strontium / specification-bundle
Specification-pattern in Doctrine and Symfony 2 framework
Installs: 125
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=5.4
- happyr/doctrine-specification: ^0.6@stable
- sylius/registry: ^0.14
- symfony/expression-language: ^2.5
- symfony/form: ^2.5
- symfony/framework-bundle: ^2.3
Requires (Dev)
- phpspec/phpspec: ~2.2
This package is auto-updated.
Last update: 2025-03-26 22:38:44 UTC
README
Integraion of Happyr/Doctrine-Specification into Symfony 2 framework.
Installation
Add composer dependency composer require strontium/doctrine-specification-bundle
.
Register bundle in your Kernel:
<?php // app/AppKernel.php public function registerBundles() { $bundles = array( // ... new \Strontium\SpecificationBundle\SpecificationBundle(), ); // ... }
Usage
Create your specification builder:
use Strontium\SpecificationBundle\Builder\SpecificationBuilderInterface; class OwnedByCurrentUser implements SpecificationBuilderInterface { protected $tokenStorage; public function setContextManager(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; return $this; } public function buildSpecification(SpecificationFactory $spec, array $options) { return $spec->eq([ 'field' => $options['field'], 'value' => $this->tokenStorage->getToken()->getUser(), 'dql_alias' => $options['dql_alias'] ]); } public function configureOptions(OptionsResolver $resolver) { $resolver ->setDefined(['field']) ->setDefaults([ 'field' => 'user', ]); } }
Register you builder by adding tag specification
:
# services.yml my_app.specification.owned_by_current_user: class: MyApp\MyBundle\Specification\OwnedByCurrentUser arguments: - @security.token_storage tags: - { name: specification, alias: ownedByCurrentUser }
Use it somewhere in your app
class CommentController extends Controller { public function indexAction(Request $request) { $spec = $this->get('specification.factory')->ownedByCurrentUser(); $comments = $this->getRepository()->match($spec); return [ 'comments' => $comments ]; } }
Or create other specification builders depends from it:
class NewCommentsOwnedByCurrentUser extends AbstractSpecificationBuilder { public function buildSpecification(SpecificationFactory $spec, array $options) { return $spec->andX( $spec->ownedByCurrentUser(), $spec->gte('createdAt', new \DateTime('-5 days')) ); } }
You can use Specification filter form in you controllers. Firsts create FormType:
class AppointmentChainFilterType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('text', 'text', [ 'specification' => function (SpecificationFactory $spec, $value) { return $spec->like([ 'field' => 'text', 'value' => $value ]); }, ]) ->add('status', 'choice', [ 'choices' => ['draft', 'posted', 'deleted'], 'specification' => 'in' 'specification_options' => [ 'field' => 'status' ], ]) ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { $form = $event->getForm(); $text = $form->get('text')->getNormData(); if ($text && strlen($text) < 3) { $form['text']->addError( new FormError("Search text should contains at least 3 symbols.") ); } }) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'specification' => 'andX', ]); } public function getName() { return 'posts_filter'; } public function getParent() { return 'resource_filter'; } }
Handle request by this form, get Specification instance!
class PostController { public function indexAction(Request $request) { $specFactory = $this->get('specification.factory'); $specification = $specFactory->ownedByCurrentUser(); $filterForm = $this->createForm('posts_filter'); $filterForm->handleRequest($request); if ($filterForm->isValid() && $filterSpecification = $filterForm->getData()) { $specification = $specFactory->andX($filterSpecification, $specification); } $comments = $this->getRepository()->match($specification); // .... } }
With some additions its possible to use Sylius/ResoucreBundle with specification. Resource routing config will look line this:
sylius_product_index: path: /products/{tag} methods: [GET] defaults: _controller: sylius.controller.product:indexAction _sylius: specification: name: haveTag options: tag: $tag paginate: $limit