Packages

composer create-project nette/web-project

Doctrine/DBAL

$config = new Configuration();

//..

$connectionParams = array(
    'dbname' => 'mydb',
    'user' => 'user',
    'password' => 'secret',
    'host' => 'localhost',
    'driver' => 'pdo_mysql',
);

$conn = DriverManager::getConnection(
    $connectionParams, 
    $config
);

Nettrine/DBAL

composer require nettrine/dbal

CompilerExtension

Tracy

Classes

Nettrine/DBAL

extensions:
    dbal: Nettrine\DBAL\DI\DbalExtension

dbal:
    debug: %debugMode%
    connection:
        host: localhost
        driver: mysqli
        dbname: nettrine
        user: root
        password: root

Parameters validation

dbal:
    debug: %debugMode%
    connection:
        host: localhost
        driver: mysqli
        dbname: nettrine
        user: root
        password: root
    foo: 1
dbal:
    debug: %debugMode%
    connection:
        host: localhost
        driver: mysqli
        dbname: nettrine
        user: root
        password: root
    foo: 1

Parameters validation

Schema 🚀

Expect::structure([
    'debug' => Expect::bool(false),
    'configuration' => Expect::structure([
        'sqlLogger' => Expect::string()->nullable(),
        'resultCacheImpl' => Expect::string()->nullable(),
        'autoCommit' => Expect::bool(true),
    ]),
    'connection' => Expect::array()->default([
        'driver' => 'pdo_sqlite',
        'types' => [],
        'typesMapping' => [],
    ]),
]);

Tracy panel

Tracy panel

Tracy BlueScreen

extensions:
    dbal: Nettrine\DBAL\DI\DbalExtension

dbal:
    debug: true/false
    connection:
        host: localhost
        driver: mysqli
        dbname: nettrine
        user: root
        password: root

Tracy

extensions:
    dbal: Nettrine\DBAL\DI\DbalExtension

dbal:
    debug: %debugMode%
    connection:
        host: localhost
        driver: mysqli
        dbname: nettrine
        user: root
        password: root

Nettrine/ORM

/**
 * @ORM\Entity(repositoryClass="App\UserRepository")
 * @ORM\Table(name="`user`")
 * @ORM\HasLifecycleCallbacks
 */
class User
{
	/**
	 * @ORM\Column(
            type="string", 
            length=255, 
            nullable=FALSE, 
            unique=TRUE
           )
	 */
	private $email;
}

Nettrine/ORM

composer require nettrine/orm

Nettrine/ORM

composer require nettrine/orm
composer require contributte/console

❤️

composer require symfony/console

Speed ↘️😢

Speed 😱

composer require nettrine/cache

Speed

extensions:
    orm: Nettrine\ORM\DI\OrmExtension
    orm.cache: Nettrine\ORM\DI\OrmCacheExtension

↗️

extensions:
    orm: Nettrine\ORM\DI\OrmExtension
    orm.cache: Nettrine\ORM\DI\OrmCacheExtension

orm.cache
    defaultDriver: apcu
  • queryCache
  • hydrationCache
  • metadataCache
  • resultCache
  • secondLevelCache

Speed

Data Fixtures

Data Fixtures

$user = new User(
    'Felix',
    'Felicis',
    'milan@sulc.dev'
);

$em->persist($user);
$em->flush();

Data Fixtures

$faker = Faker\Factory::create();

$user = new User(
    $faker->firstName,
    $faker->lastName,
    $faker->email
);

$em->persist($user);
$em->flush();

Data Fixtures

User::class => [
    'user{0..100}' => [
        '__construct' => [
            '<firstName()>',
            '<lastName()>',
            '2 (unique)' => '<email()>',
        ],
    ],
],

Data Fixtures

User::class => [
    'user{0..100}' => [
        '__construct' => [
            '<firstName()>',
            '<lastName()>',
            '2 (unique)' => '<email()>',
            '@address_<current>'
        ],
    ],
],

Address::class => [
    'address_{0..100}' => [
        '__construct' => [
            '<street()>',
            '<city()>',
        ],
    ],
],

Data Fixtures

composer require nettrine/dbal
composer require nettrine/orm
composer require nettrine/fixtures
composer require contributte/console
composer require nelmio/alice

Data Fixtures

extensions:
    # Doctrine DBAL
    dbal: Nettrine\DBAL\DI\DbalExtension
    dbal_console: Nettrine\DBAL\DI\DbalConsoleExtension

    # Doctrine ORM
    orm: Nettrine\ORM\DI\OrmExtension
    orm_cache: Nettrine\ORM\DI\OrmCacheExtension
    orm_console: Nettrine\ORM\DI\OrmConsoleExtension
    orm_annotations: Nettrine\ORM\DI\OrmAnnotationsExtension

    # Data Fixtures
    fixtures: Nettrine\Fixtures\DI\FixturesExtension

fixtures:
    paths:
        - %appDir%/db/Fixtures

Data Fixtures

class UserFixture extends AbstractFixture
{
    public function load(ObjectManager $manager): void
    {
        $loader = new NativeLoader();
        $users = $loader->loadData([
            User::class => [
                'user{0..100}' => [
                    '__construct' => [
                        '<firstName()>',
                        '<lastName()>',
                        '2 (unique)' => '<email()>',
                    ],
                ],
            ],
        ]);
        foreach($users as $user) {
            $manager->persist($user);
        }
        $manager->flush();
    }
}

Migrations

composer require nettrine/migrations

Migrations

extensions:
	migrations: Nettrine\Migrations\DI\MigrationsExtension

migrations:
	table: doctrine_migrations
	column: version
	directory: %appDir%/db/Migrations
	namespace: Database\Migrations
	versionsOrganization: null
bin/console migrations:migrate

🎉🎉🎉

🌀Annotations

🌀Annotations

composer require nettrine/annotations
/**
 * @Component\Component(name="user_list")
 * @Component\Security(role="admin")
 * @Component\Cache(expire="+20 minutes")
 */

🌀Annotations

  1. Create @Component annotation
  2. Create control factory
  3. Magic in CompilerExtension
  4. Setup components
  5. 💰💰💰🤑

💰

💰

💰

💰

🌀Annotation

use Doctrine\Common\Annotations\Annotation\Target;

/**
 * @Annotation
 * @Target("CLASS")
 */
final class Component
{

    /** @var string */
    public $name;

}

Control Factory

/**
 * @Component\Component(name="user_list")
 * @Component\Security(role="admin")
 */
final class UserListFactory implements IControlFactory
{
	public function create(?array $args = null)
	{
		return new UserList(...);
	}
}

🧙‍♀️🧙‍♂️🎩

  1. Register needed services
  2. Lookup for all factories
  3. Parse annotations
  4. Apply parsed metadata

🧙‍♀️🧙‍♂️🎩

public function loadConfiguration(): void
{
    $builder = $this->getContainerBuilder();

    $builder->addDefinition($this->prefix('creator'))
        ->setFactory(ComponentCreator::class);
}

🧙‍♀️🧙‍♂️🎩

public function beforeCompile(): void
{
    $builder = $this->getContainerBuilder();
    $components = $builder->findByType(IControlFactory::class);

    foreach ($components as $service => $def) {
        $this->parseAnnotations($def->getType());
    }
}
services:
  - App\Components\UserListFactory
protected function parseAnnotations(string $class)
{   
    $reader = new AnnotationReader();
    $rc = new ReflectionClass($class);
    $annotations = $reader->getClassAnnotations($rc);

    foreach ($annotations as $annotation) {
        // Parse @Component
        if (get_class($annotation) === Component::class) {
            $metadata['name'] = $annotation->name;
            continue;
        }

        // Other annotations..
    }
}

🧙‍♀️🧙‍♂️🎩

public function beforeCompile(): void
{
    // ...

    $creator = $builder->getDefinition($this->prefix('creator'));
    foreach ($metadata as $item) {
        $creator->addSetup('register', [
            $item['name'], 
            $item['def']
        ]);
    }
}

🧙‍♀️🧙‍♂️🎩

class BasePresenter
{
    /** @var IModalsControlFactory @inject */
    public $modalsControlFactory;

    public function createComponentModals(): ModalsControl
    {
        return $this->modalsControlFactory->create();
    }
}

Magic Control

class ModalsControl
{
    protected function createComponent($name): BaseModal
    {
       return $this->creator->create($name, $args);
    }
}

Magic Control

{control modals-user_list}

🌀Recap

NEON (factories)

CompilerExtension

Component Creator

Latte

{control xyz}

Annotation Reader

Time to selfie 📷

Conclusion

  1. Config validation❗️
  2. Tracy panel
  3. Tracy BlueScreen
  4. Cache
  5. 🌀Annotations
  6. Data Fixtures
  7. Migrations
  8. Symfony Console

Project Nutella

Project Nutella

Nette 3.0! 👍

shut

UP

and

take

my

moniez

💰💵

💰

💰

💰

?

What? Why? How? No? Oh.

Thank you

Keep Contributting!

@xf3l1x
f3l1x.io

2019-04-10 - Nettrine - Doctrine balíčky v Nette aplikaci

By Milan Felix Šulc

2019-04-10 - Nettrine - Doctrine balíčky v Nette aplikaci

  • 1,491