Grunt: Warning: stdout maxBuffer exceeded. Use –force to continue.

Pokud váš grunt sckript vypisuje hodně údajů na obrazovku, snadno se stane že dojte k přetečení defaultního bufferu. Skript se nedokončí a zkončí hláškou:

Warning: stdout maxBuffer exceeded. Use --force to continue.

Aborted due to warnings.

Doporučuji deaktivovat maxBuffer:

shell: {
    yourCommand: {
        command: [
            'command to execute'
        ],
        options: {
            execOptions: {
                maxBuffer: Infinity
            }
        }
    }
}

 

Nette – validace formuláře – zadejte jméno nebo nick

Při práci s formuláři dost často potřebujete aby byl vyplněn jeden z důležitých údajů. V mém případě uživatel musí zadat svoje jméno nebo nick. Může zadat jméno a zároveň nick, nesmí se však stát že nezadá ani jméno ani nick:

        $form = new Form;
        $form->addText('name', 'Jméno:');
        $form->addText('nick', 'Nick:');
        
        $form->addSubmit('submit', 'Odeslat');

Pro vytvoření podmínky na jiný prvek použijeme addConditionOn. Prvním parametrem je prvek na který se odvoláváme a druhým parametrem je validační pravidlo.

        $form = new Form;
        $form->addText('name', 'Jméno:');
        $form->addText('nick', 'Nick:')
            ->addConditionOn($form['name'], ~Form::FILLED)
                ->setRequired('Zadejte prosím Vaše jméno nebo nick');

        $form->addSubmit('submit', 'Odeslat');

 

První aplikace pro Pebble hodinky

Tvorba aplikací pro Pebble hodinky je velice jednoduchá. Celou aplikaci dokážete vytvořit v cloudovém IDE. Nepotřebujete ani Pebble hodinky.

Vytvořenou aplikaci můžete spustit na emulátoru (je součástí cloud IDE) nebo fyzicky na hodinkách (pokud je máte).

Vytvoření aplikace v CloudPebble

Zaregistrujte se na https://cloudpebble.net/

Vytvořte nový projekt: PROJECTS -> CREATE

  • Project name: zadejte název vašeho projektu (například Hello)
  • Project type: Pebble C SDK
  • SDK Version: SDK 2
  • Template: HelloWorld

Tlačítkem CREATE vytvoříme projekt.

Máme základ hotov. Zkompilujeme ho: COMPILATION -> RUN BUILD. Zvolíme EMULATOR a klikneme na INSTALL ON APLITE.

Spustí se emulátor a můžeme vylepšovat.

Vytvoření nové textové vrstvy

text_layer = text_layer_create(GRect(0, 0, 144, 154));

Každá vrstva je vymezena hranicemi. Hranice určíme funkcí Grect.

Funkce Grect má následující parametry: Grect( x, y, size_x, size_y )

Průhledný PNG obrázek

Hodně jsem zápasil s vložením průhledného obrázku. Obrázek byl černý a měl průhledná místa. Řešení:

g_bitmap_layer_weather = bitmap_layer_create(GRect((bounds.size.w-25), (bounds.size.h-25), 25, 25));
bitmap_layer_set_bitmap(g_bitmap_layer_weather, gbitmap_create_with_resource(RESOURCE_ID_WATHERSUNNY_BLACK));  
bitmap_layer_set_compositing_mode(g_bitmap_layer_weather, GCompOpClear);

 

 

Tahák pro Composer

Jak stáhnout balíček do nové složky s projektem?

composer create-project nette/sandbox nazev-slozky-s-projektem

Kde složka nazev-slozky-s-projektem bude automaticky vytvořena

Jak zobrazit verze nainstalovaných balíčků?

composer show -i

composer install

Tím to příkazem nainstalujeme všechny balíčky ze souboru composer.json. Zároveň dojde k vytvoření souboru composer.lock který obsahuje seznam nainstalovaných verzí.

Pokud se dostanete k projektu ve kterém existuje composer.lock použijte pro stažení balíčků příkaz: composer install

composer update

Vynucení aktualizace balíčků. Tento příkaz přegeneruje soubor composer.lock.

Odinstalování balíčku

composer remove nette/nazev-balicku

Instalace konkrétní verze balíčku

Při instalaci se konkrétní verze píše za dvojtečku za název balíčku:

composer require facebook/php-sdk-v4:4.0.*
composer require google/apiclient:~1.0
composer require kertz/twitteroauth:dev-master
composer require venca-x/social-login:dev-master
composer require venca-x/nette.ajax.js:dev-master#fe640f40c9606e78f4fd31471931969c65b175c0

Instalace balíčků pro vývoj

ne vždy jsou balíčky nutnou součástí projektu (tester, phpstan, …). Tyto balíčky nainstalujeme s parametrem –dev

composer require --dev phpstan/phpstan-nette
Name Ukázka Popis
Přesná verze 1.0.2 Můžete určit přesnou verzi balíčku.
Rozsah >=1.0
>=1.0 <2.0
>=1.0 <1.1 || >=1.2
Operátory můžete určit rozsah platných verzí. Operátory jsou: >, >=, <, <=, !=
Můžete definovat více rozsahů. Rozsahy oddělené mezerou, nebo čárkou, budou považovány za logický AND.Dvojitá trubka (||), je považována za logický OR.
Hyphen Range 1.0 - 2.0 Například 1.0-2.0 odpovídá >= 1.0.0 <2.1
1.0.0 – 2.1.0 odpovídá >= 1.0.0 <= 2.1.0
Maska 1.0.* * je zástupný znak.  1.0.* Je ekvivalent >= 1.0 <1.1
Tilda operátor ~1.2 ~1.2 odpovídá >= 1.2 <2.0
Tilda operátor ~1.2.3 ~1.2.3 odpovídá >= 1.2.3 <1.3.0
Stříška operátor ^0.3 ^0.3 odpovídá >= 0.3 <0.4
Stříška operátor ^1.2.3 ^1.2.3 odpovídá >= 1.2.3 <2.0

U vlnovky záleží na tom, kolik číslic je uvedeno v čísle verze – poslední uvedená číslice se může lišit.

  • Preferujte operátor stříšky – je to nejjednodušší způsob, jak vynutit minimální verze oprav.

Jak v Nette vytvořit PDF fakturu

Pokud budete v Nette potřebovat vytvořit fakturu, doporučuji plugin Eciovni.

composer require OndrejBrejla/Eciovni ~1.1

Následně stačí jen vytvořit akci a funkci pro zobrazení faktury:

use OndrejBrejla\Eciovni\Eciovni;
use OndrejBrejla\Eciovni\ParticipantBuilder;
use OndrejBrejla\Eciovni\ItemImpl;
use OndrejBrejla\Eciovni\DataBuilder;
use OndrejBrejla\Eciovni\TaxImpl;

//...


    public function actionDefault() {
        // in case you downloaded mPDF separately
        // include_once(LIBS_DIR . '/MPDF54/mpdf.php');
        $mpdf = new \mPDF('utf-8');

        // Exporting prepared invoice to PDF.
        // To save the invoice into a file just use the second and the third parameter, equally as it's described in the documentation of mPDF->Output().
        $this['eciovni']->exportToPdf( $mpdf );
        //file_put_contents( "faktura.pdf", $this['eciovni']->exportToPdf( $mpdf ) );//uloz pdf na disk
    }

//..


    protected function createComponentEciovni() {
        $dateNow = new \DateTime();
        $dateExp = new \DateTime();
        $dateExp->modify('+14 days');
        $variableSymbol = '1234';

        $supplierBuilder = new ParticipantBuilder('Jan Baťa', 'Vodňany', '11', 'Čurákov', '13000');
        $supplier = $supplierBuilder->setIn('12345678')->setTin('CZ12345678')->setAccountNumber('123456789 / 1111')->build();
        $customerBuilder = new ParticipantBuilder('ěščřžýáíé ŠČŘŽÝÁÍÉ', 'Another street', '3', 'Prague 9', '19000');
        $customer = $customerBuilder->setAccountNumber('123456789 / 1111')->build();

        $items = array(
            new ItemImpl('Tworba webu', 1, 900, TaxImpl::fromPercent(22)),
            new ItemImpl('Správa databáze', 1, 900, TaxImpl::fromLowerDecimal(0.22)),
            new ItemImpl('Píčoviny', 1, 900, TaxImpl::fromUpperDecimal(1.22)),
        );
		/*
		for($i = 0; $i < 100; $i++)
		{
			$items[] = new ItemImpl( "Tworba webu " . $i, 1, 900, TaxImpl::fromPercent(22));
		}*/

        $dataBuilder = new DataBuilder(date('YmdHis'), 'Faktura - faktura číslo', $supplier, $customer, $dateExp, $dateNow, $items);
        $dataBuilder->setVariableSymbol($variableSymbol)->setDateOfVatRevenueRecognition($dateNow);
        $data = $dataBuilder->build();

        return new Eciovni($data);
    }

 

Grunt + Bower: Ajax v Nette

Mám projekt v Nette ve kterém potřebuji rozjet Ajax. Na projektu mám již připraven Grunt (jak nainstalovat Grunt) a Bower (slibuji to dlouho ale o tom zase někdy příště).

Pro Ajax v Nette doporučuji nette.ajax.js (od Vojtěcha Dobeše). Nette.ajax.js samozřejmě nainstalujeme přes Bower:

bower install nette.ajax.js --save-dev

Pro automatizaci používám Grunt (jak nainstalovat Grunt), do kterého existuje nepřeberné množství doplňků.

Pro spojení více .js souborů do jednoho používám doplněk grunt-contrib-concat kde mám vytvořený následující task:

        concat: {
            js: {
                src: ['bower_components/jquery/dist/jquery.min.js',
                    'bower_components/nette.ajax.js/nette.ajax.js',
                    'vendor/nette/forms/src/assets/netteForms.js',
                    'www/js/main.js'],
                dest: 'www/js/compiled.js',
                nonull: true
            }
        },

V souboru compiled.js máme potřebné js soubory. Můžeme se pustit do další fáze.

Nette + Ajax

Ajaxace již funkčních částí je v Nette velice jednoduchá. Nyní mám vytvořený formulář který odesílá data. Po odeslání formuláře se znovu načte kompletně celá stránka. Tento skript vylepšíme, aby se po odeslání formuláře nemusela načítat komplet celá stránka ale pouze odeslaný formulář (u mne to je formulář s rezervací).

Pojďme si připravit inicializace knihovny nette.ajax.js do souboru main.js:

$(function () {
    $.nette.init();// And you fly... 
});

Mému formuláři stačí přidat class ajax:

$form = new Form;
$form->getElementPrototype()->class( 'ajax' );

V presenteru nyní máme funkci isAjax, která nám vrací TRUE pokud se jedná o Ajaxový požadavek.

Po odeslání formuláře se přesvědčíme zda byl odeslán Ajaxem:

    public function selectWorkshopFormSucceeded( $form, $values )
    {
        if ($this->isAjax()) {
            echo "fomulář odeslán AJAXem";
        }
        else
        {
            echo "fomulář nebyl odeslán AJAXem";
        }
        exit();
    }

V latte můžeme jednotlivé bloky zabalit do snippetu a nechat překreslit pouze tento snippet:

{snippet workshop}
   {control selectWorkshopForm}
{/snippet}
    public function selectWorkshopFormSucceeded( $form, $values )
    {
        if ($this->isAjax()) {
            $this->redrawControl( 'workshop' );//znovu vykresli snippet workshop
        }
        else
        {
            $this->redirect( 'this' );//znovu vykresli celou stranku
        }
    }

Proto Nette miluju!

PHP zobrazení chyb

Dřív nebo později narazíte v PHP na bílou obrazovku. V případě že je na serveru vypnuté zobrazování chyb a váš skript skončí chybou, nebude tato chyba zobrazena ale zobrazí se bílá obrazovka.

Jak nyní zjistíte kde máte chybu nebo v čem je problém? Umístěte na začátek PHP skriptu tento kód:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

...

Tím si zobrazíte chybovou hlášku z PHP. Nezapomeňte tento kód po opravení chyby opět odebrat 🙂

Nette a Doctrine

Účast na mé první Posobotě předčila veškeré očekávání. Perfektní workshop, skvělé přednášky a úžasní lidé kteří nic netají. Na workshopu jsem díky Filipovi a Chemixovi pronikl do základů Doctrine. Zkusím tyto informace sepsat.

Instalujeme Nette

Ani nemyslete na to že to budete zkoušet bez composeru 🙂

composer create-project nette/sandbox nette-doctrine

nette-doctrine je název složky do které se sandbox vytvoří.

Instalujeme Kdyby/Doctrine

cd nette-doctrine
composer require kdyby/doctrine

Pokud máte PHP verzi alespoň 5.4 hned z konzole můžete spustit web server:

php -S localhost:8888 -t www

webserver se spustí na portu 8888. Pokud do prohlížeče zadáte http://localhost:8888 uvidíte stránku Nette Congratulations!

Práda! Můžeme začít spouštět IDE a zažneme kódovat.

PhpStorm a live templaty pro Doctrine

Rozhodně doporučuji PhpStorm do kterého Filip napsal skvělé live templaty. Ušetří spoustu psaní a času.

Live templaty stáhněte a nahrajte do:

<your home directory>\.WebIde<version>\config\templates

Rozhodně doporučuji soubory: Doctrine.xml, Nette.icls, Nette.xml

Po nahrání je nutné znovu spustit PhpStorm.

Vytvoření databáze

Pojďme si vytvořit databázi a uživatele pro přístup k databázi:

CREATE DATABASE `doctrine_devel` COLLATE 'utf8_czech_ci';
CREATE USER 'doctrine'@'localhost' IDENTIFIED BY 'doctrine_pass';
GRANT USAGE ON * . * TO 'doctrine'@'localhost' IDENTIFIED BY 'doctrine_pass' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;
GRANT ALL PRIVILEGES ON `doctrine\_%` . * TO 'doctrine'@'localhost';
FLUSH PRIVILEGES;

Příkaz vykonáme v Admineru: http://localhost:8888/adminer

Klikneme na tlačítko SQL příkaz. Do okna vložíme kód výše a jeho vykonání potvrdíme tlačítkem Provést.

Tím jsme vytvořili databázi doctrine_devel a uživatele doctrine s heslem doctrine_pass.

Zaregistrování Doctrine do Nette

Do config.neon zamergujeme následující kód:

parameters:
    database:
        host: localhost
        dbname: production_db
        user: production
        password: production_pass

extensions:
    console: Kdyby\Console\DI\ConsoleExtension
    events: Kdyby\Events\DI\EventsExtension
    annotations: Kdyby\Annotations\DI\AnnotationsExtension
    doctrine: Kdyby\Doctrine\DI\OrmExtension

doctrine:
    dbname      : %database.dbname%
    host        : %database.host%
    user        : %database.user%
    password    : %database.password%
    metadata:
        App: %appDir%

Do config.local.neon uložíme přístupové údaje do DB pro vývoj u nás na localhostu:

parameters:
    database:
        host: localhost
        dbname: doctrine_devel
        user: doctrine
        password: doctrine_pass

Podle dokuentace Kdyby/Doctrine si vytvoříme první entitu:

app/model/Article.php

<?php

namespace App;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Article extends \Kdyby\Doctrine\Entities\BaseEntity
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $title;

}

V entitě Article definuje id (celé číslo, které se bude inkrementovat) a title (text).

Vytvoření tabulky z entity

V první řadě ověříme zda funguje Doctrine/Console:

php ./www/index.php

Výstup by měl vypadat takto a měl by zobrazovat všechny dostupné příkazy pro Doctrine:

D:\www\nette-doctrine>php ./www/index.php
Nette Framework version 2.2.7

Usage:
 [options] command [arguments]

Options:
 --help (-h)           Display this help message
 --quiet (-q)          Do not output any message
 --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
 --version (-V)        Display this application version
 --ansi                Force ANSI output
 --no-ansi             Disable ANSI output
 --no-interaction (-n) Do not ask any interactive question

Available commands:
 help                       Displays help for a command
 list                       Lists commands dbal
 dbal:import                Import SQL file(s) directly to Database. orm
 orm:clear-cache:metadata   Clear all metadata cache of the various cache drivers.
 orm:clear-cache:query      Clear all query cache of the various cache drivers.
 orm:clear-cache:result     Clear all result cache of the various cache drivers.

 orm:convert-mapping        Convert mapping information between supported formats.
 orm:convert:mapping        Convert mapping information between supported formats.
 orm:generate-entities      Generate entity classes and method stubs from your mapping information.
 orm:generate-proxies       Generates proxy classes for entity classes.
 orm:generate:entities      Generate entity classes and method stubs from your mapping information.
 orm:generate:proxies       Generates proxy classes for entity classes.
 orm:info                   Show basic information about all mapped entities
 orm:schema-tool:create     Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output.
 orm:schema-tool:drop       Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output.
 orm:schema-tool:update     Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata.
 orm:validate-schema        Validate the mapping files.

Provedeme validaci:

php ./www/index.php orm:validate-schema

OK, to je v pořádku:

[Mapping]  OK - The mapping files are correct.
[Database] FAIL - The database schema is not in sync with the current mapping file.

Podíváme se jaký SQL kód nám Doctrine nabízí pro synchronizaci databáze:

php ./www/index.php orm:schema-tool:update --dump-sql

SQL kód pro synchronizaci databáze:

CREATE TABLE article (id INT AUTO_INCREMENT NOT NULL, author_id INT DEFAULT NULL, title VARCHAR(255) NOT NULL, text VARCHAR(255) DEFAULT NULL, INDEX IDX_23A0E66F675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE author (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE tag (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE tag_article (tag_id INT NOT NULL, article_id INT NOT NULL, INDEX IDX_300B23CCBAD26311 (tag_id), INDEX IDX_300B23CC7294869C (article_id), PRIMARY KEY(tag_id, article_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE article ADD CONSTRAINT FK_23A0E66F675F31B FOREIGN KEY (author_id) REFERENCES author (id);
ALTER TABLE tag_article ADD CONSTRAINT FK_300B23CCBAD26311 FOREIGN KEY (tag_id)
REFERENCES tag (id) ON DELETE CASCADE;
ALTER TABLE tag_article ADD CONSTRAINT FK_300B23CC7294869C FOREIGN KEY (article_id) REFERENCES article (id) ON DELETE CASCADE;

Tento kód můžete vykonat v admineru, neb pokud máte koule můžete ho nechat vykonat přímo z příkazové řádky (hlavouni to nedoporučují):

php ./www/index.php orm:schema-tool:update --force

Nyní když znovu spustíme validaci, vidíme:

D:\www\nette-doctrine>php ./www/index.php orm:validate-schema
[Mapping]  OK - The mapping files are correct.
[Database] OK - The database schema is in sync with the mapping files.

Namapování a databáze jsou OK, pojďme na ukládání a zobrazení dat.

Doctrine – ukládání dat

V HomepagePresenter.php si uděláme add akci na přidání záznamů do entity Article:

<?php

namespace App\Presenters;

use App\Article;
use Nette;
use Kdyby;

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{

	/**
	 * @inject
	 * @var Kdyby\Doctrine\EntityManager
	 */
	public $entityManager;

	public function actionAdd()
	{
		$daoArticle = $this->entityManager->getRepository(Article::getClassName());

		$article = new Article();
		$article->title= "Slabikář";
		$daoArticle->save($article);

		$article = new Article();
		$article->title= "Čítanka";
		$daoArticle->save($article);

		exit();
	}

}

Definovali jsme $entityManager do které jsme injectli Kdyby\Doctrine\EntityManager.

V actionAdd jsme vytvořili 2 články které uložíme do DB. První s názvem Slabikář a druhý s názvem Čítanka. V DB se můžete přesvědčit že došlo k jejich uložení do tabulky article.

Doctrine výpis dat

Velice podobným způsobem jako jsme ukládali data je budeme vypisovat. Opět budeme potřebovat EntityManager:

<?php

namespace App\Presenters;

use App\Article;
use Nette;
use Kdyby;

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{

	/**
	 * @inject
	 * @var Kdyby\Doctrine\EntityManager
	 */
	public $entityManager;

	public function renderDefault()
	{
		$daoArticle = $this->entityManager->getDao(Article::getClassName());
		$this->template->articles = $daoArticle->findAll();
	}
}

v šabloně tyto články zobrazíme:

{block content}

{foreach $articles as $article}

    {$article->title}<br/>

{/foreach}

Jednoduché že ano?

Přidání nového položky do entity

Naše aplikace je známá po celém světě a používají ji milony lidí kteří píší podměty že jim pouze název článku nestačí a chtěli by ještě text článku 🙂 Vyhovíme jim a přidáme do entity Article ještě položku text.

Nyní nám perfektně poslouží Filipovo live templaty. Otevřeme si soubor Article.php a pod proměnou private $title odřádkujeme a napíšeme: col <tab> (napíšeme col a stiskneme klávesu Tab). Ide nám předvygeneruje následující kód:

    /**
     * @ORM\Column(type="string", nullable=TRUE)
     * @var string
     */
    protected $;

ve kterém se pohybujeme klávesou Tab. Napíšeme název proměnné (text) a definujeme typ (text). Výsledek vypadá takto:

    /**
     * @ORM\Column(type="text", nullable=TRUE)
     * @var text
     */
    protected $text;

Provedeme validaci:

php ./www/index.php orm:validate-schema
D:\www\nette-doctrine>php ./www/index.php orm:validate-schema
[Mapping]  OK - The mapping files are correct.
[Database] FAIL - The database schema is not in sync with the current mapping file.

která nám oznámí že nemáme synchronizovanou databázi. Podíváme se jaké úpravy databáze nám Doctrine nabízí:

D:\www\nette-doctrine>php ./www/index.php orm:schema-tool:update --dump-sql
ALTER TABLE article ADD text LONGTEXT DEFAULT NULL;

Kód vykonáme v admineru, nebo 🙂

php ./www/index.php orm:schema-tool:update --force

Následná validace by měla být OK. Tím máme přidán sloupec text a můžeme do něho rovnou ukládat data. Vytáhneme námi uložené publikace a donastavíme jim text:

    public function actionUpdate()
    {
        $daoArticle = $this->entityManager->getRepository( Article::getClassName() );

        $article = $daoArticle->findOneBy( array( "title" => "Slabikář" ) );
        $article->text = "Text knihy slabikář";

        $article = $daoArticle->findOneBy( array( "title" => "Čítanka" ) );
        $article->text = "Text knihy čítanka";

        $this->entityManager->flush();
        exit();
    }

Upravíme šablonu abychom vypisovali text:

{block content}

{foreach $articles as $article}

    <h2>{$article->title}</h2>
    <p>{$article->text}</p>

{/foreach}

 Vyšší liga – vazby mezi entitami

Toto jsme splodili na Workshopu:

Article.php

<?php

namespace App;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Article extends \Kdyby\Doctrine\Entities\BaseEntity
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $title;

    /**
     * @ORM\Column(type="string", nullable=TRUE)
     * @var string
     */
    protected $text;

    /**
     * @ORM\ManyToOne(targetEntity="\App\Author", inversedBy="articles", cascade={"persist"})
     * @var Author
     */
    protected $author;

    /**
     * @ORM\ManyToMany(targetEntity="\App\Tag", mappedBy="articles", cascade={"persist"}, orphanRemoval=true)
     * @var \App\Tag[]|\Doctrine\Common\Collections\ArrayCollection
     */
    protected $tags;


    function __construct()
    {
        $this->tags = new ArrayCollection();
    }

    public function addTag(Tag $tag)
    {
        $tag->addArticle($this);
        $this->tags->add( $tag );
    }

}

Author.php

<?php

namespace App;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;


/**
 * @ORM\Entity
 * @property $name
 */
class Author extends \Kdyby\Doctrine\Entities\BaseEntity
{


    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $name;

    /**
     * @ORM\OneToMany(targetEntity="\App\Article", mappedBy="author", cascade={"persist"})
     * @var Article[]|\Doctrine\Common\Collections\ArrayCollection
     */
    protected $articles;

    function __construct()
    {
        $this->articles = new ArrayCollection();
    }

    public function addArticle(Article $article)
    {
        $this->articles->add( $article );
    }
}

Tag.php

<?php


namespace App;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;


/**
 * @ORM\Entity
 * @property $name
 */
class Tag extends \Kdyby\Doctrine\Entities\BaseEntity
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $name;


    /**
     * @ORM\ManyToMany(targetEntity="\App\Article", inversedBy="tags", cascade={"persist"})
     * @var \App\Article[]|\Doctrine\Common\Collections\ArrayCollection
     */
    protected $articles;


    function __construct()
    {
        $this->articles = new ArrayCollection();
    }

    public function addArticle(Article $article)
    {
        $this->articles->add( $article );
    }
}

HomepagePresenter.php

<?php

namespace App\Presenters;

use App\Author;
use App\Tag;
use Nette,
	App\Model;
use App\Article;

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{

	/**
	 * @inject
	 * @var \Kdyby\Doctrine\EntityManager
	 */
	public $EntityManager;

	public function renderDefault()
	{
		$this->template->anyVariable = 'any value';
		$dao = $this->EntityManager->getRepository(Article::getClassName());
		$this->template->articles = $dao->findAll();

	}

	public function actionAdd()
	{

		$daoArticle = $this->EntityManager->getRepository(Article::getClassName());
		$daoAuthor = $this->EntityManager->getRepository(Author::getClassName());

		//$author = new Author();
		//$author->name = "Pokusne jmeno";

		$author = $daoAuthor->findOneBy( array("name" => "Pokusne jmeno"));

		$article = new Article();
		$article->title = "titulke sntagem";
		$article->text = "text novinky s tagem";
		$article->author = $author;
		$author->addArticle($article);

		$tag = new Tag();
		$tag->name = "kniha";

		$article->addTag($tag);

		$tag = new Tag();
		$tag->name = "kniha dvojita";

		$article->addTag($tag);

		$daoArticle->save($article);

		exit();
	}

}

Šablona:

{block content}

{foreach $articles as $article}

    {$article->title}<br>
    {$article->author->name}<br/>
    {dump $article->tags}
    Tags: {if $article->tags}{foreach $article->tags as $tag}{$tag->name}, {/foreach}{/if}<br/>
<hr/>
{/foreach}

{/block}

 

Celé databázové schéma smažeme a vytvoříme znovu:

php ./www/index.php orm:schema-tool:drop --force

php ./www/index.php orm:schema-tool:create

Celou ukázku jsem nahrál na GitHub: https://github.com/venca-x/nette-sandbox-doctrine

Composer: jak nainstalovat Nette 2.3.0-beta

Po vystřízlivění ze včerejší posoboty nastal čas vyzkoušet Nette 2.3.0-beta.

Upgrade je jednoduchý. Stačí upravit composer.json:

...
  "require": {
    ...
    "nette/nette": "~2.3.0",
    ...
  },
  "minimum-stability": "beta",
  "prefer-stable": true
...

Velice důležitý je řádek minimum-stability: beta a prefer-stable: true

Následně do konzole pustíte příkaz composer update a můžete testovat Nette 2.3.0-beta