php-ddd
php-ddd copied to clipboard
Implementing the Specification Pattern with Doctrine Repositories
There are some nice tutorials out there:
- http://culttt.com/2014/08/25/implementing-specification-pattern/ @philipbrown
For Zend Framework too by @UFOMelkor:
- http://programming-php.net/author/ufomelkor/
Another implementation by @mbrevda:
- https://github.com/mbrevda/SpecificationPattern
And @maximecolin:
- https://github.com/maximecolin/satisfaction
But there is also a implementation for Doctrine by @Happyr @Nyholm @cakper:
- https://github.com/Happyr/Doctrine-Specification
Anybody else with other implementations? What are your experiences? Any best practices? Thanks for the feedback!
My implementation is not implemented, that repo was to TRY to and implement the pattern... wasn't very successful.
Tried any of the others @mbrevda ? What was missing for success?
The HappyDoctrineSpecification works. I've been using in in prod for over a year. I will soon tag version 1.0.
It wasn't so much the spec part, as much as I wanted a Specification that can be turned in a query. That proved to be quite difficult and I ran out of time.
On Wed, Jun 22, 2016, 7:14 PM Tobias Nyholm [email protected] wrote:
The HappyDoctrineSpecification works. I've been using in in prod for over a year. I will soon tag version 1.0.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/webdevilopers/php-ddd/issues/17#issuecomment-227795606, or mute the thread https://github.com/notifications/unsubscribe/AAR4jP1GbTEHNnWUzA60lKsoEDAHXGOXks5qOV9SgaJpZM4I7tPY .
@Nyholm Can you say something about your directory/namespacing schema for the custom specs?
Another Bundle I found is RulerZ
by @K-Phoen:
- http://blog.kevingomez.fr/2015/03/14/rulerz-specifications-and-symfony-are-in-a-boat/
- https://github.com/K-Phoen/RulerZBundle
Using RulerZ, the two previous repositories can be refactored:
<?php
interface CompanyRepository
{
public function save(Company $company);
public function find($slug);
public function matchingSpec(Specification $spec);
}
class DoctrineCompanyRepository extends EntityRepository implements CompanyRepository
{
// ...
public function matchingSpec(Specification $spec)
{
$qb = $this->createQueryBuilder('c');
return $this->rulerz->filterSpec($qb, $spec);
}
}
class InMemoryCompanyRepository implements CompanyRepository
{
private $companies = [];
// ...
public function matchingSpec(Specification $spec)
{
return $this->rulerz->filterSpec($this->companies, $spec);
}
}
It is also possible to use the Specs for filtering directly inside Symfony Forms:
<?php
class CompanySearchType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$terms = $builder
->create('who')
->addModelTransformer(
new SpecToStringTransformer(Spec\CompanyName::class, 'terms')
);
$location = $builder
->create('where')
->addModelTransformer(
new SpecToStringTransformer(Spec\CompanyLocation::class, 'location')
);
$builder
->add($terms)
->add($location);
}
// ...
}
Personally I prefer using a Query passing the data to a Handler. Then the Handler creates the Specifications to pass them to my repository. The Handler then returns the Set from the Collection.
A word on "coupling business logic with the specification pattern":
I can understand that looking at these concrete Doctrine implementations make you think, that business logic is linked to persistence. But coming from a DDD approach you would create a Base Specification like "filterGroup". Then you create a Doctrine (or Mysql, Mongo, InMemory) class based on that Spec and add only the stuff that will be related to the same Persistence storage: DoctrineUserRepository or InMemoryRepository. What you want is the coupling of the Business Logic to the Specification. And then you build your infrastructure around it.
http://www.whitewashing.de/2013/03/04/doctrine_repositories.html#comment-2751511485
I think @timglabisch also prefers this kind of approach? http://www.whitewashing.de/2013/03/04/doctrine_repositories.html#comment-1280738273
Coming from this nice article by @beberlei: http://www.whitewashing.de/2013/03/04/doctrine_repositories.html#comment-2751511485
Which was an inspiration on the @Happyr Doctrine-Specification btw..
There is also an bundle by @rikbruil inspired by @Happyr Doctrine-Specification implementing the Doctrine Paginator: https://github.com/rikbruil/Doctrine-Specification
BTW: Doing my first steps with @Happyr now:
/**
* Class DoctrineContractRepository
*
* @package Rewotec\Contract\Infrastructure\Persistence\Doctrine
*/
class DoctrineContractRepository
extends EntityRepository
implements ContractRepository
{
use EntitySpecificationRepositoryTrait;
Works like a charm @Nyholm!
Testing some more complex stuff now: https://github.com/Happyr/Doctrine-Specification/issues/128
Where do you guys suggest to put the Specifications?
Normally I think they would go into the Domain
/ DomainModel
namespace.
But since the examples are used with Doctrine the are coupled to the infrastructure.
At least they should go into Acme\Infrastructure
.
- Acme\Infrastructure\Persistence\Doctrine (where als the repositories live)
- Acme\Infrastructure\Persistence\Doctrine\FooRepository
- Acme\Infrastructure\Persistence\Doctrine\FooSpecification
I've seen people adding a Domain namespace for this:
- Acme\Infrastructure\Persistence\Domain\Foo\FooSpecification
Thoughts?