├── Resources
├── views
│ ├── Carts
│ │ ├── deleteCart.html.twig
│ │ ├── newCart.html.twig
│ │ └── getCart.html.twig
│ ├── Transitions
│ │ └── getTransition.html.twig
│ ├── layout.html.twig
│ └── Items
│ │ └── getItem.html.twig
├── config
│ ├── validation
│ │ ├── orm.xml
│ │ └── mongodb.xml
│ ├── calculator.xml
│ ├── listener.xml
│ ├── transition.xml
│ ├── parameter.xml
│ ├── event.xml
│ ├── orm.xml
│ ├── mongodb.xml
│ ├── form.xml
│ ├── doctrine
│ │ └── model
│ │ │ ├── Item.orm.xml
│ │ │ ├── Item.mongodb.xml
│ │ │ ├── Cart.mongodb.xml
│ │ │ └── Cart.orm.xml
│ └── validation.xml
└── meta
│ └── LICENSE
├── .gitignore
├── .travis.yml
├── Tests
├── bootstrap.php
├── TestCart.php
└── DependencyInjection
│ └── LeaphlyCartExtensionTest.php
├── phpunit.xml.dist
├── DependencyInjection
├── Compiler
│ ├── ValidationPass.php
│ └── RegisterMappingsPass.php
├── Configuration.php
└── LeaphlyCartExtension.php
├── composer.json
├── Controller
├── CartTransitionsController.php
├── BaseController.php
├── CartItemsController.php
└── CartsController.php
├── README.markdown
└── LeaphlyCartBundle.php
/Resources/views/Carts/deleteCart.html.twig:
--------------------------------------------------------------------------------
1 | deleted.
2 |
--------------------------------------------------------------------------------
/Resources/views/Transitions/getTransition.html.twig:
--------------------------------------------------------------------------------
1 | {{ content }}!
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | phpunit.xml
3 | Tests/autoload.php
4 | vendor/*
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.3.3
5 | - 5.3
6 | - 5.4
7 | - 5.5
8 |
9 | before_script: composer install --dev --prefer-source
10 |
--------------------------------------------------------------------------------
/Tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | register();
10 |
--------------------------------------------------------------------------------
/Resources/config/validation/orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Resources/config/validation/mongodb.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Resources/views/Carts/newCart.html.twig:
--------------------------------------------------------------------------------
1 | {% block content_header '' %}
2 |
3 | {% block content %}
4 |
{{ 'cart.new.headline'|trans({}, 'AcmeDemoBundle') }}
5 |
6 | {% if (form is defined) %}
7 |
13 | {% endif %}
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/Resources/config/calculator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Leaphly\Cart\Calculator\PriceCalculator
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ./Tests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ./
16 |
17 | ./Resources
18 | ./Tests
19 | ./vendor
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Resources/config/listener.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Leaphly\Cart\Listener\PriceCalculatorListener
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Resources/config/transition.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Leaphly\Cart\Transition\FiniteTransition
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Resources/config/parameter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Leaphly\CartBundle\Controller\CartsController
9 | Leaphly\CartBundle\Controller\CartItemsController
10 | Leaphly\Cart\Handler\CartItemHandler
11 | Leaphly\Cart\Handler\CartHandler
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Tests/TestCart.php:
--------------------------------------------------------------------------------
1 |
10 | * @package Leaphly\Cart\Tests
11 | */
12 | class TestCart extends Cart
13 | {
14 | /**
15 | * @param $id
16 | */
17 | public function setId($id)
18 | {
19 | $this->id = $id;
20 | }
21 |
22 | /**
23 | * @return string
24 | */
25 | public function serialize()
26 | {
27 | return 'dummy_cart';
28 | }
29 |
30 | /**
31 | * @param string $serialized
32 | */
33 | public function unserialize($serialized)
34 | {
35 | $data = unserialize($serialized);
36 |
37 | list(
38 | $this->expireseAt,
39 | $this->id
40 | ) = $data;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Resources/config/event.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | Leaphly\Cart\Event\CartEventFactory
10 | Leaphly\Cart\Event\ItemEventFactory
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Resources/config/orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | %leaphly_cart.model.cart.class%
11 |
12 |
13 |
14 | %leaphly_cart.model_manager_name%
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Resources/config/mongodb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | %leaphly_cart.model.cart.class%
11 |
12 |
13 |
14 | %leaphly_cart.model_manager_name%
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Resources/config/form.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Leaphly\Cart\Form\Factory\FormFactory
9 |
10 |
11 |
12 |
13 |
14 | %leaphly_cart.model.cart.class%
15 |
16 |
17 |
18 |
19 | %leaphly_cart.model.cart.class%
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Resources/meta/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010-2011 Leaphly
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Resources/views/layout.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 | {% for type, messages in app.session.flashbag.all() %}
19 | {% for message in messages %}
20 |
21 | {{ message }}
22 |
23 | {% endfor %}
24 | {% endfor %}
25 |
26 |
27 | {% block leaphly_cart_content %}
28 | {% endblock leaphly_cart_content %}
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Resources/views/Items/getItem.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ "leaply.item.name" | trans }}: {{ item.name }}
4 |
5 | {% if item.price >= 0.01 %}
6 |
7 | {{ "leaply.item.price" | trans }}: {{ item.price ~ " " ~ item.currency }}
8 |
9 | {% if item.price > item.finalPrice %}
10 |
11 | {{ "leaply.item.finalPrice" | trans }}:
12 | {{ item.finalPrice ~ " " ~ item.currency }}
13 |
14 | {% endif %}
15 | {% endif %}
16 |
25 |
26 |
--------------------------------------------------------------------------------
/Resources/config/doctrine/model/Item.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Resources/config/doctrine/model/Item.mongodb.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Resources/views/Carts/getCart.html.twig:
--------------------------------------------------------------------------------
1 |
2 | {% for item in cart.items %}
3 | {{ include("LeaphlyCartBundle:Items:getItem.html.twig", { "item": item }) }}
4 | {% else %}
5 | {{ "leaply.cart.empty" | trans }}
6 | {% endfor %}
7 | {% if cart.price >= 0.01 %}
8 |
9 | {{ "leaply.cart.price" | trans }}: {{ cart.price ~ " " ~ cart.currency }}
10 |
11 | {% if cart.price > cart.finalPrice %}
12 |
13 | {{ "leaply.cart.finalPrice" | trans }}: {{ cart.finalPrice ~ " " ~ cart.currency }}
14 |
15 | {% endif %}
16 | {% endif %}
17 | {# todo: I don"t know if we need to say something about the state... -#}
18 |
29 |
30 |
--------------------------------------------------------------------------------
/Resources/config/doctrine/model/Cart.mongodb.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Resources/config/doctrine/model/Cart.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/ValidationPass.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | class ValidationPass implements CompilerPassInterface
15 | {
16 | /**
17 | * {@inheritDoc}
18 | */
19 | public function process(ContainerBuilder $container)
20 | {
21 | if (!$container->hasParameter('leaphly_cart.storage')) {
22 | return;
23 | }
24 |
25 | $storage = $container->getParameter('leaphly_cart.storage');
26 | if ('custom' === $storage) {
27 | return;
28 | }
29 |
30 | if (!$container->hasParameter('validator.mapping.loader.xml_files_loader.mapping_files')) {
31 | return;
32 | }
33 |
34 | $files = $container->getParameter('validator.mapping.loader.xml_files_loader.mapping_files');
35 | $validationFile = __DIR__ . '/../../Resources/config/validation/' . $storage . '.xml';
36 |
37 | if (is_file($validationFile)) {
38 | $files[] = realpath($validationFile);
39 | $container->addResource(new FileResource($validationFile));
40 | }
41 |
42 | $container->setParameter('validator.mapping.loader.xml_files_loader.mapping_files', $files);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leaphly/cart-bundle",
3 | "type": "symfony-bundle",
4 | "description": "Cart Bundle",
5 | "keywords": ["Cart management"],
6 | "homepage": "http://leaphly.org",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Giulio De Donato",
11 | "email": "liuggio@gmail.com"
12 | },
13 | {
14 | "name": "Leaphly Community",
15 | "homepage": "https://github.com/leaphly/CartBundle/contributors"
16 | }
17 | ],
18 | "minimum-stability": "dev",
19 | "require": {
20 | "php": ">=5.3.2",
21 | "symfony/framework-bundle": "~2",
22 | "jms/serializer-bundle": "~0",
23 | "leaphly/cart":"0.1.x-dev"
24 | },
25 | "require-dev": {
26 | "doctrine/doctrine-fixtures-bundle": "dev-master",
27 | "phpunit/phpunit": "3.7.*",
28 | "liip/functional-test-bundle":"dev-master"
29 | },
30 | "suggest": {
31 | "doctrine/doctrine-fixtures-bundle": "Required when using the fixture loading functionality",
32 | "doctrine/mongodb-odm-bundle": "Required when using ODM as db-driver",
33 | "doctrine/doctrine-bundle": "Required when using ORM as db-driver",
34 | "friendsofsymfony/rest-bundle": "Required if you want to use the Rest Controller"
35 | },
36 | "autoload": {
37 | "psr-0": { "Leaphly\\CartBundle": "" }
38 | },
39 | "extra": {
40 | "branch-alias": {
41 | "dev-master": "0.1.x-dev"
42 | }
43 | },
44 | "target-dir": "Leaphly/CartBundle"
45 | }
46 |
--------------------------------------------------------------------------------
/Controller/CartTransitionsController.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class CartTransitionsController extends FOSRestController
14 | {
15 | /**
16 | * Apply a transition to a cart.
17 | *
18 | * @ApiDoc(
19 | * resource=true
20 | * )
21 | *
22 | * @param mixed $cart_id
23 | * @param string $transition
24 |
25 | * @return \FOS\RestBundle\View\View
26 | *
27 | * @api
28 | */
29 | public function postTransitionAction($cart_id, $transition)
30 | {
31 | $cart = $this->get('leaphly_cart.cart_manager')->findOr404($cart_id);
32 |
33 | $this->get('leaphly_cart.cart.transition')->apply($cart, $transition, true);
34 |
35 | return $this->view($cart, 201, array())
36 | ->setTemplate("LeaphlyCartBundle:Carts:getTransition.html.twig")
37 | ->setTemplateVar('cart');
38 | }
39 |
40 | /**
41 | * Get the answer if is possible to apply a transaction to the cart.
42 | *
43 | * @ApiDoc(
44 | * resource=true
45 | * )
46 | *
47 | * @param mixed $cart_id
48 | * @param string $transition
49 |
50 | * @return \FOS\RestBundle\View\View
51 | *
52 | * @api
53 | */
54 | public function getTransitionAction($cart_id, $transition)
55 | {
56 | $cart = $this->get('leaphly_cart.cart_manager')->findOr404($cart_id);
57 | $status = 200;
58 |
59 | if (!($content = $this->get('leaphly_cart.cart.transition')->can($cart, $transition))) {
60 | $status = 406;
61 | }
62 |
63 | return $this->view($content, $status, array())
64 | ->setTemplate("LeaphlyCartBundle:Transitions:getTransition.html.twig")
65 | ->setTemplateVar('content');
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | CartBundle
2 | =================
3 |
4 | [](http://travis-ci.org/leaphly/CartBundle) [](https://packagist.org/packages/leaphly/cart-bundle) [](https://packagist.org/packages/leaphly/cart-bundle)
5 |
6 | Mission-statement
7 | ----------
8 |
9 | The Leaphly project makes it easier for developers to add cart functionality to the Symfony2 applications or to those applications that could consume REST API.
10 |
11 | This software provides the tools and guidelines for building decoupled, high-quality and long-life e-commerce applications.
12 |
13 | [continue reading on the website](http://leaphly.org)
14 |
15 | Demo
16 | ----
17 |
18 | [demo](http://leaphly.org/#demo)
19 |
20 | License
21 | -------
22 |
23 | This bundle is under the MIT license. See the complete license in the bundle:
24 |
25 | Resources/meta/LICENSE
26 |
27 | Test
28 | ----
29 |
30 | ``` bash
31 | composer.phar create-project leaphly/cart-bundle`
32 | vendor/bin/phpunit
33 | ```
34 |
35 | All the Functional tests are into the [leaphly-sandbox](https://github.com/leaphly/leaphly-sandbox).
36 |
37 | About
38 | -----
39 |
40 | CartBundle is a [leaphly](https://github.com/leaphly) initiative.
41 | See also the list of [contributors](https://github.com/leaphly/CartBundle/contributors).
42 | CartBundle has been inspired by the architecture of FosUserBundle.
43 |
44 | Reporting an issue or a feature request
45 | ---------------------------------------
46 |
47 | Issues and feature requests are tracked in the [Github issue tracker](https://github.com/leaphly/CartBundle/issues).
48 |
49 | When reporting a bug, it may be a good idea to reproduce it in a basic project
50 | built using the [Symfony Standard Edition](https://github.com/symfony/symfony-standard)
51 | to allow developers of the bundle to reproduce the issue by simply cloning it
52 | and following some steps.
53 |
54 |
55 | TODO
56 | -----------------------
57 |
58 | - ~Complete the Rest controllers.~
59 |
60 | - ~Better usage of the finite transitions.~
61 |
62 | - ~Decouple Bundle and library.~
63 |
64 | - Add more DB drivers
65 |
66 |
--------------------------------------------------------------------------------
/LeaphlyCartBundle.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | class LeaphlyCartBundle extends Bundle
17 | {
18 | public function build(ContainerBuilder $container)
19 | {
20 | parent::build($container);
21 | $container->addCompilerPass(new ValidationPass());
22 |
23 | $this->addRegisterMappingsPass($container);
24 | }
25 |
26 | /**
27 | * @param ContainerBuilder $container
28 | */
29 | private function addRegisterMappingsPass(ContainerBuilder $container)
30 | {
31 | // the base class is only available since symfony 2.3
32 | $symfonyVersion = class_exists('Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterMappingsPass');
33 |
34 | $mappings = array(
35 | realpath(__DIR__ . '/Resources/config/doctrine/model') => 'Leaphly\Cart\Model',
36 | );
37 |
38 | if ($symfonyVersion && class_exists('Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass')) {
39 | $container->addCompilerPass(DoctrineOrmMappingsPass::createXmlMappingDriver($mappings, array('leaphly_cart.model_manager_name'), 'leaphly_cart.backend_type_orm'));
40 | } else {
41 | $container->addCompilerPass(RegisterMappingsPass::createOrmMappingDriver($mappings));
42 | }
43 |
44 | if ($symfonyVersion && class_exists('Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass')) {
45 | $container->addCompilerPass(DoctrineMongoDBMappingsPass::createXmlMappingDriver($mappings, array('leaphly_cart.model_manager_name'), 'leaphly_cart.backend_type_mongodb'));
46 | } else {
47 | $container->addCompilerPass(RegisterMappingsPass::createMongoDBMappingDriver($mappings));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Resources/config/validation.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/RegisterMappingsPass.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | class RegisterMappingsPass implements CompilerPassInterface
21 | {
22 | private $driver;
23 | private $driverPattern;
24 | private $namespaces;
25 | private $enabledParameter;
26 | private $fallbackManagerParameter;
27 |
28 | public function __construct($driver, $driverPattern, $namespaces, $enabledParameter, $fallbackManagerParameter)
29 | {
30 | $this->driver = $driver;
31 | $this->driverPattern = $driverPattern;
32 | $this->namespaces = $namespaces;
33 | $this->enabledParameter = $enabledParameter;
34 | $this->fallbackManagerParameter = $fallbackManagerParameter;
35 | }
36 |
37 | /**
38 | * Register mappings with the metadata drivers.
39 | *
40 | * @param ContainerBuilder $container
41 | */
42 | public function process(ContainerBuilder $container)
43 | {
44 | if (!$container->hasParameter($this->enabledParameter)) {
45 | return;
46 | }
47 |
48 | $chainDriverDefService = $this->getChainDriverServiceName($container);
49 | $chainDriverDef = $container->getDefinition($chainDriverDefService);
50 | foreach ($this->namespaces as $namespace) {
51 | $chainDriverDef->addMethodCall('addDriver', array($this->driver, $namespace));
52 | }
53 | }
54 |
55 | protected function getChainDriverServiceName(ContainerBuilder $container)
56 | {
57 | foreach (array('leaphly_cart.model_manager_name', $this->fallbackManagerParameter) as $param) {
58 | if ($container->hasParameter($param)) {
59 | $name = $container->getParameter($param);
60 | if ($name) {
61 | return sprintf($this->driverPattern, $name);
62 | }
63 | }
64 | }
65 |
66 | throw new ParameterNotFoundException('None of the managerParameters resulted in a valid name');
67 | }
68 |
69 | public static function createOrmMappingDriver(array $mappings)
70 | {
71 | $arguments = array($mappings, '.orm.xml');
72 | $locator = new Definition('Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator', $arguments);
73 | $driver = new Definition('Doctrine\ORM\Mapping\Driver\XmlDriver', array($locator));
74 |
75 | return new RegisterMappingsPass($driver, 'doctrine.orm.%s_metadata_driver', $mappings, 'leaphly_cart.backend_type_orm', 'doctrine.default_entity_manager');
76 | }
77 |
78 | public static function createMongoDBMappingDriver($mappings)
79 | {
80 | $arguments = array($mappings, '.mongodb.xml');
81 | $locator = new Definition('Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator', $arguments);
82 | $driver = new Definition('Doctrine\ODM\MongoDB\Mapping\Driver\XmlDriver', array($locator));
83 |
84 | return new RegisterMappingsPass($driver, 'doctrine_mongodb.odm.%s_metadata_driver', $mappings, 'leaphly_cart.backend_type_mongodb', 'doctrine_mongodb.odm.default_document_manager');
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Controller/BaseController.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | abstract class BaseController extends ContainerAware
21 | {
22 | protected $cartHandler;
23 |
24 | public function setCartHandler(CartHandlerInterface $cartHandler)
25 | {
26 | $this->cartHandler = $cartHandler;
27 | }
28 | /**
29 | * Create a view
30 | *
31 | * Convenience method to allow for a fluent interface.
32 | *
33 | * @param mixed $data
34 | * @param integer $statusCode
35 | * @param array $headers
36 | *
37 | * @return View
38 | */
39 | protected function view($data = null, $statusCode = null, array $headers = array())
40 | {
41 | return View::create($data, $statusCode, $headers);
42 | }
43 |
44 | /**
45 | * Create a Redirect view
46 | *
47 | * Convenience method to allow for a fluent interface.
48 | *
49 | * @param string $url
50 | * @param integer $statusCode
51 | * @param array $headers
52 | *
53 | * @return View
54 | */
55 | protected function redirectView($url, $statusCode = Codes::HTTP_FOUND, array $headers = array())
56 | {
57 | return RedirectView::create($url, $statusCode, $headers);
58 | }
59 |
60 | /**
61 | * Create a Route Redirect View
62 | *
63 | * Convenience method to allow for a fluent interface.
64 | *
65 | * @param string $route
66 | * @param mixed $parameters
67 | * @param integer $statusCode
68 | * @param array $headers
69 | *
70 | * @return View
71 | */
72 | protected function routeRedirectView($route, array $parameters = array(), $statusCode = Codes::HTTP_CREATED, array $headers = array())
73 | {
74 | return RouteRedirectView::create($route, $parameters, $statusCode, $headers);
75 | }
76 |
77 | /**
78 | * Convert view into a response object.
79 | *
80 | * Not necessary to use, if you are using the "ViewResponseListener", which
81 | * does this conversion automatically in kernel event "onKernelView".
82 | *
83 | * @param View $view
84 | *
85 | * @return Response
86 | */
87 | protected function handleView(View $view)
88 | {
89 | return $this->container->get('fos_rest.view_handler')->handle($view);
90 | }
91 |
92 | /**
93 | * Create the Response.
94 | *
95 | * @param CartInterface $cart
96 | * @param int $statusCode
97 | * @param string $getCartRoute
98 | *
99 | * @return \FOS\RestBundle\View\View
100 | */
101 | protected function createResponse(CartInterface $cart, $statusCode = 204, $getCartRoute = 'api_1_get_cart')
102 | {
103 | $headers = array();
104 |
105 | $response = new Response();
106 | $response->setStatusCode($statusCode);
107 |
108 | // set the `Location` header only when creating new resources
109 | if (201 === $statusCode) {
110 | $headers = array('Location'=>
111 | $this->container->get('router')->generate(
112 | $getCartRoute, array('cart_id' => $cart->getId(), '_format' => $this->container->get('request')->get('_format') ),
113 | true
114 | )
115 | );
116 | }
117 |
118 | return $this->view($cart, $statusCode, $headers);
119 |
120 | }
121 |
122 | /**
123 | * Fetch the Cart.
124 | *
125 | * @param mixed $cart_id
126 | *
127 | * @return CartInterface
128 | *
129 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
130 | */
131 | protected function fetchCartOr404($cart_id)
132 | {
133 | if (!($cart = $this->cartHandler->getCart($cart_id))) {
134 | throw new NotFoundHttpException($cart_id);
135 | }
136 |
137 | return $cart;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class Configuration implements ConfigurationInterface
18 | {
19 | static $supportedDrivers = array('orm', 'mongodb');
20 | /**
21 | * Generates the configuration tree.
22 | *
23 | * @return TreeBuilder
24 | */
25 | public function getConfigTreeBuilder()
26 | {
27 | $treeBuilder = new TreeBuilder();
28 | $rootNode = $treeBuilder->root('leaphly_cart');
29 |
30 | $rootNode
31 | ->children()
32 | ->scalarNode('cart_class')->isRequired()->cannotBeEmpty()->end()
33 | ->scalarNode('cart_manager')->defaultValue('leaphly_cart.cart_manager.default')->end()
34 | ->scalarNode('model_manager_name')->defaultNull()->end()
35 | ->scalarNode('product_family_provider')->isRequired()->cannotBeEmpty()->end()
36 | ->booleanNode('use_price_listener')->defaultTrue()->end()
37 | ->scalarNode('cart_transition')->defaultValue('leaphly_cart.cart.finite.transition')->end()
38 | ->end();
39 |
40 | $this->addDbDriver($rootNode);
41 | $this->addRoles($rootNode);
42 |
43 | return $treeBuilder;
44 | }
45 |
46 | private function addDbDriver(ArrayNodeDefinition $node)
47 | {
48 | $node
49 | ->children()
50 | ->scalarNode('db_driver')
51 | ->validate()
52 | ->ifNotInArray(self::$supportedDrivers)
53 | ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode(self::$supportedDrivers))
54 | ->end()
55 | ->cannotBeOverwritten()
56 | ->isRequired()
57 | ->cannotBeEmpty()
58 | ->end()
59 | ->end();
60 | }
61 |
62 | private function addRoles(ArrayNodeDefinition $node)
63 | {
64 | $node
65 | ->addDefaultsIfNotSet()
66 | ->children()
67 | ->arrayNode('roles')
68 | ->useAttributeAsKey('name')
69 | ->prototype('array')
70 | ->children()
71 | ->booleanNode('is_default')->defaultFalse()->end()
72 | ->arrayNode('handler')
73 | ->canBeUnset()
74 | ->children()
75 | ->scalarNode('cart')->cannotBeEmpty()->end()
76 | ->scalarNode('item')->cannotBeEmpty()->end()
77 | ->end()
78 | ->end()
79 | ->arrayNode('controller')
80 | ->children()
81 | ->scalarNode('cart')->cannotBeEmpty()->end()
82 | ->scalarNode('item')->cannotBeEmpty()->end()
83 | ->end()
84 | ->end()
85 | ->scalarNode('form')->end()
86 | ->scalarNode('strategy')->end()
87 | ->scalarNode('fallback_strategy')->end()
88 | ->end()
89 | ->validate()
90 | ->ifTrue(function ($v) {return !isset($v['form']) && !isset($v['handler']['cart']);})
91 | ->thenInvalid('You need to specify or the form or the cart handler.')
92 | ->end()
93 | ->end()
94 | ->isRequired()
95 | ->cannotBeEmpty()
96 | ->validate()
97 | ->ifTrue(function ($v) {return (count($v) < 1);})
98 | ->thenInvalid('You need to specify at least one role.')
99 | ->end()
100 | ->validate()
101 | ->ifTrue(function ($roles) {
102 | $counter = 0;
103 | foreach ($roles as $role) {
104 | $counter += (isset($role['is_default']) && $role['is_default'])? 1 : 0;
105 | }
106 |
107 | return ($counter > 1);
108 | })
109 | ->thenInvalid('Multiple `is_default` defined.')
110 | ->end()
111 | ->end()
112 | ;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/Controller/CartItemsController.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | class CartItemsController extends BaseController
17 | {
18 | protected $itemHandler;
19 |
20 | public function setItemHandler(CartItemHandlerInterface $itemHandler)
21 | {
22 | $this->itemHandler = $itemHandler;
23 | }
24 |
25 | /**
26 | *
27 | * @ApiDoc(
28 | * resource=true
29 | * )
30 | *
31 | * @api
32 | *
33 | * @param mixed $cart_id
34 | *
35 | * @return Response
36 | */
37 | public function postItemAction($cart_id)
38 | {
39 | $cart = $this->fetchCartOr404($cart_id);
40 | $headers = array('Location' =>
41 | $this->container->get('router')->generate(
42 | 'api_1_get_cart', array('cart_id' => $cart->getId(), '_format' => $this->container->get('request')->get('_format') ),
43 | true)
44 | );
45 |
46 | try {
47 | $this->itemHandler
48 | ->postItem(
49 | $cart,
50 | $this->container->get('request')->request->all()
51 | );
52 |
53 | $view = $this->view($cart, 201, $headers)
54 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
55 | ->setTemplateVar('cart');
56 |
57 | } catch (InvalidFormException $exception) {
58 | return $this->view(array('errors' => $exception->getForm()), 422, $headers);
59 |
60 | } catch (BadRequestHttpException $ex) {
61 |
62 | $view = $this->view($cart, $ex->getCode())
63 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
64 | ->setTemplateVar('cart');
65 |
66 | }
67 |
68 | return $view;
69 | }
70 |
71 | /**
72 | *
73 | * @ApiDoc(
74 | * resource=true
75 | * )
76 | *
77 | * @api
78 | *
79 | * @param mixed $cart_id
80 | * @param mixed $item_id
81 | *
82 | * @return Response
83 | */
84 | public function patchItemAction($cart_id, $item_id)
85 | {
86 | $cart = $this->fetchCartOr404($cart_id);
87 | $item = $cart->getItemById($item_id);
88 |
89 | $headers = array(
90 | 'Location' => $this->container->get('router')->generate(
91 | 'api_1_get_cart', array(
92 | 'cart_id' => $cart->getId(),
93 | '_format' => $this->container->get('request')->get('_format')
94 | ), true
95 | )
96 | );
97 |
98 | try {
99 | $cart = $this->itemHandler
100 | ->patchItem(
101 | $cart,
102 | $item,
103 | $this->container->get('request')->request->all()
104 | );
105 |
106 | $view = $this->view($cart, 200, $headers)
107 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
108 | ->setTemplateVar('cart');
109 |
110 | } catch (InvalidFormException $exception) {
111 | return $this->view(array('errors' => $exception->getForm()), 422);
112 |
113 | } catch (BadRequestHttpException $ex) {
114 |
115 | $view = $this->view($cart, $ex->getCode())
116 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
117 | ->setTemplateVar('cart');
118 |
119 | }
120 |
121 | return $view;
122 | }
123 |
124 | /**
125 | * Delete Item.
126 | *
127 | * @ApiDoc(
128 | * resource=true
129 | * )
130 | *
131 | * @api
132 | *
133 | * @param mixed $cart_id
134 | * @param mixed $item_id
135 | *
136 | * @return Response
137 | *
138 | * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
139 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
140 | */
141 | public function deleteItemAction($cart_id, $item_id)
142 | {
143 | $cart = $this->fetchCartOr404($cart_id);
144 | $item = $cart->getItemById($item_id);
145 |
146 | if (!$item) {
147 | throw new NotFoundHttpException();
148 | }
149 |
150 | try {
151 | $this->itemHandler->deleteItem($cart, $item);
152 |
153 | $view = $this->view($cart, 200)
154 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
155 | ->setTemplateVar('cart');
156 |
157 | } catch (BadRequestHttpException $ex) {
158 |
159 | $view = $this->view($cart, $ex->getCode())
160 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
161 | ->setTemplateVar('cart');
162 | }
163 |
164 | return $view;
165 | } // "delete_cart_item" [DELETE] /carts/{cart_id}/items/{item_id}
166 |
167 | /**
168 | * Delete all Items.
169 | *
170 | * @ApiDoc(
171 | * resource=true
172 | * )
173 | *
174 | * @api
175 | *
176 | * @param mixed $cart_id
177 | *
178 | * @return Response
179 | *
180 | * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
181 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
182 | */
183 | public function deleteItemsAction($cart_id)
184 | {
185 | $cart = $this->fetchCartOr404($cart_id);
186 |
187 | try {
188 | $this->itemHandler->deleteAllItems($cart);
189 |
190 | $view = $this->view($cart, 200)
191 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
192 | ->setTemplateVar('cart');
193 | } catch (BadRequestHttpException $ex) {
194 |
195 | $view = $this->view($cart, $ex->getCode())
196 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
197 | ->setTemplateVar('cart');
198 | }
199 |
200 | return $view;
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/Controller/CartsController.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | class CartsController extends BaseController
21 | {
22 | /**
23 | * Get a single cart.
24 | *
25 | * @ApiDoc(
26 | * resource = true,
27 | * output = "Acme\Cart\Model\CartInterface",
28 | * statusCodes = {
29 | * 200 = "Returned when successful",
30 | * 404 = "Returned when the cart is not found"
31 | * }
32 | * )
33 | * @api
34 | * @Annotations\View(templateVar="cart")
35 | *
36 | * @param Request $request the request object
37 | * @param int $cart_id the cart id
38 | *
39 | * @return array
40 | *
41 | * @throws NotFoundHttpException when cart not exist
42 | */
43 | public function getCartAction(Request $request, $cart_id)
44 | {
45 | $cart = $this->fetchCartOr404($cart_id);
46 |
47 | return $cart;
48 | }
49 |
50 | /**
51 | * Removes a cart.
52 | *
53 | * @ApiDoc(
54 | * resource = true,
55 | * statusCodes={
56 | * 204="Returned when successful",
57 | * 400="Returned when request is a bad request",
58 | * 404="Returned when the cart is not found"
59 | * }
60 | * )
61 | *
62 | * @api
63 | * @Annotations\View(statusCode = Codes::HTTP_NO_CONTENT)
64 | *
65 | * @param Request $request the request object
66 | * @param int $cart_id the cart id
67 | *
68 | * @return array|View
69 | *
70 | * @throws NotFoundHttpException when cart not exist
71 | */
72 | public function deleteCartAction(Request $request, $cart_id)
73 | {
74 | $cart = $this->fetchCartOr404($cart_id);
75 |
76 | try {
77 | $this->cartHandler->deleteCart($cart);
78 | } catch (BadRequestHttpException $ex) {
79 | return $this->view($cart, $ex->getCode())
80 | ->setTemplate("LeaphlyCartBundle:Carts:getCart.html.twig")
81 | ->setTemplateVar('cart');
82 | }
83 |
84 | return array();
85 | }
86 |
87 | /**
88 | * Create a new cart from the submitted data.
89 | *
90 | * @ApiDoc(
91 | * resource = true,
92 | * input = "Leaphly\Cart\Form\Type\CartFormType",
93 | * statusCodes = {
94 | * 201 = "Returned when successful created",
95 | * 400 = "Returned when the form has errors"
96 | * }
97 | * )
98 | *
99 | * @Annotations\View(
100 | * template = "AcmeCartBundle:Cart:newCart.html.twig",
101 | * statusCode = Codes::HTTP_BAD_REQUEST
102 | * )
103 | *
104 | * @param Request $request the request object
105 | *
106 | * @return FormTypeInterface[]|RouteRedirectView
107 | */
108 | public function postCartAction(Request $request)
109 | {
110 | try {
111 | $cart = $this->cartHandler->postCart($request->request->all());
112 | } catch (InvalidFormException $exception) {
113 | return array('form' => $exception->getForm());
114 | }
115 |
116 | $routeOptions = array(
117 | 'cart_id' => $cart->getId(),
118 | '_format' => $request->get('_format')
119 | );
120 |
121 | return $this->routeRedirectView('api_1_get_cart', $routeOptions, Codes::HTTP_CREATED);
122 | }
123 |
124 | /**
125 | * Update existing cart from the submitted data or create a new cart at a specific location.
126 | *
127 | * @ApiDoc(
128 | * resource = true,
129 | * input = "Leaphly\Cart\Form\Type\CartFormType",
130 | * statusCodes = {
131 | * 201 = "Returned when creates a new cart",
132 | * 204 = "Returned when successful",
133 | * 400 = "Returned when the form has errors",
134 | * }
135 | * )
136 | *
137 | * @Annotations\View(
138 | * template="AcmeDemoBundle:Cart:editCart.html.twig",
139 | * statusCode = Codes::HTTP_BAD_REQUEST
140 | * )
141 | *
142 | * @param Request $request the request object
143 | * @param int $cart_id the cart id
144 | *
145 | * @return FormTypeInterface[]|RouteRedirectView
146 | */
147 | public function putCartAction(Request $request, $cart_id)
148 | {
149 | try {
150 | if (!($cart = $this->cartHandler->getCart($cart_id))) {
151 | $cart = $this->cartHandler->postCart($request->request->all());
152 | $statusCode = Codes::HTTP_CREATED;
153 | } else {
154 | $cart = $this->cartHandler->putCart($cart, $request->request->all());
155 | $statusCode = Codes::HTTP_NO_CONTENT;
156 | }
157 | } catch (InvalidFormException $exception) {
158 | return array('form' => $exception->getForm());
159 | }
160 |
161 | $routeOptions = array(
162 | 'cart_id' => $cart->getId(),
163 | '_format' => $request->get('_format')
164 | );
165 |
166 | return $this->routeRedirectView('api_1_get_cart', $routeOptions, $statusCode);
167 | }
168 |
169 | /**
170 | * Partially Update existing cart from the submitted data or create a new cart at a specific location.
171 | *
172 | * @ApiDoc(
173 | * resource = true,
174 | * input = "Leaphly\Cart\Form\Type\CartFormType",
175 | * statusCodes = {
176 | * 204 = "Returned when successful",
177 | * 400 = "Returned when the form has errors",
178 | * }
179 | * )
180 | *
181 | * @Annotations\View(
182 | * template="AcmeDemoBundle:Cart:editCart.html.twig",
183 | * statusCode = Codes::HTTP_BAD_REQUEST
184 | * )
185 | *
186 | * @param Request $request the request object
187 | * @param int $cart_id the cart id
188 | *
189 | * @return FormTypeInterface[]|RouteRedirectView
190 | */
191 | public function patchCartAction(Request $request, $cart_id)
192 | {
193 | $cart = $this->fetchCartOr404($cart_id);
194 |
195 | try {
196 | $this->cartHandler->patchCart($cart, $request->request->all());
197 | } catch (InvalidFormException $exception) {
198 | return array('form' => $exception->getForm());
199 | }
200 |
201 | $routeOptions = array(
202 | 'cart_id' => $cart->getId(),
203 | '_format' => $request->get('_format')
204 | );
205 |
206 | return $this->routeRedirectView('api_1_get_cart', $routeOptions, Codes::HTTP_NO_CONTENT);
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/DependencyInjection/LeaphlyCartExtension.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class LeaphlyCartExtension extends Extension
18 | {
19 | public function load(array $configs, ContainerBuilder $container)
20 | {
21 | $processor = new Processor();
22 | $configuration = new Configuration();
23 | $config = $processor->processConfiguration($configuration, $configs);
24 |
25 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
26 |
27 | $this->loadDbDriver($config, $container, $loader);
28 | $this->loadServices(array('calculator', 'listener', 'event', 'transition', 'parameter'), $loader);
29 |
30 | $container->setAlias('leaphly_cart.cart.transition', $config['cart_transition']);
31 | $container->setAlias('leaphly_cart.cart_manager', $config['cart_manager']);
32 | $container->setAlias('leaphly_cart.product_family_provider', $config['product_family_provider']);
33 |
34 | $this->remapParametersNamespaces($config, $container, array(
35 | '' => array(
36 | 'model_manager_name' => 'leaphly_cart.model_manager_name',
37 | 'cart_class' => 'leaphly_cart.model.cart.class'
38 | )
39 | ));
40 |
41 | $this->registerPriceListener($config, $container);
42 | $container->setParameter('leaphly_cart.cart.form.name', 'cart');
43 | $this->loadFormType($container, $loader, $config);
44 | $this->loadRoles($config, $container);
45 |
46 | $this->defineGodfatherConfiguration($config, $container);
47 | }
48 |
49 | private function registerPriceListener($config, ContainerBuilder $container)
50 | {
51 | if ($config['use_price_listener']) {
52 | $container->getDefinition('leaphly_cart.listener.price_calculator')->addTag(
53 | 'kernel.event_listener',
54 | array('method' => 'calculatePrice', 'event'=>\Leaphly\Cart\LeaphlyCartEvents::CART_CREATE_SUCCESS)
55 | );
56 | $container->getDefinition('leaphly_cart.listener.price_calculator')->addTag(
57 | 'kernel.event_listener',
58 | array('method' => 'calculatePrice', 'event'=>\Leaphly\Cart\LeaphlyCartEvents::CART_EDIT_SUCCESS)
59 | );
60 | $container->getDefinition('leaphly_cart.listener.price_calculator')->addTag(
61 | 'kernel.event_listener',
62 | array('method' => 'calculatePrice', 'event'=>\Leaphly\Cart\LeaphlyCartEvents::ITEM_CREATE_SUCCESS)
63 | );
64 | $container->getDefinition('leaphly_cart.listener.price_calculator')->addTag(
65 | 'kernel.event_listener',
66 | array('method' => 'calculatePrice', 'event'=>\Leaphly\Cart\LeaphlyCartEvents::ITEM_DELETE_COMPLETED)
67 | );
68 | }
69 | }
70 |
71 | private function loadRoles($config, ContainerBuilder $container)
72 | {
73 | $cartControllerClass = $container->getParameter('leaphly_cart.cart.controller.class');
74 | $cartHandlerClass = $container->getParameter('leaphly_cart.cart.handler.class');
75 | $itemControllerClass = $container->getParameter('leaphly_cart.item.controller.class');
76 | $itemHandlerClass = $container->getParameter('leaphly_cart.item.handler.class');
77 | $cartFormFactoryHandlerClass = $container->getParameter('leaphly_cart.cart.form.factory.class');
78 | $defaultCartHandler = 'leaphly_cart.cart.handler';
79 | $defaultCartItemHandler = 'leaphly_cart.cart_item.handler';
80 |
81 | if (isset($config['roles'])) {
82 | foreach ($config['roles'] as $roleName => $role) {
83 |
84 | $cartHandlerId = sprintf('leaphly_cart.cart.%s.handler', $roleName);
85 | $controllerId = sprintf('leaphly_cart.cart.%s.controller', $roleName);
86 | $formFactoryName = sprintf('leaphly_cart.cart.%s.form.factory', $roleName);
87 | $cartItemHandlerId = sprintf('leaphly_cart.cart_item.%s.handler', $roleName);
88 | $controllerCartItemId =sprintf('leaphly_cart.cart_item.%s.controller', $roleName);
89 |
90 | // if the handler is not defined explicitally, register the cart.handler
91 | if (isset($role['form']) && !isset($role['handler']['cart'])) {
92 | $this->registerFormFactory($container, $formFactoryName, $cartFormFactoryHandlerClass, '%leaphly_cart.cart.form.name%', $role['form']);
93 | $this->registerCartHandler($container, $cartHandlerId, $cartHandlerClass, $formFactoryName);
94 | } elseif (isset($role['handler']['cart'])) {
95 | $container->setAlias($cartHandlerId, $role['handler']['cart']);
96 | }
97 |
98 | // use the cart handler in the controller
99 | if (!isset($role['controller']['cart'])) {
100 | $this->registerController(
101 | $container,
102 | $controllerId,
103 | $cartControllerClass,
104 | array(
105 | array('setContainer', array(new Reference('service_container'))),
106 | array('setCartHandler', array(new Reference($cartHandlerId)))
107 | )
108 | );
109 | } else {
110 | $container->setAlias($controllerId, $role['controller']['cart']);
111 | }
112 |
113 | $strategy = isset($role['strategy']) ? $role['strategy'] : sprintf('godfather.%s', $roleName);
114 |
115 | if (isset($role['form']) && !isset($role['handler']['item'])) {
116 | $this->registerCartItemHandler($container, $cartItemHandlerId, $itemHandlerClass, $strategy);
117 | } elseif (isset($role['handler']['item'])) {
118 | $container->setAlias($cartItemHandlerId, $role['handler']['item']);
119 | }
120 |
121 | if (!isset($role['controller']['item'])) {
122 | $this->registerController(
123 | $container,
124 | $controllerCartItemId,
125 | $itemControllerClass,
126 | array(
127 | array('setContainer', array(new Reference('service_container'))),
128 | array('setCartHandler', array(new Reference($cartHandlerId))),
129 | array('setItemHandler', array(new Reference($cartItemHandlerId)))
130 | )
131 | );
132 | } else {
133 | $container->setAlias($controllerCartItemId, $role['controller']['item']);
134 | }
135 |
136 | // setting the default cart hanlder
137 | if (!$container->hasAlias($defaultCartHandler) || $role['is_default']) {
138 | $container->setAlias($defaultCartHandler, $cartHandlerId);
139 | }
140 | // setting the default cart hanlder
141 | if (!$container->hasAlias($defaultCartItemHandler) || $role['is_default']) {
142 | $container->setAlias($defaultCartItemHandler, $cartItemHandlerId);
143 | }
144 |
145 | }
146 | }
147 | }
148 |
149 | private function loadDbDriver($config, ContainerBuilder $container, XmlFileLoader $loader)
150 | {
151 | $loader->load(sprintf('%s.xml', $config['db_driver']));
152 | $container->setParameter($this->getAlias() . '.backend_type_' . $config['db_driver'], true);
153 | }
154 |
155 | private function loadServices(array $services, XmlFileLoader $loader)
156 | {
157 | foreach ($services as $basename) {
158 | $loader->load(sprintf('%s.xml', $basename));
159 | }
160 | }
161 |
162 | private function registerController(ContainerBuilder $container, $id, $class, $calls = array())
163 | {
164 | $controller = new Definition($class);
165 | $controller->setMethodCalls($calls);
166 | $container->setDefinition($id, $controller);
167 | }
168 |
169 | private function registerService(ContainerBuilder $container, $id, $class, $params = array())
170 | {
171 | $arguments = array_map(function ($arg) use ($container) {
172 | if ($arg[0] == '%' && $arg[strlen($arg) - 1] == '%') {
173 | return $container->getParameter(str_replace('%', '', $arg));
174 | } else {
175 | return new Reference($arg);
176 | }
177 | }, $params);
178 | $service = new Definition($class, $arguments);
179 | $container->setDefinition($id, $service);
180 | }
181 |
182 | private function registerFormFactory(ContainerBuilder $container, $formNameId, $cartFormFactoryHandlerClass, $formName, $formType)
183 | {
184 | $this->registerService(
185 | $container,
186 | $formNameId,
187 | $cartFormFactoryHandlerClass,
188 | array(
189 | 'form.factory',
190 | $formName,
191 | $formType
192 | )
193 | );
194 | }
195 |
196 | private function registerCartHandler(ContainerBuilder $container, $nameId, $cartHandlerClass, $formFactoryName)
197 | {
198 | $this->registerService(
199 | $container,
200 | $nameId,
201 | $cartHandlerClass,
202 | array(
203 | 'leaphly_cart.cart_manager',
204 | $formFactoryName,
205 | 'leaphly_cart.cart.transition',
206 | 'event_dispatcher',
207 | 'leaphly_cart.cart_event_factory'
208 | )
209 | );
210 | }
211 |
212 | private function registerCartItemHandler(ContainerBuilder $container, $nameId, $cartItemHandlerClass, $strategy)
213 | {
214 | $this->registerService(
215 | $container,
216 | $nameId,
217 | $cartItemHandlerClass,
218 | array(
219 | 'leaphly_cart.cart_manager',
220 | 'leaphly_cart.product_family_provider',
221 | $strategy,
222 | 'leaphly_cart.cart.transition',
223 | 'event_dispatcher',
224 | 'leaphly_cart.cart_item.event_factory'
225 | )
226 | );
227 | }
228 |
229 | private function defineGodfatherConfiguration($config, ContainerBuilder $container)
230 | {
231 | $godfatherConfiguration = array();
232 |
233 | foreach ($config['roles'] as $roleName => $role) {
234 | $roleStrategy = array(
235 | 'contexts' => array(
236 | 'item_handler' => array(
237 | ),
238 | )
239 | );
240 |
241 | if (isset($role['fallback_strategy'])) {
242 | $roleStrategy['contexts']['handler']['fallback'] = $role['fallback_strategy'];
243 | }
244 | $godfatherConfiguration['godfather'][$roleName] = $roleStrategy;
245 | }
246 |
247 | $strategy = new GodfatherExtension();
248 | $strategy->load($godfatherConfiguration, $container);
249 | }
250 |
251 | private function loadFormType(ContainerBuilder $container, XmlFileLoader $loader, $config)
252 | {
253 | $loader->load('form.xml');
254 | }
255 |
256 | protected function remapParameters(array $config, ContainerBuilder $container, array $map)
257 | {
258 | foreach ($map as $name => $paramName) {
259 | if (array_key_exists($name, $config)) {
260 | $container->setParameter($paramName, $config[$name]);
261 | }
262 | }
263 | }
264 |
265 | protected function remapParametersNamespaces(array $config, ContainerBuilder $container, array $namespaces)
266 | {
267 | foreach ($namespaces as $ns => $map) {
268 | if ($ns) {
269 | if (!array_key_exists($ns, $config)) {
270 | continue;
271 | }
272 | $namespaceConfig = $config[$ns];
273 | } else {
274 | $namespaceConfig = $config;
275 | }
276 | if (is_array($map)) {
277 | $this->remapParameters($namespaceConfig, $container, $map);
278 | } else {
279 | foreach ($namespaceConfig as $name => $value) {
280 | $container->setParameter(sprintf($map, $name), $value);
281 | }
282 | }
283 | }
284 | }
285 | }
286 |
--------------------------------------------------------------------------------
/Tests/DependencyInjection/LeaphlyCartExtensionTest.php:
--------------------------------------------------------------------------------
1 |
12 | * @package Leaphly\CartBundle\Tests\DependencyInjection
13 | */
14 | class LeaphlyCartExtensionTest extends \PHPUnit_Framework_TestCase
15 | {
16 | /** @var ContainerBuilder */
17 | protected $configuration;
18 |
19 | /**
20 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
21 | */
22 | public function testCartLoadThrowsExceptionUnlessDatabaseDriverSet()
23 | {
24 | $loader = new LeaphlyCartExtension();
25 | $config = $this->getFullConfigForOneRole();
26 | unset($config['db_driver']);
27 | $loader->load(array($config), new ContainerBuilder());
28 | }
29 |
30 | /**
31 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
32 | */
33 | public function testCartLoadThrowsExceptionUnlessDatabaseDriverIsValid()
34 | {
35 | $loader = new LeaphlyCartExtension();
36 | $config = $this->getFullConfigForOneRole();
37 | $config['db_driver'] = 'foo';
38 | $loader->load(array($config), new ContainerBuilder());
39 | }
40 |
41 | /**
42 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
43 | */
44 | public function testCartLoadThrowsExceptionUnlessCartModelClassSet()
45 | {
46 | $loader = new LeaphlyCartExtension();
47 | $config = $this->getFullConfigForOneRole();
48 | unset($config['cart_class']);
49 | $loader->load(array($config), new ContainerBuilder());
50 | }
51 |
52 | public function testCartLoadModelClass()
53 | {
54 | $this->createFullConfiguration();
55 | $this->assertParameter('Acme\MyBundle\Entity\Cart', 'leaphly_cart.model.cart.class');
56 | }
57 |
58 | public function testDefaultCartTransitionWithAlias()
59 | {
60 | $this->createFullConfiguration();
61 | $this->assertAlias('leaphly_cart.cart.finite.transition', 'leaphly_cart.cart.transition');
62 | }
63 |
64 | public function testCustomCartTransition()
65 | {
66 | $config = $this->getOnlyFormConfig();
67 | $config['cart_transition'] = 'my.custom';
68 | $this->createConfiguration($config);
69 | $this->assertNotAlias('leaphly_cart.cart.finite.transition', 'leaphly_cart.cart.transition');
70 | $this->assertHasDefinition('leaphly_cart.cart.transition');
71 | }
72 |
73 | public function testCartLoadManagerClass()
74 | {
75 | $this->createFullConfiguration();
76 | $this->assertAlias('acme_my.product_family_provider', 'leaphly_cart.product_family_provider');
77 | }
78 |
79 | public function testCartHandlerRegistration()
80 | {
81 | $this->createConfiguration($this->getOnlyFormConfig());
82 |
83 | $this->assertHasDefinition('leaphly_cart.cart.full.handler');
84 | $this->assertHasDefinition('leaphly_cart.cart.limited.handler');
85 | }
86 |
87 | public function testControllersRegistration()
88 | {
89 | $this->createConfiguration($this->getOnlyFormConfig());
90 | $this->assertHasDefinition('leaphly_cart.cart.full.controller');
91 | $this->assertHasDefinition('leaphly_cart.cart.limited.controller');
92 | }
93 |
94 | public function testGodFatherAutoConfiguration()
95 | {
96 | $this->createConfiguration($this->getFullConfig());
97 |
98 | $this->assertHasDefinition('godfather.full');
99 | $this->assertHasDefinition('godfather.limited');
100 | }
101 |
102 | /**
103 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
104 | */
105 | public function testExpectedExceptionWhenMultipleDefaultRole()
106 | {
107 | $roleName = 'full';
108 | $config = $this->getFullConfig();
109 | $config['roles']['full']['is_default'] = true;
110 | $config['roles']['limited']['is_default'] = true;
111 | $this->createConfiguration($config);
112 | }
113 |
114 | public function testSetDefaultRole()
115 | {
116 | $cartHandlerId = 'leaphly_cart.cart.handler';
117 |
118 | $config = $this->getFullConfig();
119 | $config['roles']['limited']['is_default'] = true;
120 | $this->createConfiguration($config);
121 |
122 | $this->assertAlias('leaphly_cart.cart.limited.handler', $cartHandlerId);
123 | }
124 |
125 | public function testIsDefaultRole()
126 | {
127 | $cartHandlerId = 'leaphly_cart.cart.handler';
128 |
129 | $config = $this->getFullConfig();
130 | $config['roles']['full']['is_default'] = true;
131 | $config['roles']['limited']['is_default'] = false;
132 | $this->createConfiguration($config);
133 |
134 | $this->assertAlias('leaphly_cart.cart.full.handler', $cartHandlerId);
135 | }
136 |
137 | public function testAllExplicitRoles()
138 | {
139 | $roleName = 'full';
140 | $cartHandlerId = sprintf('leaphly_cart.cart.%s.handler', $roleName);
141 | $controllerId = sprintf('leaphly_cart.cart.%s.controller', $roleName);
142 | $cartItemHandlerId = sprintf('leaphly_cart.cart_item.%s.handler', $roleName);
143 | $controllerCartItemId =sprintf('leaphly_cart.cart_item.%s.controller', $roleName);
144 |
145 | $this->createConfiguration($this->getFullConfigForOneRole());
146 | $this->assertAlias('full.controller.cart', $controllerId);
147 | $this->assertAlias('full.controller.item', $controllerCartItemId);
148 | $this->assertAlias('full.handler.cart', $cartHandlerId);
149 | $this->assertAlias('full.handler.item', $cartItemHandlerId);
150 | }
151 |
152 | public function testControllerShouldBeRegisteredDefiningFormAndHandlersExplicitly()
153 | {
154 | $roleName = 'full';
155 | $cartHandlerId = sprintf('leaphly_cart.cart.%s.handler', $roleName);
156 | $controllerId = sprintf('leaphly_cart.cart.%s.controller', $roleName);
157 | $cartItemHandlerId = sprintf('leaphly_cart.cart_item.%s.handler', $roleName);
158 | $controllerCartItemId =sprintf('leaphly_cart.cart_item.%s.controller', $roleName);
159 |
160 | $config = $this->getFullConfigForOneRole();
161 | unset($config['roles']['full']['controller']);
162 | $this->createConfiguration($config);
163 | $this->assertHasDefinition($controllerId);
164 | $this->assertHasDefinition($controllerCartItemId);
165 | $this->assertAlias('full.handler.cart', $cartHandlerId);
166 | $this->assertAlias('full.handler.item', $cartItemHandlerId);
167 | }
168 |
169 | public function testHandlersAndControllerShouldBeRegisteredDefiningFormExplicitly()
170 | {
171 | $roleName = 'full';
172 | $cartHandlerId = sprintf('leaphly_cart.cart.%s.handler', $roleName);
173 | $controllerId = sprintf('leaphly_cart.cart.%s.controller', $roleName);
174 | $formFactoryName = sprintf('leaphly_cart.cart.%s.form.factory', $roleName);
175 | $cartItemHandlerId = sprintf('leaphly_cart.cart_item.%s.handler', $roleName);
176 | $controllerCartItemId =sprintf('leaphly_cart.cart_item.%s.controller', $roleName);
177 |
178 | $config = $this->getFullConfigForOneRole();
179 | unset($config['roles']['full']['handler']);
180 | unset($config['roles']['full']['controller']);
181 | $this->createConfiguration($config);
182 | $this->assertHasDefinition($controllerId);
183 | $this->assertHasDefinition($controllerCartItemId);
184 | $this->assertHasDefinition($cartHandlerId);
185 | $this->assertHasDefinition($cartItemHandlerId);
186 | }
187 |
188 | public function testControllerShouldBeRegisteredDefiningHandlersExplicitly()
189 | {
190 | $roleName = 'full';
191 | $cartHandlerId = sprintf('leaphly_cart.cart.%s.handler', $roleName);
192 | $controllerId = sprintf('leaphly_cart.cart.%s.controller', $roleName);
193 | $cartItemHandlerId = sprintf('leaphly_cart.cart_item.%s.handler', $roleName);
194 | $controllerCartItemId =sprintf('leaphly_cart.cart_item.%s.controller', $roleName);
195 |
196 | $config = $this->getFullConfigForOneRole();
197 | unset($config['roles']['form']);
198 | unset($config['roles']['full']['controller']);
199 | $this->createConfiguration($config);
200 | $this->assertHasDefinition($controllerId);
201 | $this->assertHasDefinition($controllerCartItemId);
202 | $this->assertHasDefinition($cartHandlerId);
203 | $this->assertHasDefinition($cartItemHandlerId);
204 | }
205 |
206 | /**
207 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
208 | */
209 | public function testWithRolesExpectedException()
210 | {
211 | $config = $this->getBaseConfig();
212 | $this->createConfiguration($config);
213 | }
214 |
215 | /**
216 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
217 | */
218 | public function testWithoutRolesExpectedException()
219 | {
220 | $config = $this->getBaseConfig();
221 | unset($config['roles']);
222 | $this->createConfiguration($config);
223 | }
224 |
225 | /**
226 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
227 | */
228 | public function testNotDefiningFormAndHandlersExceptionShouldBeExpected()
229 | {
230 |
231 | $config = $this->getFullConfigForOneRole();
232 | unset($config['roles']['full']['form']);
233 | unset($config['roles']['full']['handler']);
234 | $this->createConfiguration($config);
235 | }
236 |
237 | protected function createFullConfiguration()
238 | {
239 | $this->configuration = new ContainerBuilder();
240 | $loader = new LeaphlyCartExtension();
241 | $config = $this->getFullConfig();
242 | $loader->load(array($config), $this->configuration);
243 | $this->assertTrue($this->configuration instanceof ContainerBuilder);
244 | }
245 |
246 | protected function createConfiguration($config)
247 | {
248 | $this->configuration = new ContainerBuilder();
249 | $loader = new LeaphlyCartExtension();
250 | $loader->load(array($config), $this->configuration);
251 | $this->assertTrue($this->configuration instanceof ContainerBuilder);
252 | }
253 |
254 | /**
255 | * getBaseConfig
256 | *
257 | * @return array
258 | */
259 | protected function getBaseConfig()
260 | {
261 | return array(
262 | 'db_driver' => 'mongodb',
263 | 'cart_class' => 'Acme\MyBundle\Document\Cart',
264 | 'product_family_provider' => 'acme_my.product_family_provider',
265 | 'roles' => array()
266 | );
267 | }
268 | protected function getFullConfig()
269 | {
270 | $yaml = <<parse($yaml);
294 | }
295 |
296 | protected function getOnlyFormConfig()
297 | {
298 | $yaml = <<parse($yaml);
312 | }
313 |
314 |
315 | protected function getFullConfigForOneRole()
316 | {
317 | $yaml = <<parse($yaml);
334 | }
335 |
336 | /**
337 | * @param string $value
338 | * @param string $key
339 | */
340 | private function assertAlias($value, $key)
341 | {
342 | $this->assertEquals($value, (string) $this->configuration->getAlias($key), sprintf('%s alias is correct', $key));
343 | }
344 |
345 | /**
346 | * @param string $value
347 | * @param string $key
348 | */
349 | private function assertNotAlias($value, $key)
350 | {
351 | $this->assertNotEquals($value, (string) $this->configuration->getAlias($key), sprintf('%s alias is correct', $key));
352 | }
353 |
354 | /**
355 | * @param mixed $value
356 | * @param string $key
357 | */
358 | private function assertParameter($value, $key)
359 | {
360 | $this->assertEquals($value, $this->configuration->getParameter($key), sprintf('%s parameter is correct', $key));
361 | }
362 |
363 | /**
364 | * @param string $id
365 | */
366 | private function assertHasDefinition($id)
367 | {
368 | $this->assertTrue(($this->configuration->hasDefinition($id) ?: $this->configuration->hasAlias($id)));
369 | }
370 |
371 | /**
372 | * @param string $id
373 | */
374 | private function assertNotHasDefinition($id)
375 | {
376 | $this->assertFalse(($this->configuration->hasDefinition($id) ?: $this->configuration->hasAlias($id)));
377 | }
378 |
379 | protected function tearDown()
380 | {
381 | unset($this->configuration);
382 | }
383 | }
384 |
--------------------------------------------------------------------------------