etten / doctrine
Doctrine helpers and extensions for Nette Framework
Requires
- php: >=7.0
- etten/utils: ^0.2
- kdyby/doctrine: ^3.1
- ramsey/uuid-doctrine: ^1.2
Requires (Dev)
- etten/codestyle: ^2.0
- phpunit/phpunit: ^6.0
- rixxi/gedmo: ^1.0
- squizlabs/php_codesniffer: ~2.6.0
- zenify/doctrine-behaviors: ^2.4
- dev-master
- v4.7.2
- v4.7.1
- v4.7.0
- v4.6.5
- v4.6.4
- v4.6.3
- v4.6.2
- v4.6.1
- v4.6.0
- v4.5.0
- v4.4.0
- v4.3.0
- v4.2.0
- v4.1.0
- v4.0.1
- v4.0.0
- v3.2.0
- v3.1.0
- v3.0.1
- v3.0.0
- v2.11.0
- v2.10.1
- v2.10.0
- v2.9.0
- v2.8.1
- v2.8.0
- v2.7.0
- v2.6.0
- v2.5.1
- v2.5.0
- v2.4.0
- v2.3.1
- v2.3.0
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.0
- v1.5.0
- v1.4.0
- v1.3.1
- v1.3.0
- v1.2.0
- v1.1.0
- v1.0.1
- v1.0.0
- dev-feature/console
This package is auto-updated.
Last update: 2024-12-14 03:46:03 UTC
README
Provides some helpers and extension for Doctrine 2 ORM into Nette Framework.
Installation
First install package via Composer:
$ composer require etten/doctrine
Then register basic DI Extension in config.neon
:
extensions:
etten.doctrine: Etten\Doctrine\DI\DIExtension
EntityManager Facades
Doctrine's default EntityManager is a GOD class. Monster. It does too much, violates SRP, mocks are difficilt, ...
But you can use:
- Etten\Doctrine\Facade (abstract class)
- Etten\Doctrine\Persister
- Etten\Doctrine\RepositoryLocator
- Etten\Doctrine\Transaction
Services are registered automatically with Etten\Doctrine\DI\DIExtension
.
Helpers
Collections
When you have i.e. Product:Tags (M:N)
associations and set-up all values via setter Product::setTags
, you'll
probably get a Duplicate entry...
error. Because you set-up new associations (replace Product's Tags Collection instance).
But this kind of operation can be very easy with Etten\Doctrine\Helpers\Collections
.
Just use:
public function setTags(array $tags):Product
{
\Etten\Doctrine\Helpers\Collections::replace($this->tags, $tags);
return $this;
}
The $this->tags
instance is preserved, only new items are added and removed items removed from Collection.
FieldOrderHelper
Sometimes, you need sort items by order given by another array.
In MySQL, you can use ORDER BY FIELD.
But when we use Doctrine, our code should be platform independent and we shouldn't use DBMS-specific functions directly.
You can sort items in PHP via Etten\Doctrine\Helpers\FieldOrderHelper
. See implementation.
Note: This kind of operations in PHP is inefficient. Use it only for few filtered items. If you have hundreds of items, rather rewrite the code and sort items directly in DBMS, not in PHP.
Randomizer
Randomizer helps you find random-look results without ORDER BY RAND()
clause.
It counts all items in given Query
object and selects random offset.
Then applies limit and returns items as a shuffled array result.
For better results, offset + limit is performed in multiple iterations (by default for each 25 items). It increases a cost of the operation, but results are not in order as-inserted into database.
Extensions
Cache
Etten/Doctrine provides comfortable cache invalidation when a specific entity is changed (in term of Doctrine: persisted, updated, removed).
Entity must implements Etten\Doctrine\Entities\Cacheable
, see interface.
Basic implementation of Cacheable you'll get with Etten\Doctrine\Entities\Attributes\Cache
, see trait.
You can also inherit from Etten\Doctrine\Entities\Entity
(implementation) and you'll get both of these requirements.
Finally, you must register a Nette DI extension:
# app/config.neon
extensions:
etten.doctrine.cache: Etten\Doctrine\DI\CacheExtension
When the extension is registered, cache is automatically invalidated. How? It depends on concrete implementations. For default, see Etten\Doctrine\Entities\Attributes\Cache and Etten\Doctrine\Caching\NetteCacheInvalidator.
UUID
If you need item's ID before persist and flush, you can use UUID as a primary index.
Doctrine 2 has native support of UUID (GUID) but it's auto-generated value by RDMS. And we don't know the ID before persist and flush.
But you can generate UUID before persist and flush, in PHP.
For more information see ramsey/uuid-doctrine and Percona blog.
In etten/doctrine, UUID types are used a bit differently:
- UuidBinary has really a binary attribute (PHP string, SQL binary), not Uuid instance. But you can get hexdec value when you need it (i.e. select in a form). If you need insert UUID manually in a raw SQL, use something like
UNHEX(REPLACE(UUID(), '-', ''))
. - Uuid has really a string attribute (both PHP + SQL), not Uuid instance. See UuidBinary above.
- UuidBinary uses InnoDB optimized variant by default.
- When you need simple conversion of types, you can use UuidConverter.
In a Nette Framework application, simple add UUID support by registering an extension:
# app/config.neon
extensions:
etten.doctrine.uuid: Etten\Doctrine\DI\UuidExtension
InstanceId
If you need item's ID before persist and flush, you can use InstanceId as a primary index.
It's globally unique integer generated by PHP, not RDMS.
You can add the InstanceId support by registering a Nette DI extension:
# app/config.neon
extensions:
etten.doctrine.instanceId: Etten\Doctrine\DI\InstanceIdExtension
etten.doctrine.instanceId:
path: safe://%storageDir%/instance-generator.id
DQL
MySQL MATCH AGAINST
The original source of the code is here.
Register a DQL in config:
# app/config.neon
kdyby.doctrine:
dql:
string:
MATCH: Etten\Doctrine\DQL\MatchAgainstFunction
Usage:
<?php
public function search(string $q)
{
$qb = $this->createQueryBuilder()
->addSelect('MATCH (a.title) AGAINST (:search) as HIDDEN score')
->addWhere('MATCH (a.title) AGAINST (:search) > 1')
->setParameter('search', $q)
->orderBy('score', 'desc');
return new Paginator($qb);
}
MySQL FIELD
The original source of the code is here.
Register a DQL in config:
# app/config.neon
kdyby.doctrine:
dql:
string:
MATCH: Etten\Doctrine\DQL\FieldFunction
Usage:
<?php
public function search(array $ids)
{
$qb = $this->createQueryBuilder()
->addSelect('FIELD(p.id, :ids) as HIDDEN score')
->andWhere('p.id IN :ids')
->setParameter('ids', $ids)
->orderBy('score', 'desc');
return new Paginator($qb);
}
Others (not included in this package)
For more functions plese visit beberlei/DoctrineExtensions.