[AssociationBundle] Merged into ProductBundle

This commit is contained in:
Jan Goralski 2016-11-07 10:58:44 +01:00
parent ea8c3b35a2
commit a80347f30d
52 changed files with 306 additions and 1367 deletions

View file

@ -3,6 +3,11 @@ UPGRADE
## From 0.19 to 1.0.0-alpha
### Association and AssociationBundle
* Merged Association component with Product component
* Merged AssociationBundle into ProductBundle
### Customer
* Renamed ``Group`` to ``CustomerGroup``

View file

@ -0,0 +1,40 @@
<?php
namespace Sylius\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20161108115020 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('ALTER TABLE sylius_product_association DROP FOREIGN KEY FK_48E9CDABB1E1C39');
$this->addSql('CREATE TABLE sylius_product_association_type (id INT AUTO_INCREMENT NOT NULL, code VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_CCB8914C77153098 (code), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
$this->addSql('DROP TABLE sylius_association_type');
$this->addSql('ALTER TABLE sylius_product_association ADD CONSTRAINT FK_48E9CDABB1E1C39 FOREIGN KEY (association_type_id) REFERENCES sylius_product_association_type (id) ON DELETE CASCADE');
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('ALTER TABLE sylius_product_association DROP FOREIGN KEY FK_48E9CDABB1E1C39');
$this->addSql('CREATE TABLE sylius_association_type (id INT AUTO_INCREMENT NOT NULL, code VARCHAR(255) NOT NULL COLLATE utf8_unicode_ci, name VARCHAR(255) NOT NULL COLLATE utf8_unicode_ci, created_at DATETIME NOT NULL, updated_at DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_6237029277153098 (code), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
$this->addSql('DROP TABLE sylius_product_association_type');
$this->addSql('ALTER TABLE sylius_product_association ADD CONSTRAINT FK_48E9CDABB1E1C39 FOREIGN KEY (association_type_id) REFERENCES sylius_association_type (id) ON DELETE CASCADE');
}
}

View file

@ -22,7 +22,7 @@ Create a new Association Type using a dedicated factory. Give the association a
.. code-block:: php
/** @var AssociationTypeInterface $associationType */
/** @var ProductAssociationTypeInterface $associationType */
$associationType = $this->container->get('sylius.factory.product_association_type')->createNew();
$associationType->setCode('accessories');
@ -37,7 +37,7 @@ To have the new association type in the system add it to the repository.
How to add a new Association to a Product?
------------------------------------------
Find in your system a product to which you would like to add an association. We wiill use a Go Pro camera as an example.
Find in your system a product to which you would like to add an association. We will use a Go Pro camera as an example.
.. code-block:: php
@ -51,7 +51,7 @@ in the previous step above.
/** @var ProductAssociationInterface $association */
$association = $this->container->get('sylius.factory.product_association')->createNew();
/** @var AssociationTypeInterface $associationType */
/** @var ProductAssociationTypeInterface $associationType */
$associationType = $this->container->get('sylius.repository.product_association_type')->findOneBy(['code' => 'accessories']);
$association->setType($associationType);
@ -71,7 +71,7 @@ Having a collection of products from the SD cards taxon iterate over them and ad
.. code-block:: php
foreach ($associatedProducts as $associatedProduct) {
$association->addAssociatedObject($associatedProduct);
$association->addAssociatedProduct($associatedProduct);
}
Finally add the created association with SD cards to our Go Pro camera product.

View file

@ -26,7 +26,6 @@ suites:
Taxonomy: { namespace: Sylius\Component\Taxonomy, psr4_prefix: Sylius\Component\Taxonomy, spec_path: src/Sylius/Component/Taxonomy, src_path: src/Sylius/Component/Taxonomy }
User: { namespace: Sylius\Component\User, psr4_prefix: Sylius\Component\User, spec_path: src/Sylius/Component/User, src_path: src/Sylius/Component/User }
AssociationBundle: { namespace: Sylius\Bundle\AssociationBundle, psr4_prefix: Sylius\Bundle\AssociationBundle, spec_path: src/Sylius/Bundle/AssociationBundle, src_path: src/Sylius/Bundle/AssociationBundle }
AddressingBundle: { namespace: Sylius\Bundle\AddressingBundle, psr4_prefix: Sylius\Bundle\AddressingBundle, spec_path: src/Sylius/Bundle/AddressingBundle, src_path: src/Sylius/Bundle/AddressingBundle }
AdminBundle: { namespace: Sylius\Bundle\AdminBundle, psr4_prefix: Sylius\Bundle\AdminBundle, spec_path: src/Sylius/Bundle/AdminBundle, src_path: src/Sylius/Bundle/AdminBundle }
ApiBundle: { namespace: Sylius\Bundle\ApiBundle, psr4_prefix: Sylius\Bundle\ApiBundle, spec_path: src/Sylius/Bundle/ApiBundle, src_path: src/Sylius/Bundle/ApiBundle }

View file

@ -13,9 +13,9 @@ namespace Sylius\Behat\Context\Setup;
use Behat\Behat\Context\Context;
use Sylius\Behat\Service\SharedStorageInterface;
use Sylius\Component\Product\Model\AssociationTypeInterface;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Product\Model\ProductAssociationInterface;
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
@ -84,7 +84,7 @@ final class ProductAssociationContext implements Context
*/
public function theProductHasAnAssociationWithProducts(
ProductInterface $product,
AssociationTypeInterface $productAssociationType,
ProductAssociationTypeInterface $productAssociationType,
array $products
) {
$this->createProductAssociation($product, $productAssociationType, $products);
@ -100,7 +100,7 @@ final class ProductAssociationContext implements Context
$code = $this->generateCodeFromName($name);
}
/** @var AssociationTypeInterface $productAssociationType */
/** @var ProductAssociationTypeInterface $productAssociationType */
$productAssociationType = $this->productAssociationTypeFactory->createNew();
$productAssociationType->setCode($code);
$productAssociationType->setName($name);
@ -111,12 +111,12 @@ final class ProductAssociationContext implements Context
/**
* @param ProductInterface $product
* @param AssociationTypeInterface $productAssociationType
* @param ProductAssociationTypeInterface $productAssociationType
* @param array $associatedProducts
*/
private function createProductAssociation(
ProductInterface $product,
AssociationTypeInterface $productAssociationType,
ProductAssociationTypeInterface $productAssociationType,
array $associatedProducts
) {
/** @var ProductAssociationInterface $productAssociation */
@ -124,7 +124,7 @@ final class ProductAssociationContext implements Context
$productAssociation->setType($productAssociationType);
foreach ($associatedProducts as $associatedProduct) {
$productAssociation->addAssociatedObject($associatedProduct);
$productAssociation->addAssociatedProduct($associatedProduct);
}
$product->addAssociation($productAssociation);

View file

@ -16,7 +16,7 @@ use Sylius\Behat\Page\Admin\Crud\IndexPageInterface;
use Sylius\Behat\Page\Admin\ProductAssociationType\CreatePageInterface;
use Sylius\Behat\Page\Admin\ProductAssociationType\UpdatePageInterface;
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
use Sylius\Component\Product\Model\AssociationTypeInterface;
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
use Webmozart\Assert\Assert;
/**
@ -81,7 +81,7 @@ final class ManagingProductAssociationTypesContext implements Context
/**
* @When I want to modify the :productAssociationType product association type
*/
public function iWantToModifyAPaymentMethod(AssociationTypeInterface $productAssociationType)
public function iWantToModifyAPaymentMethod(ProductAssociationTypeInterface $productAssociationType)
{
$this->updatePage->open(['id' => $productAssociationType->getId()]);
}
@ -134,7 +134,7 @@ final class ManagingProductAssociationTypesContext implements Context
/**
* @When I delete the :productAssociationType product association type
*/
public function iDeleteTheProductAssociationType(AssociationTypeInterface $productAssociationType)
public function iDeleteTheProductAssociationType(ProductAssociationTypeInterface $productAssociationType)
{
$this->iWantToBrowseProductAssociationTypes();
@ -173,7 +173,7 @@ final class ManagingProductAssociationTypesContext implements Context
/**
* @Then the product association type :productAssociationType should appear in the store
*/
public function theProductAssociationTypeShouldAppearInTheStore(AssociationTypeInterface $productAssociationType)
public function theProductAssociationTypeShouldAppearInTheStore(ProductAssociationTypeInterface $productAssociationType)
{
$this->indexPage->open();
@ -191,7 +191,7 @@ final class ManagingProductAssociationTypesContext implements Context
* @Then /^(this product association type) should still be named "([^"]+)"$/
*/
public function thisProductAssociationTypeNameShouldBe(
AssociationTypeInterface $productAssociationType,
ProductAssociationTypeInterface $productAssociationType,
$productAssociationTypeName
) {
$this->iWantToBrowseProductAssociationTypes();
@ -222,7 +222,7 @@ final class ManagingProductAssociationTypesContext implements Context
* @Then /^(this product association type) should no longer exist in the registry$/
*/
public function thisProductAssociationTypeShouldNoLongerExistInTheRegistry(
AssociationTypeInterface $productAssociationType
ProductAssociationTypeInterface $productAssociationType
) {
Assert::false(
$this->indexPage->isSingleResourceOnPage([

View file

@ -1,5 +0,0 @@
vendor/
bin/
composer.phar
composer.lock

View file

@ -1,6 +0,0 @@
CHANGELOG
=========
### v0.17.0
* Initial dev release.

View file

@ -1,129 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\AssociationBundle\DependencyInjection;
use Sylius\Bundle\AssociationBundle\Form\Type\AssociationType;
use Sylius\Bundle\AssociationBundle\Form\Type\AssociationTypeType;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
use Sylius\Bundle\ResourceBundle\Form\Type\ResourceChoiceType;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Sylius\Component\Product\Model\AssociationType as AssociationTypeModel;
use Sylius\Component\Resource\Factory\Factory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('sylius_association');
$rootNode
->addDefaultsIfNotSet()
->children()
->scalarNode('driver')->defaultValue(SyliusResourceBundle::DRIVER_DOCTRINE_ORM)->end()
->end()
;
$this->addResourcesSection($rootNode);
return $treeBuilder;
}
/**
* @param ArrayNodeDefinition $node
*/
private function addResourcesSection(ArrayNodeDefinition $node)
{
$node
->children()
->arrayNode('resources')
->useAttributeAsKey('name')
->prototype('array')
->children()
->scalarNode('subject')->isRequired()->end()
->arrayNode('association')
->isRequired()
->addDefaultsIfNotSet()
->children()
->arrayNode('classes')
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->isRequired()->cannotBeEmpty()->end()
->scalarNode('interface')->isRequired()->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->children()
->scalarNode('default')->defaultValue(AssociationType::class)->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->arrayNode('validation_groups')
->addDefaultsIfNotSet()
->children()
->arrayNode('default')
->prototype('scalar')->end()
->defaultValue(['sylius'])
->end()
->end()
->end()
->end()
->end()
->arrayNode('association_type')
->addDefaultsIfNotSet()
->children()
->arrayNode('classes')
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->defaultValue(AssociationTypeModel::class)->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->children()
->scalarNode('default')->defaultValue(AssociationTypeType::class)->cannotBeEmpty()->end()
->scalarNode('choice')->defaultValue(ResourceChoiceType::class)->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->arrayNode('validation_groups')
->addDefaultsIfNotSet()
->children()
->arrayNode('default')
->prototype('scalar')->end()
->defaultValue(['sylius'])
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
}
}

View file

@ -1,105 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\AssociationBundle\DependencyInjection;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class SyliusAssociationExtension extends AbstractResourceExtension
{
/**
* {@inheritdoc}
*/
public function load(array $config, ContainerBuilder $container)
{
$config = $this->processConfiguration($this->getConfiguration($config, $container), $config);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
$this->registerResources('sylius', $config['driver'], $this->resolveResources($config['resources'], $container), $container);
foreach ($config['resources'] as $subjectName => $subjectConfig) {
$this->resolveFormsConfiguration($subjectConfig, $subjectName, $container);
}
}
/**
* @param array $resources
* @param ContainerBuilder $container
*
* @return array
*/
private function resolveResources(array $resources, ContainerBuilder $container)
{
$subjects = [];
$resolvedResources = [];
foreach ($resources as $subject => $parameters) {
$subjects[$subject] = $parameters;
}
$container->setParameter('sylius.association.subjects', $subjects);
foreach ($resources as $subjectName => $subjectConfig) {
$resolvedResources = array_merge(
$resolvedResources,
$this->resolveResourceConfiguration($subjectConfig, $resolvedResources, $subjectName)
);
}
return $resolvedResources;
}
/**
* @param array $subjectConfig
* @param array $resolvedResources
* @param string $subjectName
*
* @return array
*/
private function resolveResourceConfiguration(array $subjectConfig, array $resolvedResources, $subjectName)
{
foreach ($subjectConfig as $resourceName => $resourceConfig) {
if (!is_array($resourceConfig)) {
continue;
}
$resolvedResources[$subjectName.'_'.$resourceName] = $resourceConfig;
$resolvedResources[$subjectName.'_'.$resourceName]['subject'] = $subjectName;
}
return $resolvedResources;
}
/**
* @param array $subjectConfig
* @param string $subjectName
* @param ContainerBuilder $container
*/
private function resolveFormsConfiguration(array $subjectConfig, $subjectName, ContainerBuilder $container)
{
foreach ($subjectConfig as $resourceName => $resourceConfig) {
if (!is_array($resourceConfig)) {
continue;
}
$formDefinition = $container->getDefinition('sylius.form.type.'.$subjectName.'_'.$resourceName);
$formDefinition->addArgument($subjectName);
}
}
}

View file

@ -1,163 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\AssociationBundle\Doctrine\ORM\Subscriber;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class LoadMetadataSubscriber implements EventSubscriber
{
/**
* @var array
*/
protected $subjects;
/**
* @param array $subjects
*/
public function __construct(array $subjects)
{
$this->subjects = $subjects;
}
/**
* @return array
*/
public function getSubscribedEvents()
{
return [
'loadClassMetadata',
];
}
/**
* @param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$metadata = $eventArgs->getClassMetadata();
$metadataFactory = $eventArgs->getEntityManager()->getMetadataFactory();
foreach ($this->subjects as $subject => $class) {
if ($class['association']['classes']['model'] === $metadata->getName()) {
$associationEntity = $class['subject'];
$associationEntityMetadata = $metadataFactory->getMetadataFor($associationEntity);
$associationTypeModel = $class['association_type']['classes']['model'];
$associationTypeMetadata = $metadataFactory->getMetadataFor($associationTypeModel);
$metadata->mapManyToOne($this->createSubjectMapping($associationEntity, $subject, $associationEntityMetadata));
$metadata->mapManyToMany($this->createAssociationMapping($associationEntity, $subject, $associationEntityMetadata));
$metadata->mapManyToOne($this->createAssociationTypeMapping($associationTypeModel, $associationTypeMetadata));
}
if ($class['subject'] === $metadata->getName()) {
$associationEntity = $class['association']['classes']['model'];
$metadata->mapOneToMany($this->createAssociationsMapping($associationEntity));
}
}
}
/**
* @param string $associationEntity
* @param string $subject
* @param ClassMetadata $associationEntityMetadata
*
* @return array
*/
private function createSubjectMapping($associationEntity, $subject, ClassMetadata $associationEntityMetadata)
{
return [
'fieldName' => 'owner',
'targetEntity' => $associationEntity,
'inversedBy' => 'associations',
'joinColumns' => [[
'name' => $subject.'_id',
'referencedColumnName' => $associationEntityMetadata->fieldMappings['id']['columnName'],
'nullable' => false,
'onDelete' => 'CASCADE',
]],
];
}
/**
* @param string $associationEntity
* @param string $subject
* @param ClassMetadata $associationEntityMetadata
*
* @return array
*/
private function createAssociationMapping($associationEntity, $subject, ClassMetadata $associationEntityMetadata)
{
return [
'fieldName' => 'associatedObjects',
'targetEntity' => $associationEntity,
'joinTable' => [
'name' => sprintf('sylius_%s_association_%s', $subject, $subject),
'joinColumns' => [[
'name' => 'association_id',
'referencedColumnName' => 'id',
'nullable' => false,
'unique' => false,
'onDelete' => 'CASCADE',
]],
'inverseJoinColumns' => [[
'name' => $subject.'_id',
'referencedColumnName' => $associationEntityMetadata->fieldMappings['id']['columnName'],
'nullable' => false,
'unique' => false,
'onDelete' => 'CASCADE',
]],
],
];
}
/**
* @param string $associationModel
* @param ClassMetadata $associationMetadata
*
* @return array
*/
private function createAssociationTypeMapping($associationModel, ClassMetadata $associationMetadata)
{
return [
'fieldName' => 'type',
'targetEntity' => $associationModel,
'joinColumns' => [[
'name' => 'association_type_id',
'referencedColumnName' => $associationMetadata->fieldMappings['id']['columnName'],
'nullable' => false,
'onDelete' => 'CASCADE',
]],
];
}
/**
* @param string $associationEntity
*
* @return array
*/
private function createAssociationsMapping($associationEntity)
{
return [
'fieldName' => 'associations',
'targetEntity' => $associationEntity,
'mappedBy' => 'owner',
'cascade' => ['all'],
];
}
}

View file

@ -1,63 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\AssociationBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
class AssociationType extends AbstractResourceType
{
/**
* @var string
*/
protected $subjectName;
/**
* @param string $dataClass
* @param array $validationGroups
* @param string $subjectName
*/
public function __construct($dataClass, array $validationGroups, $subjectName)
{
parent::__construct($dataClass, $validationGroups);
$this->subjectName = $subjectName;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', sprintf('sylius_%s_association_type_choice', $this->subjectName), [
'label' => sprintf('sylius.form.%s_association.type', $this->subjectName),
])
->add($this->subjectName, sprintf('sylius_%s_choice', $this->subjectName), [
'label' => sprintf('sylius.form.%s_association.%s', $this->subjectName, $this->subjectName),
'property_path' => 'associatedObjects',
'multiple' => true,
])
;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return sprintf('sylius_%s_association', $this->subjectName);
}
}

View file

@ -1,47 +0,0 @@
SyliusAssociationBundle [![Build status...](https://secure.travis-ci.org/Sylius/SyliusAssociationBundle.png?branch=master)](http://travis-ci.org/Sylius/SyliusAssociationBundle)
=====================
Association system for entities in Symfony2 applications.
Sylius
------
![Sylius](http://sylius.org/assets/img/logo.png)
Sylius is an Open Source eCommerce solution built from decoupled components with powerful API and the highest quality code. [Read more on sylius.org](http://sylius.org).
Documentation
-------------
Documentation is available on [**docs.sylius.org**](http://docs.sylius.org).
Contributing
------------
[This page](http://docs.sylius.org/en/latest/contributing/index.html) contains all the information about contributing to Sylius.
Follow Sylius' Development
--------------------------
If you want to keep up with the updates and latest features, follow us on the following channels:
* [Official Blog](https://sylius.org/blog)
* [Sylius on Twitter](https://twitter.com/Sylius)
* [Sylius on Facebook](https://facebook.com/SyliusEcommerce)
Bug tracking
------------
Sylius uses [GitHub issues](https://github.com/Sylius/Sylius/issues).
If you have found bug, please create an issue.
MIT License
-----------
License can be found [here](https://github.com/Sylius/Sylius/blob/master/LICENSE).
Authors
-------
The bundle was originally created by [Łukasz Chruściel](lukasz.chrusciel@lakion.com) based on initial work by [Leszek Prabucki](leszek.prabucki@gmail.com).
See the list of [contributors](https://github.com/Sylius/Sylius/contributors).

View file

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
This file is part of the Sylius package.
(c) Paweł Jędrzejewski
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
-->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<mapped-superclass name="Sylius\Component\Product\Model\Association" table="sylius_association">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="createdAt" column="created_at" type="datetime">
<gedmo:timestampable on="create"/>
</field>
<field name="updatedAt" column="updated_at" type="datetime" nullable="true">
<gedmo:timestampable on="update"/>
</field>
</mapped-superclass>
</doctrine-mapping>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is part of the Sylius package.
(c) Paweł Jędrzejewski
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.doctrine.orm.event_subscriber.load_metadata.association" class="Sylius\Bundle\AssociationBundle\Doctrine\ORM\Subscriber\LoadMetadataSubscriber">
<argument>%sylius.association.subjects%</argument>
<tag name="doctrine.event_subscriber" />
</service>
</services>
</container>

View file

@ -1,19 +0,0 @@
Copyright (c) 2011-2016 Paweł Jędrzejewski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,9 +0,0 @@
sylius:
association_type:
name:
not_blank: Please enter association type name.
min_length: Association type name must be at least 1 character long.|Association name must be at least {{ limit }} characters long.
max_length: Association type name must not be longer than 1 character.|Association name must not be longer than {{ limit }} characters.
code:
unique: The association type with given code already exists.
not_blank: Please enter association type code.

View file

@ -1,12 +0,0 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius:
association_type:
name:
not_blank: Por favor, introduzca el nombre del tipo de asociación.
min_length: El nombre del tipo de asociación debe tener al menos 1 carácter.| El nombre del tipo de asociación debe tener al menos {{ limit }} caracteres.
max_length: El nombre del tipo de asociación no debe tener más de 1 carácter.| El nombre del tipo de asociación no debe tener más de {{ limit }} caracteres.
code:
unique: El tipo de asociación con el código dado ya existe.
not_blank: Por favor, introduzca el código del tipo de asociación.

View file

@ -1,12 +0,0 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius:
association_type:
name:
not_blank: Entrez le nom du type de liaison.
min_length: Le nom de l'association doit posséder au moins 1 caractère. | Le nom de l'association doit posséder au moins {{ limit }} caractères.
max_length: Le nom de l'association ne doit pas excéder 1 caractère.|Le nom de l'association ne doit pas excéder {{ limit }} caractères.
code:
unique: Le type de liaison avec le code donné existe déjà.
not_blank: Veuillez entrer le code du type de liaison.

View file

@ -1,12 +0,0 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius:
association_type:
name:
not_blank: Inserisci il nome del tipo di associazione.
min_length: Nome del tipo di associazione deve essere lungo almeno 1 carattere.| Il nome dell'associazione deve essere lungo almeno {{ limit }} caratteri.
max_length: Nome del tipo di associazione non può essere più lungo di 1 carattere.| Il nome dell'associazione non può essere lungo più di {{ limit }} caratteri.
code:
unique: Il tipo di associazione con questo codice esiste già.
not_blank: Inserisci il codice del tipo di associazione.

View file

@ -1,12 +0,0 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius:
association_type:
name:
not_blank: Voer a.u.b. een naam in voor de associatie type.
min_length: De naam van het gerelateerde type moet minimaal 1 teken bevatten. | De gerelateerde type naam moet ten minste {{ limit }} tekens bevatten.
max_length: De naam van de associatie mag niet langer zijn dan 1 teken.|De naam van de associatie mag niet langer zijn dan {{ limit }} tekens.
code:
unique: De associatie met de gegeven code bestaat al.
not_blank: Voer a.u.b. een een code in voor het associatietype.

View file

@ -1,12 +0,0 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius:
association_type:
name:
not_blank: กรุณาระบุชื่อชนิดความสัมพันธ์
min_length: ชื่อความสัมพันธ์ต้องมีความยาวไม่น้อยกว่า 1 ตัวอักษร|ชื่อความสัมพันธ์ต้องมีความยาวไม่น้อยกว่า {{ limit }} ตัวอักษร
max_length: ชื่อความสัมพันธ์ต้องมีความยาวไม่เกิน 1 ตัวอักษร|ชื่อความสัมพันธ์ต้องมีความยาวไม่เกิน {{ limit }} ตัวอักษร
code:
unique: รหัสความสัมพันธ์ถูกกำหนดแล้ว
not_blank: กรุณาระบุรหัสความสัมพันธ์

View file

@ -1,39 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\AssociationBundle;
use Sylius\Bundle\ResourceBundle\AbstractResourceBundle;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
class SyliusAssociationBundle extends AbstractResourceBundle
{
/**
* {@inheritdoc}
*/
public function getSupportedDrivers()
{
return [
SyliusResourceBundle::DRIVER_DOCTRINE_ORM,
];
}
/**
* {@inheritdoc}
*/
protected function getModelNamespace()
{
return 'Sylius\Component\Product\Model';
}
}

View file

@ -1,66 +0,0 @@
{
"name": "sylius/association-bundle",
"type": "symfony-bundle",
"description": "Products association for your Symfony2 applications.",
"keywords": ["shop", "ecommerce", "products", "product", "assortment", "association"],
"homepage": "http://sylius.org",
"license": "MIT",
"authors": [
{
"name": "Paweł Jędrzejewski",
"homepage": "http://pjedrzejewski.com"
},
{
"name": "Leszek Prabucki",
"email": "leszek.prabucki@gmail.com"
},
{
"name": "Łukasz Chruściel",
"email": "lukasz.chrusciel@lakion.com"
},
{
"name": "Sylius project",
"homepage": "http://sylius.org"
},
{
"name": "Community contributions",
"homepage": "http://github.com/Sylius/Sylius/contributors"
}
],
"require": {
"php": "^5.6|^7.0",
"symfony/framework-bundle": "^2.8",
"doctrine/orm": "^2.4.8",
"stof/doctrine-extensions-bundle": "~1.1",
"symfony/form": "^2.8",
"symfony/validator": "^2.8",
"sylius/resource-bundle": "^1.0",
"sylius/product": "^1.0"
},
"require-dev": {
"phpspec/phpspec": "^3.1"
},
"config": {
"bin-dir": "bin"
},
"autoload": {
"psr-4": { "Sylius\\Bundle\\AssociationBundle\\": "" }
},
"autoload-dev": {
"psr-4": { "Sylius\\Bundle\\AssociationBundle\\spec\\": "spec/" }
},
"minimum-stability": "dev",
"prefer-stable": true,
"repositories": [
{
"type": "path",
"url": "../../*/*"
}
],
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
}
}

View file

@ -1,5 +0,0 @@
suites:
main:
namespace: Sylius\Bundle\AssociationBundle
psr4_prefix: Sylius\Bundle\AssociationBundle
src_path: .

View file

@ -1,130 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\AssociationBundle\Doctrine\ORM\Subscriber;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use PhpSpec\ObjectBehavior;
use Sylius\Bundle\AssociationBundle\Doctrine\ORM\Subscriber\LoadMetadataSubscriber;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class LoadMetadataSubscriberSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith([
'product' => [
'subject' => 'Some\App\Product\Entity\Product',
'association' => [
'classes' => [
'model' => 'Some\App\Product\Entity\EntityAssociation',
],
],
'association_type' => [
'classes' => [
'model' => 'Some\App\Product\Entity\AssociationType',
]
],
],
]);
}
function it_is_initializable()
{
$this->shouldHaveType(LoadMetadataSubscriber::class);
}
function it_is_a_doctrine_event_subscriber()
{
$this->shouldImplement(EventSubscriber::class);
}
function it_subscribes_a_doctrines_load_class_metadata_event()
{
$this->getSubscribedEvents()->shouldReturn(['loadClassMetadata']);
}
function it_loads_class_metadata_for_associations(
LoadClassMetadataEventArgs $eventArguments,
ClassMetadataInfo $metadata,
EntityManager $entityManager,
ClassMetadataFactory $classMetadataFactory,
ClassMetadataInfo $classMetadataInfo
) {
$eventArguments->getClassMetadata()->willReturn($metadata)->shouldBeCalled();
$eventArguments->getEntityManager()->willReturn($entityManager)->shouldBeCalled();
$entityManager->getMetadataFactory()->willReturn($classMetadataFactory)->shouldBeCalled();
$classMetadataInfo->fieldMappings = [
'id' => [
'columnName' => 'id',
],
];
$classMetadataFactory->getMetadataFor('Some\App\Product\Entity\Product')->willReturn($classMetadataInfo);
$classMetadataFactory->getMetadataFor('Some\App\Product\Entity\AssociationType')->willReturn($classMetadataInfo);
$subjectMapping = [
'fieldName' => 'owner',
'targetEntity' => 'Some\App\Product\Entity\Product',
'inversedBy' => 'associations',
'joinColumns' => [[
'name' => 'product_id',
'referencedColumnName' => 'id',
'nullable' => false,
'onDelete' => 'CASCADE',
]],
];
$associationMapping = [
'fieldName' => 'associatedObjects',
'targetEntity' => 'Some\App\Product\Entity\Product',
'joinTable' => [
'name' => 'sylius_product_association_product',
'joinColumns' => [[
'name' => 'association_id',
'referencedColumnName' => 'id',
'nullable' => false,
'unique' => false,
'onDelete' => 'CASCADE',
]],
'inverseJoinColumns' => [[
'name' => 'product_id',
'referencedColumnName' => 'id',
'nullable' => false,
'unique' => false,
'onDelete' => 'CASCADE',
]],
],
];
$associationTypeMapping = [
'fieldName' => 'type',
'targetEntity' => 'Some\App\Product\Entity\AssociationType',
'joinColumns' => [[
'name' => 'association_type_id',
'referencedColumnName' => 'id',
'nullable' => false,
'onDelete' => 'CASCADE',
]],
];
$metadata->getName()->willReturn('Some\App\Product\Entity\EntityAssociation');
$metadata->mapManyToOne($subjectMapping)->shouldBeCalled();
$metadata->mapManyToMany($associationMapping)->shouldBeCalled();
$metadata->mapManyToOne($associationTypeMapping)->shouldBeCalled();
$this->loadClassMetadata($eventArguments);
}
}

View file

@ -1,62 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\AssociationBundle\Form\Type;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\AssociationBundle\Form\Type\AssociationType;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Sylius\Component\Product\Model\Association;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class AssociationTypeSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(Association::class, ['sylius'], 'product');
}
function it_is_initializable()
{
$this->shouldHaveType(AssociationType::class);
}
function it_extends_abstract_resource_type()
{
$this->shouldImplement(AbstractResourceType::class);
}
function it_builds_form(FormBuilderInterface $formBuilder)
{
$formBuilder
->add('type', 'sylius_product_association_type_choice', Argument::cetera())
->shouldBeCalled()
->willReturn($formBuilder)
;
$formBuilder
->add('product', 'sylius_product_choice', Argument::cetera())
->shouldBeCalled()
->willReturn($formBuilder)
;
$this->buildForm($formBuilder, []);
}
function it_has_name()
{
$this->getName()->shouldReturn('sylius_product_association');
}
}

View file

@ -1,63 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\AssociationBundle\Form\Type;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\AssociationBundle\Form\Type\AssociationTypeType;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Sylius\Component\Product\Model\AssociationType;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class AssociationTypeTypeSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(AssociationType::class, ['sylius'], 'product');
}
function it_is_initializable()
{
$this->shouldHaveType(AssociationTypeType::class);
}
function it_extends_abstract_resource_type()
{
$this->shouldImplement(AbstractResourceType::class);
}
function it_builds_form(FormBuilderInterface $formBuilder)
{
$formBuilder
->add('name', 'text', Argument::cetera())
->shouldBeCalled()
->willReturn($formBuilder)
;
$formBuilder
->addEventSubscriber(Argument::type(AddCodeFormSubscriber::class))
->shouldBeCalled()
->willReturn($formBuilder)
;
$this->buildForm($formBuilder, []);
}
function it_has_name()
{
$this->getName()->shouldReturn('sylius_product_association_type');
}
}

View file

@ -54,7 +54,6 @@ class Kernel extends HttpKernel
new \Sylius\Bundle\UserBundle\SyliusUserBundle(),
new \Sylius\Bundle\CustomerBundle\SyliusCustomerBundle(),
new \Sylius\Bundle\UiBundle\SyliusUiBundle(),
new \Sylius\Bundle\AssociationBundle\SyliusAssociationBundle(),
new \Sylius\Bundle\ReviewBundle\SyliusReviewBundle(),
new \Sylius\Bundle\CoreBundle\SyliusCoreBundle(),
new \Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),

View file

@ -1,6 +1,5 @@
imports:
- { resource: "@SyliusCoreBundle/Resources/config/app/sylius/sylius_addressing.yml" }
- { resource: "@SyliusCoreBundle/Resources/config/app/sylius/sylius_association.yml" }
- { resource: "@SyliusCoreBundle/Resources/config/app/sylius/sylius_channel.yml" }
- { resource: "@SyliusCoreBundle/Resources/config/app/sylius/sylius_content.yml" }
- { resource: "@SyliusCoreBundle/Resources/config/app/sylius/sylius_core.yml" }

View file

@ -1,11 +0,0 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius_association:
resources:
product:
subject: "%sylius.model.product.class%"
association:
classes:
model: Sylius\Component\Product\Model\ProductAssociation
interface: Sylius\Component\Product\Model\ProductAssociationInterface

View file

@ -63,6 +63,12 @@
</cascade>
</one-to-many>
<one-to-many field="associations" target-entity="Sylius\Component\Product\Model\ProductAssociationInterface" mapped-by="owner">
<cascade>
<cascade-all/>
</cascade>
</one-to-many>
<gedmo:loggable />
</mapped-superclass>

View file

@ -11,6 +11,8 @@
namespace Sylius\Bundle\ProductBundle\DependencyInjection;
use Sylius\Bundle\ProductBundle\Form\Type\ProductAssociationType;
use Sylius\Bundle\ProductBundle\Form\Type\ProductAssociationTypeType;
use Sylius\Bundle\ProductBundle\Form\Type\ProductOptionTranslationType;
use Sylius\Bundle\ProductBundle\Form\Type\ProductOptionType;
use Sylius\Bundle\ProductBundle\Form\Type\ProductOptionValueTranslationType;
@ -26,6 +28,10 @@ use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Sylius\Component\Product\Factory\ProductFactory;
use Sylius\Component\Product\Factory\ProductVariantFactory;
use Sylius\Component\Product\Model\Product;
use Sylius\Component\Product\Model\ProductAssociation;
use Sylius\Component\Product\Model\ProductAssociationInterface;
use Sylius\Component\Product\Model\ProductAssociationType as ProductAssociationTypeModel;
use Sylius\Component\Product\Model\ProductAssociationTypeInterface as ProductAssociationTypeModelInterface;
use Sylius\Component\Product\Model\ProductInterface;
use Sylius\Component\Product\Model\ProductOption;
use Sylius\Component\Product\Model\ProductOptionInterface;
@ -318,6 +324,69 @@ final class Configuration implements ConfigurationInterface
->end()
->end()
->end()
->arrayNode('product_association')
->addDefaultsIfNotSet()
->children()
->variableNode('options')->end()
->arrayNode('classes')
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->defaultValue(ProductAssociation::class)->cannotBeEmpty()->end()
->scalarNode('interface')->defaultValue(ProductAssociationInterface::class)->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->children()
->scalarNode('default')->defaultValue(ProductAssociationType::class)->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->arrayNode('validation_groups')
->addDefaultsIfNotSet()
->children()
->arrayNode('default')
->prototype('scalar')->end()
->defaultValue(['sylius'])
->end()
->end()
->end()
->end()
->end()
->arrayNode('product_association_type')
->addDefaultsIfNotSet()
->children()
->variableNode('options')->end()
->arrayNode('classes')
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->defaultValue(ProductAssociationTypeModel::class)->cannotBeEmpty()->end()
->scalarNode('interface')->defaultValue(ProductAssociationTypeModelInterface::class)->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->children()
->scalarNode('default')->defaultValue(ProductAssociationTypeType::class)->cannotBeEmpty()->end()
->scalarNode('choice')->defaultValue(ResourceChoiceType::class)->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->arrayNode('validation_groups')
->addDefaultsIfNotSet()
->children()
->arrayNode('default')
->prototype('scalar')->end()
->defaultValue(['sylius'])
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()

View file

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ProductBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
class ProductAssociationType extends AbstractResourceType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', 'sylius_product_association_type_choice', [
'label' => 'sylius.form.product_association.type',
])
->add('product', 'sylius_product_choice', [
'label' => 'sylius.form.product_association.product',
'property_path' => 'associatedProducts',
'multiple' => true,
])
;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'sylius_product_association';
}
}

View file

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\AssociationBundle\Form\Type;
namespace Sylius\Bundle\ProductBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
@ -18,35 +18,18 @@ use Symfony\Component\Form\FormBuilderInterface;
/**
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
*/
class AssociationTypeType extends AbstractResourceType
class ProductAssociationTypeType extends AbstractResourceType
{
/**
* @var string
*/
private $subject;
/**
* @param string $dataClass
* @param array $validationGroups
* @param string $subject
*/
public function __construct($dataClass, array $validationGroups = [], $subject)
{
parent::__construct($dataClass, $validationGroups);
$this->subject = $subject;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->addEventSubscriber(new AddCodeFormSubscriber())
->add('name', 'text', [
'label' => sprintf('sylius.form.%s_association_type.name', $this->subject),
'label' => 'sylius.form.product_association_type.name',
])
->addEventSubscriber(new AddCodeFormSubscriber())
;
}
@ -55,6 +38,6 @@ class AssociationTypeType extends AbstractResourceType
*/
public function getName()
{
return sprintf('sylius_%s_association_type', $this->subject);
return 'sylius_product_association_type';
}
}

View file

@ -11,8 +11,43 @@
-->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<mapped-superclass name="Sylius\Component\Product\Model\ProductAssociation" table="sylius_product_association" />
<mapped-superclass name="Sylius\Component\Product\Model\ProductAssociation" table="sylius_product_association">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="createdAt" column="created_at" type="datetime">
<gedmo:timestampable on="create"/>
</field>
<field name="updatedAt" column="updated_at" type="datetime" nullable="true">
<gedmo:timestampable on="update"/>
</field>
<many-to-one field="type" target-entity="Sylius\Component\Product\Model\ProductAssociationTypeInterface">
<join-columns>
<join-column name="association_type_id" referenced-column-name="id" nullable="false" on-delete="CASCADE" />
</join-columns>
</many-to-one>
<many-to-one field="owner" target-entity="Sylius\Component\Product\Model\ProductInterface" inversed-by="associations">
<join-columns>
<join-column name="product_id" referenced-column-name="id" nullable="false" on-delete="CASCADE" />
</join-columns>
</many-to-one>
<many-to-many field="associatedProducts" target-entity="Sylius\Component\Product\Model\ProductInterface">
<join-table name="sylius_product_association_product">
<join-columns>
<join-column name="association_id" referenced-column-name="id" nullable="false" unique="false" on-delete="CASCADE" />
</join-columns>
<inverse-join-columns>
<join-column name="product_id" referenced-column-name="id" nullable="false" unique="false" on-delete="CASCADE" />
</inverse-join-columns>
</join-table>
</many-to-many>
</mapped-superclass>
</doctrine-mapping>

View file

@ -14,7 +14,7 @@
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<mapped-superclass name="Sylius\Component\Product\Model\AssociationType" table="sylius_association_type">
<mapped-superclass name="Sylius\Component\Product\Model\ProductAssociationType" table="sylius_product_association_type">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>

View file

@ -12,7 +12,7 @@
-->
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/services/constraint-mapping-1.0.xsd">
<class name="Sylius\Component\Product\Model\AssociationType">
<class name="Sylius\Component\Product\Model\ProductAssociationType">
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">code</option>
<option name="message">sylius.association_type.code.unique</option>

View file

@ -33,3 +33,11 @@ sylius:
unique: The option value with given code already exists.
value:
not_blank: Please enter option value.
association_type:
name:
not_blank: Please enter association type name.
min_length: Association type name must be at least 1 character long.|Association name must be at least {{ limit }} characters long.
max_length: Association type name must not be longer than 1 character.|Association name must not be longer than {{ limit }} characters.
code:
unique: The association type with given code already exists.
not_blank: Please enter association type code.

View file

@ -25,7 +25,6 @@
"stof/doctrine-extensions-bundle": "~1.1",
"sylius/product": "^1.0",
"sylius/attribute-bundle": "^1.0",
"sylius/association-bundle": "^1.0",
"sylius/resource-bundle": "^1.0",
"symfony/framework-bundle": "^2.8"
},

View file

@ -1 +1 @@
{% include '@SyliusShop/Product/_simpleList.html.twig' with {'products': product_association.associatedObjects} %}
{% include '@SyliusShop/Product/_simpleList.html.twig' with {'products': product_association.associatedProducts} %}

View file

@ -1,19 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Component\Product\Model;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
interface AssociableInterface
{
}

View file

@ -1,127 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Component\Product\Model;
use Doctrine\Common\Collections\ArrayCollection;
use Sylius\Component\Resource\Model\TimestampableTrait;
/**
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
class Association implements AssociationInterface
{
use TimestampableTrait;
/**
* @var int
*/
protected $id;
/**
* @var AssociationTypeInterface
*/
protected $type;
/**
* @var AssociableInterface
*/
protected $owner;
/**
* @var AssociableInterface[]
*/
protected $associatedObjects;
public function __construct()
{
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
$this->associatedObjects = new ArrayCollection();
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return $this->type;
}
/**
* {@inheritdoc}
*/
public function setType(AssociationTypeInterface $type)
{
$this->type = $type;
}
/**
* {@inheritdoc}
*/
public function getOwner()
{
return $this->owner;
}
/**
* {@inheritdoc}
*/
public function setOwner(AssociableInterface $owner = null)
{
$this->owner = $owner;
}
/**
* {@inheritdoc}
*/
public function getAssociatedObjects()
{
return $this->associatedObjects;
}
/**
* {@inheritdoc}
*/
public function hasAssociatedObject(AssociableInterface $associatedObject)
{
return $this->associatedObjects->contains($associatedObject);
}
/**
* {@inheritdoc}
*/
public function addAssociatedObject(AssociableInterface $associatedObject)
{
if (!$this->hasAssociatedObject($associatedObject)) {
$this->associatedObjects->add($associatedObject);
}
}
/**
* {@inheritdoc}
*/
public function removeAssociatedObject(AssociableInterface $associatedObject)
{
if ($this->hasAssociatedObject($associatedObject)) {
$this->associatedObjects->removeElement($associatedObject);
}
}
}

View file

@ -1,63 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Component\Product\Model;
use Sylius\Component\Resource\Model\ResourceInterface;
use Sylius\Component\Resource\Model\TimestampableInterface;
/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
interface AssociationInterface extends TimestampableInterface, ResourceInterface
{
/**
* @return AssociationType
*/
public function getType();
/**
* @param AssociationTypeInterface $type
*/
public function setType(AssociationTypeInterface $type);
/**
* @return AssociableInterface
*/
public function getOwner();
/**
* @param AssociableInterface|null $owner
*/
public function setOwner(AssociableInterface $owner = null);
/**
* @return AssociableInterface[]
*/
public function getAssociatedObjects();
/**
* @param AssociableInterface $associatedObject
*/
public function addAssociatedObject(AssociableInterface $associatedObject);
/**
* @param AssociableInterface $associatedObject
*/
public function removeAssociatedObject(AssociableInterface $associatedObject);
/**
* @param AssociableInterface $associatedObject
*
* @return bool
*/
public function hasAssociatedObject(AssociableInterface $associatedObject);
}

View file

@ -17,7 +17,7 @@ use Sylius\Component\Resource\Model\TimestampableTrait;
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
class AssociationType implements AssociationTypeInterface
class ProductAssociationType implements ProductAssociationTypeInterface
{
use TimestampableTrait;

View file

@ -19,7 +19,7 @@ use Sylius\Component\Resource\Model\TimestampableInterface;
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
interface AssociationTypeInterface extends CodeAwareInterface, TimestampableInterface, ResourceInterface
interface ProductAssociationTypeInterface extends CodeAwareInterface, TimestampableInterface, ResourceInterface
{
/**
* @return string

View file

@ -12,7 +12,6 @@
namespace Sylius\Component\Product\Model;
use Doctrine\Common\Collections\Collection;
use Sylius\Component\Product\Model\AssociableInterface;
use Sylius\Component\Attribute\Model\AttributeSubjectInterface;
use Sylius\Component\Resource\Model\CodeAwareInterface;
use Sylius\Component\Resource\Model\ResourceInterface;
@ -26,7 +25,6 @@ use Sylius\Component\Resource\Model\TranslatableInterface;
* @author Gonzalo Vilaseca <gvilaseca@reiss.co.uk>
*/
interface ProductInterface extends
AssociableInterface,
AttributeSubjectInterface,
CodeAwareInterface,
ResourceInterface,

View file

@ -1,64 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Component\Product\Model;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Product\Model\AssociableInterface;
use Sylius\Component\Product\Model\Association;
use Sylius\Component\Product\Model\AssociationInterface;
use Sylius\Component\Product\Model\AssociationType;
/**
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class AssociationSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType(Association::class);
}
function it_implements_association_interface()
{
$this->shouldHaveType(AssociationInterface::class);
}
function it_has_owner(AssociableInterface $product)
{
$this->setOwner($product);
$this->getOwner()->shouldReturn($product);
}
function it_has_type(AssociationType $associationType)
{
$this->setType($associationType);
$this->getType()->shouldReturn($associationType);
}
function it_adds_association_objects(AssociableInterface $product)
{
$this->addAssociatedObject($product);
$this->getAssociatedObjects()->shouldHaveCount(1);
}
function it_checks_if_product_is_associated(AssociableInterface $product)
{
$this->hasAssociatedObject($product)->shouldReturn(false);
$this->addAssociatedObject($product);
$this->hasAssociatedObject($product)->shouldReturn(true);
$this->removeAssociatedObject($product);
$this->hasAssociatedObject($product)->shouldReturn(false);
}
}

View file

@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Component\Product\Model;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Product\Model\ProductAssociation;
use Sylius\Component\Product\Model\ProductAssociationInterface;
use Sylius\Component\Product\Model\ProductAssociationType;
use Sylius\Component\Product\Model\ProductInterface;
/**
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class ProductAssociationSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType(ProductAssociation::class);
}
function it_implements_ProductAssociation_interface()
{
$this->shouldHaveType(ProductAssociationInterface::class);
}
function it_has_owner(ProductInterface $product)
{
$this->setOwner($product);
$this->getOwner()->shouldReturn($product);
}
function it_has_type(ProductAssociationType $associationType)
{
$this->setType($associationType);
$this->getType()->shouldReturn($associationType);
}
function it_adds_association_product(ProductInterface $product)
{
$this->addAssociatedProduct($product);
$this->getAssociatedProducts()->shouldHaveCount(1);
}
function it_checks_if_product_is_associated(ProductInterface $product)
{
$this->hasAssociatedProduct($product)->shouldReturn(false);
$this->addAssociatedProduct($product);
$this->hasAssociatedProduct($product)->shouldReturn(true);
$this->removeAssociatedProduct($product);
$this->hasAssociatedProduct($product)->shouldReturn(false);
}
}

View file

@ -12,23 +12,23 @@
namespace spec\Sylius\Component\Product\Model;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Product\Model\AssociationType;
use Sylius\Component\Product\Model\AssociationTypeInterface;
use Sylius\Component\Product\Model\ProductAssociationType;
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
/**
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class AssociationTypeSpec extends ObjectBehavior
final class ProductAssociationTypeSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType(AssociationType::class);
$this->shouldHaveType(ProductAssociationType::class);
}
function it_implements_association_type_interface()
{
$this->shouldImplement(AssociationTypeInterface::class);
$this->shouldImplement(ProductAssociationTypeInterface::class);
}
function it_has_name()

View file

@ -13,7 +13,6 @@ namespace spec\Sylius\Component\Product\Model;
use Doctrine\Common\Collections\Collection;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Product\Model\AssociableInterface;
use Sylius\Component\Product\Model\Product;
use Sylius\Component\Product\Model\ProductAssociationInterface;
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
@ -49,11 +48,6 @@ final class ProductSpec extends ObjectBehavior
$this->shouldImplement(ToggleableInterface::class);
}
function it_is_associatable()
{
$this->shouldImplement(AssociableInterface::class);
}
function it_has_no_id_by_default()
{
$this->getId()->shouldReturn(null);