[Variation] Introduce code to OptionValue and Option

This commit is contained in:
tuka217 2015-12-17 13:02:20 +01:00
parent c438924272
commit ccfb7cb7bd
32 changed files with 339 additions and 78 deletions

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 Version20151221121710 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_option ADD code VARCHAR(255) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_E4C0EBEF77153098 ON sylius_product_option (code)');
$this->addSql('ALTER TABLE sylius_product_option_value ADD code VARCHAR(255) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_F7FF7D4B77153098 ON sylius_product_option_value (code)');
}
/**
* @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('DROP INDEX UNIQ_E4C0EBEF77153098 ON sylius_product_option');
$this->addSql('ALTER TABLE sylius_product_option DROP code');
$this->addSql('DROP INDEX UNIQ_F7FF7D4B77153098 ON sylius_product_option_value');
$this->addSql('ALTER TABLE sylius_product_option_value DROP code');
}
}

View file

@ -7,9 +7,9 @@ Feature: Inventory tracking
Background:
Given store has default configuration
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
And the following products exist:
| name | price | options |
| Super T-Shirt | 19.99 | T-Shirt size, T-Shirt color |

View file

@ -7,13 +7,13 @@ Feature: Product archetypes
Background:
Given store has default configuration
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| Bag color | Color | Black, Light balsamic |
| Beverage size | Size | Tall, Grande, Venti |
| Beverage milk | Milk | None, Whole, Skinny, Soya |
| Coffee variety | Variety | Colombian, Ethiopian |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
| O3 | Bag color | Color | Black[OV7], Light balsamic[OV8] |
| O4 | Beverage size | Size | Tall[OV9], Grande[OV10], Venti[OV11] |
| O5 | Beverage milk | Milk | None[OV12], Whole[OV13], Skinny[OV14], Soya[OV15] |
| O6 | Coffee variety | Variety | Colombian[OV16], Ethiopian[OV17] |
And there are following attributes:
| name | presentation | type |
| T-Shirt collection | Collection | text |

View file

@ -7,9 +7,9 @@ Feature: Product options
Background:
Given store has default configuration
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
And I am logged in as administrator
Scenario: Seeing index of all options
@ -40,7 +40,8 @@ Feature: Product options
Scenario: Trying to create option without at least 2 values
Given I am on the product option creation page
When I fill in "Internal name" with "Bag color"
When I fill in "Code" with "PO3"
And I fill in "Internal name" with "Bag color"
And I fill in "Presentation" with "Color"
And I press "Create"
Then I should still be on the product option creation page
@ -49,13 +50,14 @@ Feature: Product options
@javascript
Scenario: Creating option with 4 possible values
Given I am on the product option creation page
When I fill in "Internal name" with "Bag color"
When I fill in "Code" with "PO3"
And I fill in "Internal name" with "Bag color"
And I fill in "Presentation" with "Color"
And I add following option values:
| Black |
| White |
| Brown |
| Purple |
| OV7 | Black |
| OV8 | White |
| OV9 | Brown |
| OV10 | Purple |
And I press "Create"
Then I should be on the product option index page
And I should see "Option has been successfully created."
@ -63,12 +65,13 @@ Feature: Product options
@javascript
Scenario: Values are listed after creating the option
Given I am on the product option creation page
When I fill in "Internal name" with "Mug type"
When I fill in "Code" with "PO3"
And I fill in "Internal name" with "Mug type"
And I fill in "Presentation" with "Type"
And I add following option values:
| Normal mug |
| Large mug |
| MONSTER mug |
| OV7 | Normal mug |
| OV8 | Large mug |
| OV9 | MONSTER mug |
And I press "Create"
Then I should be on the product option index page
And I should see option with value containing "Normal mug" in that list
@ -77,15 +80,15 @@ Feature: Product options
Scenario: Adding values to existing option
Given I am editing product option "T-Shirt size"
And I add following option values:
| XL |
| XXL |
| OV7 | XL |
| OV8 | XXL |
And I press "Save changes"
Then I should be on the product option index page
And "Option has been successfully updated." should appear on the page
And I should see option with value containing "XXL" in the list
Scenario: Created options appear in the list
Given I created option "Hat size" with values "S, M, L"
Given I created option "Hat size" with values "S[VO3], M[VO4], L[V05]" and option code "PO3"
When I go to the product option index page
Then I should see 3 options in the list
And I should see option with name "Hat size" in that list
@ -105,3 +108,57 @@ Feature: Product options
And I click "delete" from the confirmation modal
Then I should be on the product option index page
And I should not see option with name "T-Shirt color" in that list
Scenario: Cannot edit product option code
When I am editing product option "T-Shirt color"
Then the code field should be disabled
@javascript
Scenario: Try add product option without code
Given I am on the product option creation page
When I fill in "Internal name" with "Bag color"
And I fill in "Presentation" with "Color"
And I add following option values:
| OV7 | Black |
| OV8 | White |
And I press "Create"
Then I should still be on the product option creation page
And I should see "Please enter option code."
@javascript
Scenario: Try add product option with existing code
Given I am on the product option creation page
When I fill in "Code" with "O1"
And I fill in "Internal name" with "Bag color"
And I fill in "Presentation" with "Color"
And I add following option values:
| OV7 | Black |
| OV8 | White |
And I press "Create"
Then I should still be on the product option creation page
And I should see "The option with given code already exists."
@javascript
Scenario: Try add product option values without code
Given I am on the product option creation page
When I fill in "Code" with "O3"
And I fill in "Internal name" with "Bag color"
And I fill in "Presentation" with "Color"
And I add option value "Black"
And I add option value "White"
And I press "Create"
Then I should still be on the product option creation page
And I should see "Please enter option value code."
@javascript
Scenario: Try add product option value with existing code
Given I am on the product option creation page
When I fill in "Code" with "O3"
And I fill in "Internal name" with "Bag color"
And I fill in "Presentation" with "Color"
And I add following option values:
| OV1 | Black |
| OV8 | White |
And I press "Create"
Then I should still be on the product option creation page
And I should see "The option value with given code already exists."

View file

@ -7,9 +7,9 @@ Feature: Product variants
Background:
Given store has default configuration
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
And the following products exist:
| name | price | options |
| Super T-Shirt | 19.99 | T-Shirt size, T-Shirt color |

View file

@ -7,9 +7,9 @@ Feature: Products
Background:
Given store has default configuration
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
And there are following attributes:
| name | type | configuration |
| T-Shirt fabric | text | min:2,max:255 |

View file

@ -13,9 +13,9 @@ Feature: Cart
| Clothing[TX1] > T-Shirts[TX2] |
| Clothing[TX1] > PHP T-Shirts[TX3] |
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
And the following products exist:
| name | price | options | taxons | variants selection |
| Super T-Shirt | 20.00 | T-Shirt size, T-Shirt color | T-Shirts | match |

View file

@ -13,8 +13,8 @@ Feature: Checkout starting
| Clothing[TX1] > T-Shirts[TX2] |
| Clothing[TX1] > PHP T-Shirts[TX3] |
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
And the following products exist:
| name | price | options | taxons | variants selection |
| Super T-Shirt | 20.00 | T-Shirt color | T-Shirts | match |

View file

@ -13,9 +13,9 @@ Feature: Browse products, categories, attributes and options in preferred langua
| Clothing[TX1] > T-Shirts[TX2] |
| Clothing[TX1] > PHP T-Shirts[TX3] |
And there are following options:
| name | presentation | values |
| T-Shirt color | Color | Red, Blue, Green |
| T-Shirt size | Size | S, M, L |
| code | name | presentation | values |
| O1 |T-Shirt color | Color | Red[OV1], Blue[OV2], Green[OV3] |
| O2 |T-Shirt size | Size | S[OV4], M[OV5], L[OV6] |
And there are following attributes:
| name | presentation | type | choices |
| T-Shirt fabric | Fabric | text | |

View file

@ -31,32 +31,55 @@ class LoadProductOptionData extends DataFixture
{
// T-Shirt size option.
$option = $this->createOption(
'O1',
'T-Shirt size',
array($this->defaultLocale => 'Size', 'es_ES' => 'Talla'),
array('S', 'M', 'L', 'XL', 'XXL')
array(
'OV1' => 'S',
'OV2' => 'M',
'OV3' => 'L',
'OV4' => 'XL',
'OV5' => 'XXL',
)
);
$manager->persist($option);
// T-Shirt color option.
$option = $this->createOption(
'O2',
'T-Shirt color',
array($this->defaultLocale => 'Color'),
array('Red', 'Blue', 'Green')
array(
'OV6' => 'Red',
'OV7' => 'Blue',
'OV8' => 'Green',
)
);
$manager->persist($option);
// Sticker size option.
$option = $this->createOption(
'O3',
'Sticker size',
array($this->defaultLocale => 'Size', 'es_ES' => 'Talla'),
array('3"', '5"', '7"'));
array(
'OV9' => '3"',
'OV10' => '5"',
'OV11' => '7"',
)
);
$manager->persist($option);
// Mug type option.
$option = $this->createOption(
'O4',
'Mug type',
array($this->defaultLocale => 'Type', 'es_ES' => 'Tipo'),
array('Medium mug', 'Double mug', 'MONSTER mug')
array(
'OV12' => 'Medium mug',
'OV13' => 'Double mug',
'OV14' => 'MONSTER mug',
)
);
$manager->persist($option);
@ -72,19 +95,19 @@ class LoadProductOptionData extends DataFixture
}
/**
* Create an option.
*
* @param string $optionCode
* @param string $name
* @param array $presentationTranslation
* @param array $values
* @param array $presentationTranslation
* @param array $valuesData
*
* @return OptionInterface
*/
protected function createOption($name, array $presentationTranslation, array $values)
protected function createOption($optionCode, $name, array $presentationTranslation, array $valuesData)
{
/* @var $option OptionInterface */
$option = $this->getProductOptionFactory()->createNew();
$option->setName($name);
$option->setCode($optionCode);
foreach ($presentationTranslation as $locale => $presentation) {
$option->setCurrentLocale($locale);
@ -92,12 +115,13 @@ class LoadProductOptionData extends DataFixture
}
$option->setCurrentLocale($this->defaultLocale);
foreach ($values as $text) {
foreach ($valuesData as $code => $value) {
/* @var $value OptionValueInterface */
$value = $this->getProductOptionValueFactory()->createNew();
$value->setValue($text);
$optionValue = $this->getProductOptionValueFactory()->createNew();
$optionValue->setValue($value);
$optionValue->setCode($code);
$option->addValue($value);
$option->addValue($optionValue);
}
$this->setReference('Sylius.Option.'.$name, $option);

View file

@ -145,26 +145,30 @@ class ProductContext extends DefaultContext
public function thereAreOptions(TableNode $table)
{
foreach ($table->getHash() as $data) {
$this->thereIsOption($data['name'], $data['values'], $data['presentation'], false);
$this->thereIsOption($data['name'], $data['values'], $data['code'], $data['presentation'], false);
}
$this->getEntityManager()->flush();
}
/**
* @Given /^I created option "([^""]*)" with values "([^""]*)"$/
* @Given /^I created option "([^""]*)" with values "([^""]*)" and option code "([^""]*)"$/
*/
public function thereIsOption($name, $values, $presentation = null, $flush = true)
public function thereIsOption($name, $values, $optionCode, $presentation = null, $flush = true)
{
$optionValueFactory = $this->getFactory('product_option_value');
$option = $this->getFactory('product_option')->createNew();
$option->setCode($optionCode);
$option->setName($name);
$option->setPresentation($presentation ?: $name);
foreach (explode(',', $values) as $value) {
foreach(explode(',', $values) as $valueData) {
$valueData = preg_split("[\\[|\\]]", $valueData, -1, PREG_SPLIT_NO_EMPTY);
$optionValue = $optionValueFactory->createNew();
$optionValue->setValue(trim($value));
$optionValue->setValue(trim($valueData[0]));
$optionValue->setCode(trim($valueData[1]));
$option->addValue($optionValue);
}

View file

@ -51,15 +51,15 @@ class AddCodeFormSubscriber implements EventSubscriberInterface
public function preSetData(FormEvent $event)
{
$resource = $event->getData();
$disabled = false;
if (!$resource instanceof CodeAwareInterface) {
if ($resource instanceof CodeAwareInterface) {
$disabled = (null !== $resource->getCode());
} else if (null !== $resource) {
throw new UnexpectedTypeException($resource, CodeAwareInterface::class);
}
$form = $event->getForm();
$disabled = (null !== $resource->getCode());
$form->add('code', $this->type, array('label' => 'sylius.ui.code', 'disabled' => $disabled));
}
}

View file

@ -45,10 +45,10 @@ class AddCodeFormSubscriberSpec extends ObjectBehavior
$event->getData()->willReturn($resource);
$event->getForm()->willReturn($form);
$resource->getCode()->shouldBeCalled()->willReturn('Code12');
$resource->getCode()->willReturn(null);
$form
->add('code', Argument::type('string'), Argument::containing(true))
->add('code', Argument::type('string'), Argument::withEntry('disabled', false))
->shouldBeCalled()
;
@ -63,10 +63,10 @@ class AddCodeFormSubscriberSpec extends ObjectBehavior
$event->getData()->willReturn($resource);
$event->getForm()->willReturn($form);
$resource->getCode()->shouldBeCalled()->willReturn(null);
$resource->getCode()->willReturn('Code12');
$form
->add('code', Argument::type('string'), Argument::containing(false))
->add('code', Argument::type('string'), Argument::withEntry('disabled', true))
->shouldBeCalled()
;
@ -79,6 +79,19 @@ class AddCodeFormSubscriberSpec extends ObjectBehavior
$this->shouldThrow('\UnexpectedTypeException');
}
function it_sets_code_as_enabled_when_resource_is_null(FormEvent $event, FormInterface $form)
{
$event->getForm()->willReturn($form);
$event->getData()->willReturn(null);
$form
->add('code', 'text', Argument::withEntry('disabled', false))
->shouldBeCalled()
;
$this->preSetData($event);
}
function it_adds_code_with_specified_type(FormEvent $event, FormInterface $form, CodeAwareInterface $resource)
{
$this->beConstructedWith('currency');
@ -86,10 +99,10 @@ class AddCodeFormSubscriberSpec extends ObjectBehavior
$event->getData()->willReturn($resource);
$event->getForm()->willReturn($form);
$resource->getCode()->shouldBeCalled()->willReturn('Code12');
$resource->getCode()->willReturn('Code12');
$form
->add('code', 'currency', Argument::containing(true))
->add('code', 'currency', Argument::withEntry('disabled', true))
->shouldBeCalled()
;
@ -101,10 +114,10 @@ class AddCodeFormSubscriberSpec extends ObjectBehavior
$event->getData()->willReturn($resource);
$event->getForm()->willReturn($form);
$resource->getCode()->shouldBeCalled()->willReturn('Code12');
$resource->getCode()->willReturn('Code12');
$form
->add('code', 'text', Argument::containing(true))
->add('code', 'text', Argument::withEntry('disabled', true))
->shouldBeCalled()
;

View file

@ -11,6 +11,7 @@
namespace Sylius\Bundle\VariationBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Symfony\Component\Form\FormBuilderInterface;
@ -58,6 +59,7 @@ class OptionType extends AbstractResourceType
'label' => false,
'button_add_label' => 'sylius.form.option_value.add_value',
))
->addEventSubscriber(new AddCodeFormSubscriber())
;
}

View file

@ -11,6 +11,7 @@
namespace Sylius\Bundle\VariationBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Symfony\Component\Form\FormBuilderInterface;
@ -45,6 +46,7 @@ class OptionValueType extends AbstractResourceType
->add('value', 'text', array(
'label' => 'sylius.form.option_value.value',
))
->addEventSubscriber(new AddCodeFormSubscriber())
;
}

View file

@ -22,6 +22,7 @@
<generator strategy="AUTO" />
</id>
<field name="code" column="code" type="string" unique="true" />
<field name="name" column="name" type="string" />
<field name="createdAt" column="created_at" type="datetime">

View file

@ -22,6 +22,7 @@
<generator strategy="AUTO" />
</id>
<field name="code" column="code" type="string" unique="true" />
<field name="value" column="value" type="string" />
</mapped-superclass>

View file

@ -2,6 +2,9 @@ Sylius\Component\Variation\Model\Option:
exclusion_policy: ALL
xml_root_name: option
properties:
code:
exopse: true
type: string
name:
expose: true
type: string

View file

@ -2,6 +2,9 @@ Sylius\Component\Variation\Model\OptionValue:
exclusion_policy: ALL
xml_root_name: option-value
properties:
code:
expose: true
type: string
value:
expose: true
type: string

View file

@ -23,6 +23,17 @@
</class>
<class name="Sylius\Component\Variation\Model\Option">
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">code</option>
<option name="message">sylius.option.code.unique</option>
<option name="groups">sylius</option>
</constraint>
<property name="code">
<constraint name="NotBlank">
<option name="message">sylius.option.code.not_blank</option>
<option name="groups">sylius</option>
</constraint>
</property>
<property name="name">
<constraint name="NotBlank">
<option name="message">sylius.option.name.not_blank</option>
@ -66,6 +77,17 @@
</class>
<class name="Sylius\Component\Variation\Model\OptionValue">
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">code</option>
<option name="message">sylius.option_value.code.unique</option>
<option name="groups">sylius</option>
</constraint>
<property name="code">
<constraint name="NotBlank">
<option name="message">sylius.option_value.code.not_blank</option>
<option name="groups">sylius</option>
</constraint>
</property>
<property name="value">
<constraint name="NotBlank">
<option name="message">sylius.option_value.value.not_blank</option>

View file

@ -1,5 +1,8 @@
sylius:
option:
code:
not_blank: Please enter option code.
unique: The option with given code already exists.
name:
not_blank: Please enter option name.
min_length: Option name must be at least 1 character long.|Option name must be at least {{ limit }} characters long.
@ -11,6 +14,9 @@ sylius:
values:
min_count: Please add at least {{ limit }} option value.|Please add at least {{ limit }} option values.
option_value:
code:
not_blank: Please enter option value code.
unique: The option value with given code already exists.
value:
not_blank: Please enter option value.
variant:

View file

@ -13,6 +13,7 @@ namespace spec\Sylius\Bundle\VariationBundle\Form\Type;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -42,16 +43,25 @@ class OptionTypeSpec extends ObjectBehavior
{
$builder
->add('name', 'text', Argument::any())
->shouldBeCalled()
->willReturn($builder)
;
$builder
->add('translations', 'a2lix_translationsForms', Argument::any())
->shouldBeCalled()
->willReturn($builder)
;
$builder
->add('values', 'collection', Argument::any())
->shouldBeCalled()
->willReturn($builder)
;
$builder
->addEventSubscriber(Argument::type(AddCodeFormSubscriber::class))
->shouldBeCalled()
->willReturn($builder)
;

View file

@ -13,6 +13,7 @@ namespace spec\Sylius\Bundle\VariationBundle\Form\Type;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -41,6 +42,13 @@ class OptionValueTypeSpec extends ObjectBehavior
{
$builder
->add('value', 'text', Argument::any())
->shouldBeCalled()
->willReturn($builder)
;
$builder
->addEventSubscriber(Argument::type(AddCodeFormSubscriber::class))
->shouldBeCalled()
->willReturn($builder)
;

View file

@ -514,12 +514,22 @@ class WebContext extends BaseWebContext implements SnippetAcceptingContext
*/
public function iAddFollowingOptionValues(TableNode $table)
{
foreach ($table->getRows() as $i => $value) {
foreach ($table->getRows() as $value) {
$newItem = $this->addNewItemToFormCollection($this->getSession()->getPage(), 'option_values');
$newItem->fillField('Value', $value[0]);
$newItem->fillField('Value', $value[1]);
$newItem->fillField('Code', $value[0]);
}
}
/**
* @When /^I add option value "([^""]*)"$/
*/
public function iAddOptionValue($optionValue)
{
$newItem = $this->addNewItemToFormCollection($this->getSession()->getPage(), 'option_values');
$newItem->fillField('Value', $optionValue);
}
/**
* @Given /^I add choice "([^""]*)"$/
*/

View file

@ -4,6 +4,7 @@
<div class="row">
<div class="col-md-8 row-split">
{{ form_row(form.code) }}
{{ form_row(form.name) }}
{{ form_row(form.translations) }}
</div>

View file

@ -8,6 +8,7 @@
<thead>
<tr>
<th>{{ sylius_resource_sort('id', '#id') }}</th>
<th>{{ sylius_resource_sort('code', 'sylius.ui.code'|trans) }}</th>
<th>{{ sylius_resource_sort('name', 'sylius.product_option.name'|trans) }}</th>
{#TODO allow sort by translation field#}
{#<th>{{ sylius_resource_sort('presentation', 'sylius.product_option.presentation'|trans) }}</th>#}
@ -21,6 +22,7 @@
{% for option in options %}
<tr id="{{ option.id }}">
<td>{{ option.id }}</td>
<td>{{ option.code }}</td>
<td>{{ option.name }}</td>
<td>{{ option.presentation }}</td>
<td>

View file

@ -26,6 +26,11 @@ class Option extends AbstractTranslatable implements OptionInterface
*/
protected $id;
/**
* @var string
*/
protected $code;
/**
* Internal name.
*
@ -78,6 +83,22 @@ class Option extends AbstractTranslatable implements OptionInterface
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getCode()
{
return $this->code;
}
/**
* {@inheritdoc}
*/
public function setCode($code)
{
$this->code = $code;
}
/**
* {@inheritdoc}
*/

View file

@ -12,6 +12,7 @@
namespace Sylius\Component\Variation\Model;
use Doctrine\Common\Collections\Collection;
use Sylius\Component\Resource\Model\CodeAwareInterface;
use Sylius\Component\Resource\Model\TimestampableInterface;
/**
@ -20,7 +21,7 @@ use Sylius\Component\Resource\Model\TimestampableInterface;
*
* @author Paweł Jędrzejewski <pawel@sylius.org>
*/
interface OptionInterface extends TimestampableInterface, OptionTranslationInterface
interface OptionInterface extends CodeAwareInterface, TimestampableInterface, OptionTranslationInterface
{
/**
* Get internal name.

View file

@ -21,6 +21,11 @@ class OptionValue implements OptionValueInterface
*/
protected $id;
/**
* @var string
*/
protected $code;
/**
* @var string
*/
@ -47,6 +52,22 @@ class OptionValue implements OptionValueInterface
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getCode()
{
return $this->code;
}
/**
* {@inheritdoc}
*/
public function setCode($code)
{
$this->code = $code;
}
/**
* {@inheritdoc}
*/

View file

@ -11,23 +11,20 @@
namespace Sylius\Component\Variation\Model;
use Sylius\Component\Resource\Model\CodeAwareInterface;
use Sylius\Component\Resource\Model\ResourceInterface;
/**
* @author Paweł Jędrzejewski <pawel@sylius.org>
*/
interface OptionValueInterface extends ResourceInterface
interface OptionValueInterface extends ResourceInterface, CodeAwareInterface
{
/**
* Get option.
*
* @return OptionInterface
*/
public function getOption();
/**
* Set option.
*
* @param OptionInterface $option
*/
public function setOption(OptionInterface $option = null);

View file

@ -42,6 +42,12 @@ class OptionSpec extends ObjectBehavior
$this->getId()->shouldReturn(null);
}
function it_has_mutable_code()
{
$this->setCode('O1');
$this->getCode()->shouldReturn('O1');
}
function it_should_not_have_name_by_default()
{
$this->getName()->shouldReturn(null);

View file

@ -35,6 +35,12 @@ class OptionValueSpec extends ObjectBehavior
$this->getId()->shouldReturn(null);
}
function it_has_mutable_code()
{
$this->setCode('OV1');
$this->getCode()->shouldReturn('OV1');
}
function it_should_not_belong_to_an_option_by_default()
{
$this->getOption()->shouldReturn(null);