Ce diaporama a bien été signalé.
Le téléchargement de votre SlideShare est en cours. ×

Doctrine - Co dělat když entity nestačí [Filip Procházka] (7. sraz, Praha)

Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Chargement dans…3
×

Consultez-les par la suite

1 sur 35 Publicité

Doctrine - Co dělat když entity nestačí [Filip Procházka] (7. sraz, Praha)

Télécharger pour lire hors ligne

Ukážeme si, že Doctrine není jenom ORMko a kdy jít o vrstvu níž. Jak DQL naučit věci, které v základu neumí, ale vaše databáze ano. A pár dalších tipů, jak nemít z databáze úplně hloupé úložiště.

Ukážeme si, že Doctrine není jenom ORMko a kdy jít o vrstvu níž. Jak DQL naučit věci, které v základu neumí, ale vaše databáze ano. A pár dalších tipů, jak nemít z databáze úplně hloupé úložiště.

Publicité
Publicité

Plus De Contenu Connexe

Les utilisateurs ont également aimé (16)

Publicité

Plus par Péhápkaři (20)

Publicité

Doctrine - Co dělat když entity nestačí [Filip Procházka] (7. sraz, Praha)

  1. 1. Doctrine: Co dělat, když entity nestačí? @ProchazkaFilip #makeCodeNotWar
  2. 2. Co si povíme? ● minimum využití databáze každého Doctrinisty ● batch operace ● rozšiřování DQL ● metody hydratace ● native queries #makeCodeNotWar
  3. 3. Minimum využití databáze každého Doctrinisty
  4. 4. Minimum využití databáze každého Doctrinisty ● Co za vás dělá Doctrine ○ indexy pro vazby a primární klíče ○ vzdálené klíče ● Co si musíte pohlídat sami ○ unique indexy ○ vlastní typy
  5. 5. Indexy a vzdálené klíče class User { /** * @ORMId() * @ORMColumn(type="uuid") */ private $id; class Order { /** * @ORMManyToOne(targetEntity=User::class) * @ORMJoinColumn(nullable=false) */ private $user;
  6. 6. Unique indexy class User { /** * @ORMColumn(type="string", unique=true) */ private $email;
  7. 7. Unique indexy /** * @ORMEntity() * @ORMTable(name="order_item_rating", * uniqueConstraints={ * @ORMUniqueConstraint(name="order_item_rating_x_unique", columns={ * "order_item_id", "user_id" * }) * } * ) */ class OrderItemRating
  8. 8. Unique indexy: vkládání a race conditions ● Opravdu to potřebujete řešit? ○ >90% aplikacím stačí check přes repository před flushem ○ >90% aplikací nikdy nenaroste natolik, aby to byl skutečný problém ● Pokud to opravdu opravdu potřebujete řešit ○ kdyby/doctrine ... NonLockingUniqueInserter ○ ^ brzy i samostatně, jako kdyby/doctrine-nonlocking-unique-inserter ○ ^ Symfony friendly ❤ ○ ^ sledujte issue kdyby/doctrine#238
  9. 9. Vlastní datový typ class UuidType extends Type { const NAME = 'uuid'; function getName() { return self::NAME; } function getSQLDeclaration( array $fieldDeclaration, AbstractPlatform $platform); function convertToPHPValue( $value, AbstractPlatform $platform); function convertToDatabaseValue( $value, AbstractPlatform $platform); Zdroj: ramsey/uuid-doctrine
  10. 10. Vlastní datový typ: komentáře ve schématu class SomethingBasedOnStringType extends StringType { function requiresSQLCommentHint( AbstractPlatform $platform) : bool // … $platform->markDoctrineTypeCommented(Type::getType($type));
  11. 11. Vlastní datový typ: konverze na úrovni DB class GeometryType extends Type { function canRequireSQLConversion() : bool; function convertToDatabaseValueSQL( $sqlExpr, AbstractPlatform $platform); function convertToPHPValueSQL( $sqlExpr, $platform);
  12. 12. Vlastní datový typ: registrace doctrine: dbal: types: uuid: class: RamseyUuidDoctrineUuidType Zdroj: ramsey/uuid-doctrine
  13. 13. Vlastní datový typ: použití /** * @ORMId() * @ORMColumn(type="uuid") */ private $id; CREATE TABLE "user" ( id UUID NOT NULL, email VARCHAR(255) DEFAULT NULL -- atd ); COMMENT ON COLUMN "user".id IS '(DC2Type:uuid)';
  14. 14. Logika v databázi vs Logika v modelu Premature optimization is the root of all evil ~ Donald Knuth
  15. 15. Batch operace
  16. 16. Batch operace s DQL “UPDATE/DELETE statements are ported directly into a Database statement and therefore bypass any locking scheme, events and do not increment the version column. Entities that are already loaded into the persistence context will NOT be synced with the updated database state. It is recommended to call EntityManager#clear() and retrieve new instances of any affected entity.” ~ Dokumentace
  17. 17. Batch operace s DQL ● Zkuste nejprve chytřejší způsoby iterace nad výsledkem ○ ORMQuery::iterate(); ○ Stránkování ● Raději DQL update, než SQL update ● Neumí JOINy :(
  18. 18. Batch operace s DQL $select = $em->createQueryBuilder() ->addSelect('orderItem.price') ->from(OrderItem::class, 'orderItem') ->andWhere('orderItem.order = theOrder.id'); $update = $em->createQueryBuilder() ->update(Order::class, 'theOrder') ->set('theOrder.totalPrice', sprintf('(%s)', $select)) ->getQuery();
  19. 19. Batch operace s DQL UPDATE "order" SET total_price = ( SELECT SUM(o0_.price) AS dctrn__1 FROM order_item o0_ WHERE o0_.order_id = order.id )
  20. 20. Batch operace s DBAL ● $connection->prepare('UPDATE ...'); ● $connection->createQueryBuilder();
  21. 21. Rozšiřování DQL
  22. 22. Rozšiřování DQL ● TreeWalker - může modifikovat AST ● output SqlWalker - generuje samotný SQL dotaz ● vlastní funkce
  23. 23. Rozšiřování DQL: limitace ● Gramatika je jasně definovaná, není možné to nijak ohackovat ● Tree Walker může modifikovat výsledné AST, ale opět nezmění gramatiku ● SqlWalker to nemá jak zachránit
  24. 24. Rozšiřování DQL: co jde Kam nemůže DQL SELECT order.finishedTime IS NULL AS something FROM ...; Tam musí funkce SELECT IS_NULL(order.finishedTime) AS something FROM ...;
  25. 25. Rozšiřování DQL: vlastní funkce class IsNull extends FunctionNode { private $expression; public function getSql(SqlWalker $sqlWalker) { return $sqlWalker->walkArithmeticPrimary($this->expression) . ' IS NULL'; } public function parse(Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); $this->expression = $parser->ArithmeticPrimary(); $parser->match(Lexer::T_CLOSE_PARENTHESIS); }
  26. 26. SELECT employee, AVG(salary) OVER (PARTITION BY employee.department) AS avgSalary FROM MyEmployee employee; SELECT employee, WINDOW_OVER(AVG(salary), employee.department) AS avgSalary FROM MyEmployee employee; SELECT employee, WINDOW(AVG(salary) OVER (PARTITION BY employee.department)) AS avgSalary FROM MyEmployee employee; Rozšiřování DQL: komplexnější syntaxe
  27. 27. Rozšiřování DQL: existující knihovny ● oro/doctrine-extensions (MySQL, PostgreSQL) ● opsway/doctrine-dbal-postgresql (PostgreSQL) ● beberlei/DoctrineExtensions (MySQL, Oracle) ● syslogic/doctrine-json-functions (MySQL) ● další na: https://packagist.org/search/?q=dql
  28. 28. Hydratace
  29. 29. Druhy hydratace ● entity ○ ORMQuery::getResult(); ● scalar + entity (mixed results) ○ ORMQuery::getResult(); ● array - vytvoří strukturu jako pro entity a tu vrátí ○ ORMQuery::getArrayResult(); ● scalar - přejmenuje sloupce na fieldy a přetypuje ○ ORMQuery::getScalarResult();
  30. 30. Native queries $rsm = new ResultSetMappingBuilder($em); $rsm->addRootEntityFromClassMetadata(OrderItem::class, 'order_item') $connection->createQueryBuilder() ->addSelect($rsm->generateSelectClause()) ->from(...) $em->createNativeQuery($sql, $rsm)
  31. 31. Shrnutí: co si z toho odnést? ● Logika v modelu dokud to jenom trochu jde ● Nebát se využívat hojně vlastní typy ● Rozšiřování DQL je snadné ● Doctrine není určená na batch operace Kam dál? ● Youtube kanál “Nette Framework” > search “Doctrine”
  32. 32. Dotazy?
  33. 33. Díky za pozornost! @ProchazkaFilip #makeCodeNotWar
  34. 34. Díky za pozornost! @ProchazkaFilip #makeCodeNotWar

×