[Core] Images refactor

The `code` field name has been changed to `type`, and is no longer
unique; in addition it became editable upon editing by UI.
Product/Taxon `getImageByCode` has been refactored to `getImagesByType`,
now returning a collection, instead of a single image.
This commit is contained in:
Jan Goralski 2017-02-02 09:46:45 +01:00
parent da5ca643db
commit 6d3c706615
No known key found for this signature in database
GPG key ID: 48749B194497003F
64 changed files with 592 additions and 889 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 Version20170201094058 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('DROP INDEX product_image_code_idx ON sylius_product_image');
$this->addSql('DROP INDEX taxon_image_code_idx ON sylius_taxon_image');
$this->addSql('ALTER TABLE sylius_product_image CHANGE code `type` VARCHAR(255)');
$this->addSql('ALTER TABLE sylius_taxon_image CHANGE code `type` VARCHAR(255)');
}
/**
* @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_image CHANGE `type` code VARCHAR(255) NOT NULL');
$this->addSql('ALTER TABLE sylius_taxon_image CHANGE `type` code VARCHAR(255) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX product_image_code_idx ON sylius_product_image (owner_id, code)');
$this->addSql('CREATE UNIQUE INDEX taxon_image_code_idx ON sylius_taxon_image (owner_id, code)');
}
}

View file

@ -8,30 +8,68 @@ Feature: Adding images to an existing product
Given I am logged in as an administrator
@ui @javascript
Scenario: Adding a single image to an existing simple product
Scenario: Adding a single image to an existing product
Given the store has a product "Lamborghini Gallardo Model"
And I want to modify this product
When I attach the "lamborghini.jpg" image with a code "banner"
When I attach the "lamborghini.jpg" image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And the product "Lamborghini Gallardo Model" should have an image with a code "banner"
And the product "Lamborghini Gallardo Model" should have an image with "banner" type
@ui @javascript
Scenario: Adding multiple images to an existing taxon
Scenario: Adding multiple images to an existing product
Given the store has a product "Lamborghini Gallardo Model"
And I want to modify this product
When I attach the "lamborghini.jpg" image with a code "banner"
And I attach the "lamborghini.jpg" image with a code "thumbnail"
When I attach the "lamborghini.jpg" image with "banner" type
And I attach the "lamborghini.jpg" image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And the product "Lamborghini Gallardo Model" should have an image with a code "banner"
And this product should have also an image with a code "thumbnail"
And the product "Lamborghini Gallardo Model" should have an image with "banner" type
And it should also have an image with "thumbnail" type
@ui @javascript
Scenario: Adding multiple images of the same type to an existing product
Given the store has a product "Lamborghini Ford Model"
And I want to modify this product
When I attach the "lamborghini.jpg" image with "banner" type
And I attach the "ford.jpg" image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have 2 images
@ui @javascript
Scenario: Adding a single image to an existing configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
And I want to modify this product
When I attach the "lamborghini.jpg" image with a code "banner"
When I attach the "lamborghini.jpg" image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And the product "Lamborghini Gallardo Model" should have an image with a code "banner"
And the product "Lamborghini Gallardo Model" should have an image with "banner" type
@ui @javascript
Scenario: Adding multiple images of the same type to an existing configurable product
Given the store has a "Lamborghini Ford Model" configurable product
And I want to modify this product
When I attach the "lamborghini.jpg" image with "banner" type
And I attach the "ford.jpg" image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have 2 images
@ui @javascript
Scenario: Adding an image to an existing product without providing its type
Given the store has a product "Lamborghini Gallardo Model"
And I want to modify this product
When I attach the "lamborghini.jpg" image
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have only one image
@ui @javascript
Scenario: Adding an image to an existing configurable product without providing its type
Given the store has a "Lamborghini Gallardo Model" configurable product
And I want to modify this product
When I attach the "lamborghini.jpg" image
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have only one image

View file

@ -14,10 +14,10 @@ Feature: Adding a new product with images
When I specify its code as "LAMBORGHINI_GALLARDO"
And I name it "Lamborghini Gallardo Model" in "English (United States)"
And I set its price to "$100.00" for "United States" channel
And I attach the "lamborghini.jpg" image with a code "banner"
And I attach the "lamborghini.jpg" image with "banner" type
And I add it
Then I should be notified that it has been successfully created
And the product "Lamborghini Gallardo Model" should have an image with a code "banner"
And the product "Lamborghini Gallardo Model" should have an image with "banner" type
@ui @javascript
Scenario: Adding a new simple product with multiple images
@ -25,12 +25,12 @@ Feature: Adding a new product with images
When I specify its code as "LAMBORGHINI_GALLARDO"
And I name it "Lamborghini Gallardo Model" in "English (United States)"
And I set its price to "$100.00" for "United States" channel
And I attach the "lamborghini.jpg" image with a code "banner"
And I attach the "lamborghini.jpg" image with a code "thumbnail"
And I attach the "lamborghini.jpg" image with "banner" type
And I attach the "lamborghini.jpg" image with "thumbnail" type
And I add it
Then I should be notified that it has been successfully created
And the product "Lamborghini Gallardo Model" should have an image with a code "banner"
And this product should have an image with a code "thumbnail"
And the product "Lamborghini Gallardo Model" should have an image with "banner" type
And it should also have an image with "thumbnail" type
@ui @javascript
Scenario: Adding a new configurable product with a single image
@ -41,7 +41,7 @@ Feature: Adding a new product with images
When I specify its code as "LAMBORGHINI_GALLARDO"
And I name it "Lamborghini Gallardo Model" in "English (United States)"
And I add the "Model scale" option to it
And I attach the "lamborghini.jpg" image with a code "banner"
And I attach the "lamborghini.jpg" image with "banner" type
And I add it
Then I should be notified that it has been successfully created
And the product "Lamborghini Gallardo Model" should have an image with a code "banner"
And the product "Lamborghini Gallardo Model" should have an image with "banner" type

View file

@ -2,7 +2,7 @@
Feature: Changing images of an existing product
In order to change images of my product
As an Administrator
I want to be able to changing images of an existing product
I want to be able to change images of an existing product
Background:
Given I am logged in as an administrator
@ -10,33 +10,43 @@ Feature: Changing images of an existing product
@ui @javascript
Scenario: Changing a single image of a simple product
Given the store has a product "Lamborghini Gallardo Model"
And this product has an image "ford.jpg" with a code "thumbnail"
And this product has an image "ford.jpg" with "thumbnail" type
When I want to modify this product
And I change the image with the "thumbnail" code to "lamborghini.jpg"
And I change the image with the "thumbnail" type to "lamborghini.jpg"
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "thumbnail"
And this product should have an image with "thumbnail" type
@ui @javascript
Scenario: Changing a single image of a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
And this product has an image "ford.jpg" with a code "thumbnail"
And this product has an image "ford.jpg" with "thumbnail" type
When I want to modify this product
And I change the image with the "thumbnail" code to "lamborghini.jpg"
And I change the image with the "thumbnail" type to "lamborghini.jpg"
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "thumbnail"
And this product should have an image with "thumbnail" type
@ui
Scenario: Unable to change an image's code of a simple product
Given the store has a product "Lamborghini Gallardo Model"
And this product has an image "lamborghini.jpg" with a code "thumbnail"
@ui @javascript
Scenario: Changing the type of image of a simple product
Given the store has a product "Lamborghini Ford Model"
And this product has an image "lamborghini.jpg" with "thumbnail" type
And this product has an image "ford.jpg" with "banner" type
When I want to modify this product
Then the image code field should be disabled
And I change the first image type to "banner"
And I save my changes
Then I should be notified that it has been successfully edited
And this product should still have 2 images
But it should not have any images with "thumbnail" type
@ui
Scenario: Unable to change an image's code of a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
And this product has an image "lamborghini.jpg" with a code "thumbnail"
@ui @javascript
Scenario: Changing the type of image of a configurable product
Given the store has a "Lamborghini Ford Model" configurable product
And this product has an image "lamborghini.jpg" with "thumbnail" type
And this product has an image "ford.jpg" with "banner" type
When I want to modify this product
Then the image code field should be disabled
And I change the first image type to "banner"
And I save my changes
Then I should be notified that it has been successfully edited
And this product should still have 2 images
But it should not have any images with "thumbnail" type

View file

@ -25,4 +25,4 @@ Feature: Editing product's attributes
And I remove its "Gun caliber" attribute
And I try to add new attributes
And I save my changes
And product "44 Magnum" should not have any attributes
Then product "44 Magnum" should not have any attributes

View file

@ -1,26 +0,0 @@
@managing_products
Feature: Product image unique code validation within a product
In order to uniquely identify images within a product
As an Administrator
I want to be prevented from adding two images with the same code to the same product
Background:
Given the store has "Lamborghini Gallardo Model" and "Ford Capri Model" products
And the "Lamborghini Gallardo Model" product has an image "lamborghini.jpg" with a code "thumbnail"
And I am logged in as an administrator
@ui @javascript
Scenario: Adding images with the same code to different products
When I want to modify the "Ford Capri Model" product
And I attach the "ford.jpg" image with a code "thumbnail"
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "thumbnail"
@ui @javascript
Scenario: Trying to add an image with a code that is already used by other image of this product
When I want to modify the "Lamborghini Gallardo Model" product
And I attach the "ford.jpg" image with a code "thumbnail"
And I try to save my changes
Then I should be notified that the image with this code already exists
And there should still be only one image in the "Lamborghini Gallardo Model" product

View file

@ -1,36 +0,0 @@
@managing_products
Feature: Product's images unique code validation within a product
In order to uniquely identify images within a product
As an Administrator
I want to be prevented from adding two images with the same code to the same product
Background:
Given I am logged in as an administrator
And the store has a product "Toy lamborghini"
And this product has an image "lamborghini.jpg" with a code "lamborghini"
And the store has a product "Car T-shirt"
@ui @javascript
Scenario: Adding images with the same code to different product
When I want to modify the "Car T-shirt" product
And I attach the "t-shirts.jpg" image with a code "lamborghini"
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "lamborghini"
@ui @javascript
Scenario: Trying to add an image with a code that is already used by other image of this product
When I want to modify the "Toy lamborghini" product
And I attach the "t-shirts.jpg" image with a code "lamborghini"
And I try to save my changes
Then I should be notified that the image with this code already exists
And there should still be only one image in the "Toy lamborghini" product
@ui @javascript
Scenario: Trying to add images with the same code
When I want to modify the "Car T-shirt" product
And I attach the "t-shirts.jpg" image with a code "lamborghini"
And I attach the "lamborghini.jpg" image with a code "lamborghini"
And I try to save my changes
Then I should be notified that the 1st image should have an unique code
And I should be notified that the 2nd image should have an unique code

View file

@ -1,26 +0,0 @@
@managing_products
Feature: Product image validation
In order to avoid making mistakes when managing a product images
As an Administrator
I want to be prevented from adding it without specifying required fields
Background:
Given I am logged in as an administrator
@ui @javascript
Scenario: Trying to add a new image without specifying its code to a simple product
Given the store has a product "Lamborghini Gallardo Model"
When I want to modify the "Lamborghini Gallardo Model" product
And I attach the "lamborghini.jpg" image without a code
And I try to save my changes
Then I should be notified that an image code is required
And this product should not have any images
@ui @javascript
Scenario: Trying to add a new image without specifying its code to a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
When I want to modify the "Lamborghini Gallardo Model" product
And I attach the "lamborghini.jpg" image without a code
And I try to save my changes
Then I should be notified that an image code is required
And this product should not have any images

View file

@ -114,8 +114,7 @@ Feature: Products validation
And I want to modify this product
When I remove its name from "English (United States)" translation
And I try to save my changes
Then I should not be notified that simple product code has to be unique
And this product should still be named "Dice Brewing"
Then this product should still be named "Dice Brewing"
@ui
Scenario: Trying to assign new channel to an existing configurable product without specifying its all variant prices for this channel

View file

@ -10,9 +10,9 @@ Feature: Removing images of an existing product
@ui @javascript
Scenario: Removing a single image of a simple product
Given the store has a product "Lamborghini Gallardo Model"
And this product has an image "lamborghini.jpg" with a code "thumbnail"
And this product has an image "lamborghini.jpg" with "thumbnail" type
When I want to modify this product
And I remove an image with a code "thumbnail"
And I remove an image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should not have any images
@ -20,9 +20,9 @@ Feature: Removing images of an existing product
@ui @javascript
Scenario: Removing a single image of a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
And this product has an image "lamborghini.jpg" with a code "thumbnail"
And this product has an image "lamborghini.jpg" with "thumbnail" type
When I want to modify this product
And I remove an image with a code "thumbnail"
And I remove an image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should not have any images
@ -30,11 +30,11 @@ Feature: Removing images of an existing product
@ui @javascript
Scenario: Removing all images of a simple product
Given the store has a product "Lamborghini Gallardo Model"
And this product has an image "lamborghini.jpg" with a code "thumbnail"
And this product has also an image "lamborghini.jpg" with a code "main"
And this product has an image "lamborghini.jpg" with "thumbnail" type
And it also has an image "lamborghini.jpg" with "main" type
When I want to modify this product
And I remove an image with a code "thumbnail"
And I remove also an image with a code "main"
And I remove an image with "thumbnail" type
And I also remove an image with "main" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should not have any images
@ -42,11 +42,11 @@ Feature: Removing images of an existing product
@ui @javascript
Scenario: Removing all images of a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
And this product has an image "lamborghini.jpg" with a code "thumbnail"
And this product has also an image "lamborghini.jpg" with a code "main"
And this product has an image "lamborghini.jpg" with "thumbnail" type
And it also has an image "lamborghini.jpg" with "main" type
When I want to modify this product
And I remove an image with a code "thumbnail"
And I remove also an image with a code "main"
And I remove an image with "thumbnail" type
And I also remove an image with "main" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should not have any images
@ -54,47 +54,59 @@ Feature: Removing images of an existing product
@ui @javascript
Scenario: Removing only one image of a simple product
Given the store has a product "Lamborghini Gallardo Model"
And this product has an image "lamborghini.jpg" with a code "thumbnail"
And this product has also an image "lamborghini.jpg" with a code "main"
And this product has an image "lamborghini.jpg" with "thumbnail" type
And it also has an image "lamborghini.jpg" with "main" type
When I want to modify this product
And I remove an image with a code "thumbnail"
And I remove an image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "main"
But this product should not have an image with a code "thumbnail"
And this product should have an image with "main" type
But it should not have any images with "thumbnail" type
@ui @javascript
Scenario: Removing only one image of a simple product when all images have same type
Given the store has a product "Lamborghini Ford Model"
And this product has an image "lamborghini.jpg" with "thumbnail" type
And it also has an image "ford.jpg" with "thumbnail" type
When I want to modify this product
And I remove the first image
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have only one image
@ui @javascript
Scenario: Removing only one image of a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
And this product has an image "lamborghini.jpg" with a code "thumbnail"
And this product has also an image "lamborghini.jpg" with a code "main"
And this product has an image "lamborghini.jpg" with "thumbnail" type
And it also has an image "lamborghini.jpg" with "main" type
When I want to modify this product
And I remove an image with a code "thumbnail"
And I remove an image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "main"
But this product should not have an image with a code "thumbnail"
And this product should have an image with "main" type
But it should not have any images with "thumbnail" type
@ui @javascript
Scenario: Adding multiple images and removing a single image of a simple product
Given the store has a product "Lamborghini Gallardo Model"
When I want to modify this product
And I attach the "lamborghini.jpg" image with a code "thumbnail"
And I attach the "lamborghini.jpg" image with a code "main"
And I attach the "lamborghini.jpg" image with "thumbnail" type
And I attach the "lamborghini.jpg" image with "main" type
And I remove the first image
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "main"
But this product should not have an image with a code "thumbnail"
And this product should have only one image
And this product should have an image with "main" type
But it should not have any images with "thumbnail" type
@ui @javascript
Scenario: Adding multiple images and removing a single image of a configurable product
Given the store has a "Lamborghini Gallardo Model" configurable product
When I want to modify this product
And I attach the "lamborghini.jpg" image with a code "thumbnail"
And I attach the "lamborghini.jpg" image with a code "main"
And I attach the "lamborghini.jpg" image with "thumbnail" type
And I attach the "lamborghini.jpg" image with "main" type
And I remove the first image
And I save my changes
Then I should be notified that it has been successfully edited
And this product should have an image with a code "main"
But this product should not have an image with a code "thumbnail"
And this product should have an image with "main" type
But it should not have any images with "thumbnail" type

View file

@ -7,7 +7,7 @@ Feature: Viewing a product's image on a product details page
Background:
Given the store operates on a single channel in "United States"
And the store has a product "Lamborghini Gallardo Model"
And this product has an image "lamborghini.jpg" with a code "main"
And this product has an image "lamborghini.jpg" with "main" type
@ui @javascript
Scenario: Viewing a product's image on a product details page

View file

@ -12,17 +12,34 @@ Feature: Adding images to an existing taxon
@ui @javascript
Scenario: Adding a single image to an existing taxon
Given I want to modify the "T-Shirts" taxon
When I attach the "t-shirts.jpg" image with a code "banner"
When I attach the "t-shirts.jpg" image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have an image with a code "banner"
And this taxon should have an image with "banner" type
@ui @javascript
Scenario: Adding a single image to an existing taxon without specifying the type
Given I want to modify the "T-Shirts" taxon
When I attach the "t-shirts.jpg" image
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have only one image
@ui @javascript
Scenario: Adding multiple images to an existing taxon
Given I want to modify the "T-Shirts" taxon
When I attach the "t-shirts.jpg" image with a code "banner"
And I attach the "t-shirts.jpg" image with a code "thumbnail"
When I attach the "t-shirts.jpg" image with "banner" type
And I attach the "t-shirts.jpg" image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have an image with a code "banner"
And this taxon should have also an image with a code "thumbnail"
And this taxon should have an image with "banner" type
And it should also have an image with "thumbnail" type
@ui @javascript
Scenario: Adding multiple images of the same type to an existing taxon
Given I want to modify the "T-Shirts" taxon
When I attach the "t-shirts.jpg" image with "banner" type
And I attach the "t-shirts.jpg" image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have 2 images

View file

@ -13,21 +13,21 @@ Feature: Adding a new taxon with images
Given I want to create a new taxon
When I specify its code as "t-shirts"
And I name it "T-Shirts" in "English (United States)"
And I attach the "t-shirts.jpg" image with a code "banner"
And I attach the "t-shirts.jpg" image with "banner" type
And I add it
Then I should be notified that it has been successfully created
And the "T-Shirts" taxon should appear in the registry
And this taxon should have an image with a code "banner"
And this taxon should have an image with "banner" type
@ui @javascript
Scenario: Adding a new taxon with multiple images
Given I want to create a new taxon
When I specify its code as "t-shirts"
And I name it "T-Shirts" in "English (United States)"
And I attach the "t-shirts.jpg" image with a code "banner"
And I attach the "t-shirts.jpg" image with a code "thumbnail"
And I attach the "t-shirts.jpg" image with "banner" type
And I attach the "t-shirts.jpg" image with "thumbnail" type
And I add it
Then I should be notified that it has been successfully created
And the "T-Shirts" taxon should appear in the registry
And this taxon should have an image with a code "banner"
And this taxon should have also an image with a code "thumbnail"
And this taxon should have an image with "banner" type
And it should also have an image with "thumbnail" type

View file

@ -7,18 +7,24 @@ Feature: Changing images of an existing taxon
Background:
Given the store is available in "English (United States)"
And the store classifies its products as "T-Shirts"
And the "T-Shirts" taxon has an image "mugs.jpg" with a code "banner"
And I am logged in as an administrator
@ui @javascript
Scenario: Changing a single image of a taxon
Given I want to modify the "T-Shirts" taxon
When I change the image with the "banner" code to "t-shirts.jpg"
Given the "T-Shirts" taxon has an image "ford.jpg" with "banner" type
And I want to modify the "T-Shirts" taxon
When I change the image with the "banner" type to "t-shirts.jpg"
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have an image with a code "banner"
And this taxon should have an image with "banner" type
@ui
Scenario: Unable to change a code of an image
When I want to modify the "T-Shirts" taxon
Then the image code field should be disabled
@ui @javascript
Scenario: Changing the type of image of a taxon
Given the "T-Shirts" taxon has an image "ford.jpg" with "thumbnail" type
And the "T-Shirts" taxon also has an image "t-shirts.jpg" with "banner" type
And I want to modify the "T-Shirts" taxon
When I change the first image type to "banner"
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should still have 2 images
But it should not have any images with "thumbnail" type

View file

@ -11,42 +11,52 @@ Feature: Removing images of an existing taxon
@ui @javascript
Scenario: Removing a single image of a taxon
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with a code "banner"
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with "banner" type
And I want to modify the "T-Shirts" taxon
When I remove an image with a code "banner"
When I remove an image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should not have any images
@ui @javascript
Scenario: Removing all images of a taxon
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with a code "banner"
And the "T-Shirts" taxon has also an image "t-shirts.jpg" with a code "thumbnail"
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with "banner" type
And the "T-Shirts" taxon also has an image "t-shirts.jpg" with "thumbnail" type
And I want to modify the "T-Shirts" taxon
When I remove an image with a code "banner"
When I remove also an image with a code "thumbnail"
When I remove an image with "banner" type
When I also remove an image with "thumbnail" type
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should not have any images
@ui @javascript
Scenario: Removing only one image of a taxon
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with a code "banner"
And the "T-Shirts" taxon has also an image "t-shirts.jpg" with a code "thumbnail"
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with "banner" type
And the "T-Shirts" taxon also has an image "t-shirts.jpg" with "thumbnail" type
And I want to modify the "T-Shirts" taxon
When I remove an image with a code "banner"
When I remove an image with "banner" type
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have an image with a code "thumbnail"
But this taxon should not have an image with a code "banner"
And this taxon should have an image with "thumbnail" type
But this taxon should not have any images with "banner" type
@ui @javascript
Scenario: Removing only one image of a simple product when all images have same type
Given the "T-Shirts" taxon has an image "t-shirts.jpg" with "banner" type
And the "T-Shirts" taxon also has an image "mugs.jpg" with "banner" type
And I want to modify the "T-Shirts" taxon
When I remove the first image
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have only one image
@ui @javascript
Scenario: Adding multiple images and removing a single image of a taxon
Given I want to modify the "T-Shirts" taxon
When I attach the "t-shirts.jpg" image with a code "banner"
And I attach the "t-shirts.jpg" image with a code "thumbnail"
When I attach the "t-shirts.jpg" image with "banner" type
And I attach the "t-shirts.jpg" image with "thumbnail" type
And I remove the first image
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have an image with a code "thumbnail"
But this taxon should not have an image with a code "banner"
And this taxon should have an image with "thumbnail" type
But this taxon should not have any images with "banner" type

View file

@ -1,36 +0,0 @@
@managing_taxons
Feature: Taxon image unique code validation within a taxon
In order to uniquely identify images within a taxon
As an Administrator
I want to be prevented from adding two images with the same code to the same taxon
Background:
Given the store is available in "English (United States)"
And the store classifies its products as "T-Shirts" and "Mugs"
And the "T-Shirts" taxon has an image "t-shirts.jpg" with a code "banner"
And I am logged in as an administrator
@ui @javascript
Scenario: Adding images with the same code to different taxons
When I want to modify the "Mugs" taxon
And I attach the "mugs.jpg" image with a code "banner"
And I save my changes
Then I should be notified that it has been successfully edited
And this taxon should have an image with a code "banner"
@ui @javascript
Scenario: Trying to add an image with a code that is already used by other image of this taxon
When I want to modify the "T-Shirts" taxon
And I attach the "mugs.jpg" image with a code "banner"
And I try to save my changes
Then I should be notified that the image with this code already exists
And there should still be only one image in the "T-Shirts" taxon
@ui @javascript
Scenario: Trying to add images with the same code
When I want to modify the "Mugs" taxon
And I attach the "t-shirts.jpg" image with a code "banner"
And I attach the "mugs.jpg" image with a code "banner"
And I try to save my changes
Then I should be notified that the 1st image should have an unique code
And I should be notified that the 2nd image should have an unique code

View file

@ -1,17 +0,0 @@
@managing_taxons
Feature: Taxon image validation
In order to avoid making mistakes when managing a taxon images
As an Administrator
I want to be prevented from adding it without specifying required fields
Background:
Given the store classifies its products as "T-Shirts"
And I am logged in as an administrator
@ui @javascript
Scenario: Trying to add a new image without specifying its code to an existing taxon
When I want to modify the "T-Shirts" taxon
And I attach the "t-shirts.jpg" image without a code
And I try to save my changes
Then I should be notified that an image code is required
And this taxon should not have any images

View file

@ -1,8 +1,8 @@
@managing_taxons
Feature: Taxon validation
In order to avoid making mistakes when managing a taxons
In order to avoid making mistakes when managing taxons
As an Administrator
I want to be prevented from adding it without specifying required fields
I want to be prevented from adding any without specifying required fields
Background:
Given the store is available in "English (United States)"
@ -15,7 +15,7 @@ Feature: Taxon validation
And I name it "T-Shirts" in "English (United States)"
And I try to add it
Then I should be notified that code is required
And Taxon named "T-Shirts" should not be added
And taxon named "T-Shirts" should not be added
@ui
Scenario: Trying to add a taxon without specifying its name

View file

@ -631,17 +631,18 @@ final class ProductContext implements Context
}
/**
* @Given /^(this product) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
* @Given /^the ("[^"]+" product) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
* @Given /^(this product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
* @Given /^the ("[^"]+" product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
* @Given /^(it)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
*/
public function thisProductHasAnImageWithACode(ProductInterface $product, $imagePath, $imageCode)
public function thisProductHasAnImageWithType(ProductInterface $product, $imagePath, $imageType)
{
$filesPath = $this->getParameter('files_path');
/** @var ImageInterface $productImage */
$productImage = $this->productImageFactory->createNew();
$productImage->setFile(new UploadedFile($filesPath.$imagePath, basename($imagePath)));
$productImage->setCode($imageCode);
$productImage->setType($imageType);
$this->imageUploader->upload($productImage);
$product->addImage($productImage);

View file

@ -15,12 +15,14 @@ use Behat\Behat\Context\Context;
use Behat\Mink\Element\NodeElement;
use Doctrine\Common\Persistence\ObjectManager;
use Sylius\Component\Core\Formatter\StringInflector;
use Sylius\Component\Core\Model\ImageInterface;
use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Model\TranslationInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Taxonomy\Generator\TaxonSlugGeneratorInterface;
use Sylius\Component\Taxonomy\Model\TaxonTranslationInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
@ -126,15 +128,16 @@ final class TaxonomyContext implements Context
}
/**
* @Given /^the ("[^"]+" taxon) has(?:| also) an image "([^"]+)" with a code "([^"]+)"$/
* @Given /^the ("[^"]+" taxon)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/
*/
public function theTaxonHasAnImageWithACode(TaxonInterface $taxon, $imagePath, $imageCode)
public function theTaxonHasAnImageWithType(TaxonInterface $taxon, $imagePath, $imageType)
{
$filesPath = $this->getParameter('files_path');
/** @var ImageInterface $taxonImage */
$taxonImage = $this->taxonImageFactory->createNew();
$taxonImage->setFile(new UploadedFile($filesPath.$imagePath, basename($imagePath)));
$taxonImage->setCode($imageCode);
$taxonImage->setType($imageType);
$this->imageUploader->upload($taxonImage);
$taxon->addImage($taxonImage);
@ -169,7 +172,7 @@ final class TaxonomyContext implements Context
$taxon = $this->taxonFactory->createNew();
$taxon->setCode(StringInflector::nameToCode($names['en_US']));
foreach ($names as $locale => $name) {
/** @var TranslationInterface $taxonTranslation */
/** @var TranslationInterface|TaxonTranslationInterface $taxonTranslation */
$taxonTranslation = $this->taxonTranslationFactory->createNew();
$taxonTranslation->setLocale($locale);
$taxonTranslation->setName($name);

View file

@ -23,6 +23,7 @@ use Sylius\Behat\Page\Admin\Product\IndexPerTaxonPageInterface;
use Sylius\Behat\Page\Admin\Product\UpdateConfigurableProductPageInterface;
use Sylius\Behat\Page\Admin\Product\UpdateSimpleProductPageInterface;
use Sylius\Behat\Page\Admin\ProductReview\IndexPageInterface as ProductReviewIndexPageInterface;
use Sylius\Behat\Page\SymfonyPageInterface;
use Sylius\Behat\Service\NotificationCheckerInterface;
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
use Sylius\Behat\Service\SharedStorageInterface;
@ -432,7 +433,6 @@ final class ManagingProductsContext implements Context
*/
public function iSaveMyChanges()
{
/** @var UpdatePageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->saveChanges();
@ -502,10 +502,10 @@ final class ManagingProductsContext implements Context
}
/**
* @Then product :product should not have any attributes
* @Then product :product should have :count attribute
* @Then /^product "[^"]+" should not have any attributes$/
* @Then /^product "[^"]+" should have (\d+) attributes?$/
*/
public function productShouldNotHaveAnyAttributes(ProductInterface $product, $count = 0)
public function productShouldNotHaveAnyAttributes($count = 0)
{
Assert::same($this->updateSimpleProductPage->getNumberOfAttributes(), (int) $count);
}
@ -599,25 +599,14 @@ final class ManagingProductsContext implements Context
}
/**
* @When I attach the :path image with a code :code
* @When I attach the :path image with :type type
* @When I attach the :path image
*/
public function iAttachImageWithACode($path, $code)
public function iAttachImageWithType($path, $type = null)
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->attachImage($path, $code);
}
/**
* @When I attach the :path image without a code
*/
public function iAttachImageWithoutACode($path)
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->attachImage($path);
$currentPage->attachImage($path, $type);
}
/**
@ -628,7 +617,6 @@ final class ManagingProductsContext implements Context
ProductAssociationTypeInterface $productAssociationType,
...$productsNames
) {
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->associateProducts($productAssociationType, $productsNames);
@ -641,57 +629,49 @@ final class ManagingProductsContext implements Context
$productName,
ProductAssociationTypeInterface $productAssociationType
) {
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->removeAssociatedProduct($productName, $productAssociationType);
}
/**
* @Then /^(this product) should have(?:| also) an image with a code "([^"]*)"$/
* @Then /^the (product "[^"]+") should have(?:| also) an image with a code "([^"]*)"$/
* @Then /^(?:this product|the product "[^"]+"|it) should(?:| also) have an image with "([^"]*)" type$/
*/
public function thisProductShouldHaveAnImageWithCode(ProductInterface $product, $code)
public function thisProductShouldHaveAnImageWithType($type)
{
$this->sharedStorage->set('product', $product);
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
Assert::true($currentPage->isImageWithCodeDisplayed($code));
Assert::true($currentPage->isImageWithTypeDisplayed($type));
}
/**
* @Then /^this product should not have(?:| also) an image with a code "([^"]*)"$/
* @Then /^(?:this product|it)(?:| also) should not have any images with "([^"]*)" type$/
*/
public function thisProductShouldNotHaveAnImageWithCode($code)
public function thisProductShouldNotHaveAnyImagesWithType($code)
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
Assert::false($currentPage->isImageWithCodeDisplayed($code));
Assert::false($currentPage->isImageWithTypeDisplayed($code));
}
/**
* @When I change the image with the :code code to :path
* @When I change the image with the :type type to :path
*/
public function iChangeItsImageToPathForTheCode($path, $code)
public function iChangeItsImageToPathForTheType($type, $path)
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->changeImageWithCode($code, $path);
$currentPage->changeImageWithType($type, $path);
}
/**
* @When /^I remove(?:| also) an image with a code "([^"]*)"$/
* @When /^I(?:| also) remove an image with "([^"]*)" type$/
*/
public function iRemoveAnImageWithACode($code)
public function iRemoveAnImageWithType($code)
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->removeImageWithCode($code);
$currentPage->removeImageWithType($code);
}
/**
@ -699,12 +679,21 @@ final class ManagingProductsContext implements Context
*/
public function iRemoveTheFirstImage()
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
$currentPage->removeFirstImage();
}
/**
* @When I change the first image type to :type
*/
public function iChangeTheFirstImageTypeTo($type)
{
$currentPage = $this->resolveCurrentPage();
$currentPage->modifyFirstImageType($type);
}
/**
* @Then /^(this product) should not have any images$/
*/
@ -718,45 +707,15 @@ final class ManagingProductsContext implements Context
}
/**
* @Then the image code field should be disabled
* @Then /^(this product) should(?:| still) have (?:only one|(\d+)) images?$/
*/
public function theImageCodeFieldShouldBeDisabled()
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
Assert::true($currentPage->isImageCodeDisabled());
}
/**
* @Then I should be notified that the image with this code already exists
*/
public function iShouldBeNotifiedThatTheImageWithThisCodeAlreadyExists()
{
Assert::same($this->updateSimpleProductPage->getValidationMessageForImage(), 'Image code must be unique within this product.');
}
/**
* @Then I should be notified that an image code is required
*/
public function iShouldBeNotifiedThatAnImageCodeIsRequired()
{
/** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
Assert::same($currentPage->getValidationMessageForImage(), 'Please enter an image code.');
}
/**
* @Then there should still be only one image in the :product product
*/
public function thereShouldStillBeOnlyOneImageInThisTaxon(ProductInterface $product)
public function thereShouldStillBeOnlyOneImageInThisProduct(ProductInterface $product, $count = 1)
{
$this->iWantToModifyAProduct($product);
$currentPage = $this->resolveCurrentPage();
Assert::same($currentPage->countImages(), 1);
Assert::same($currentPage->countImages(), (int) $count);
}
/**
@ -792,7 +751,7 @@ final class ManagingProductsContext implements Context
/**
* @Then this product should not have an association :productAssociationType with product :productName
*/
public function theProductShouldNotHaveAnAssociationWithProducts(
public function theProductShouldNotHaveAnAssociationWithProduct(
ProductAssociationTypeInterface $productAssociationType,
$productName
) {
@ -807,23 +766,6 @@ final class ManagingProductsContext implements Context
$this->assertValidationMessage('code', 'Simple product code must be unique among all products and product variants.');
}
/**
* @Then I should not be notified that simple product code has to be unique
*/
public function iShouldNotBeNotifiedThatSimpleProductCodeHasToBeUnique()
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->resolveCurrentPage();
try {
$validationMessge = $currentPage->getValidationMessage('code');
Assert::notSame($validationMessge, 'Simple product code must be unique among all products and product variants.');
} catch (ElementNotFoundException $e) {
// intentionally left blank, as it could not have any validation at all
}
}
/**
* @Then I should be notified that slug has to be unique
*/
@ -917,17 +859,6 @@ final class ManagingProductsContext implements Context
);
}
/**
* @Then I should be notified that the :imageNumber image should have an unique code
*/
public function iShouldBeNotifiedThatTheFirstImageShouldHaveAnUniqueCode($imageNumber)
{
Assert::same(
$this->updateSimpleProductPage->getValidationMessageForImageAtPosition((int) $imageNumber - 1),
'Image code must be unique within this product.'
);
}
/**
* @Then I should be notified that I have to define product variants' prices for newly assigned channels first
*/
@ -969,7 +900,7 @@ final class ManagingProductsContext implements Context
}
/**
* @return IndexPageInterface|IndexPerTaxonPageInterface|CreateSimpleProductPageInterface|CreateConfigurableProductPageInterface|UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface
* @return SymfonyPageInterface|IndexPageInterface|IndexPerTaxonPageInterface|CreateSimpleProductPageInterface|CreateConfigurableProductPageInterface|UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface
*/
private function resolveCurrentPage()
{

View file

@ -15,6 +15,7 @@ use Behat\Behat\Context\Context;
use Sylius\Behat\Page\Admin\Taxon\CreateForParentPageInterface;
use Sylius\Behat\Page\Admin\Taxon\CreatePageInterface;
use Sylius\Behat\Page\Admin\Taxon\UpdatePageInterface;
use Sylius\Behat\Page\SymfonyPageInterface;
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
use Sylius\Behat\Service\SharedStorageInterface;
use Sylius\Component\Core\Model\TaxonInterface;
@ -100,26 +101,23 @@ final class ManagingTaxonsContext implements Context
/**
* @When I specify its code as :code
* @When I do not specify its code
*/
public function iSpecifyItsCodeAs($code)
public function iSpecifyItsCodeAs($code = null)
{
$this->createPage->specifyCode($code);
}
/**
* @When I name it :name in :language
*/
public function iNameItIn($name, $language)
{
$this->createPage->nameIt($name, $language);
}
/**
* @When I rename it to :name in :language
* @When I do not specify its name
*/
public function iRenameItIn($name, $language)
public function iNameItIn($name = null, $language = 'en_US')
{
$this->updatePage->nameIt($name, $language);
$currentPage = $this->resolveCurrentPage();
$currentPage->nameIt($name, $language);
}
/**
@ -129,12 +127,7 @@ final class ManagingTaxonsContext implements Context
*/
public function iSetItsSlugToIn($slug = null, $language = 'en_US')
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->currentPageResolver->getCurrentPageWithForm([
$this->createPage,
$this->createForParentPage,
$this->updatePage,
]);
$currentPage = $this->resolveCurrentPage();
$currentPage->specifySlug($slug, $language);
}
@ -182,22 +175,6 @@ final class ManagingTaxonsContext implements Context
$this->updatePage->chooseParent($taxon);
}
/**
* @When I do not specify its code
*/
public function iDoNotSpecifyItsCode()
{
// Intentionally left blank to fulfill context expectation
}
/**
* @When I do not specify its name
*/
public function iDoNotSpecifyItsName()
{
// Intentionally left blank to fulfill context expectation
}
/**
* @When I delete taxon named :name
*/
@ -293,8 +270,7 @@ final class ManagingTaxonsContext implements Context
*/
public function iShouldBeNotifiedThatTaxonWithThisCodeAlreadyExists()
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
$currentPage = $this->resolveCurrentPage();
Assert::same($currentPage->getValidationMessage('code'), 'Taxon with given code already exists.');
}
@ -304,8 +280,7 @@ final class ManagingTaxonsContext implements Context
*/
public function iShouldBeNotifiedThatTaxonSlugMustBeUnique()
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
$currentPage = $this->resolveCurrentPage();
Assert::same($currentPage->getValidationMessage('slug'), 'Taxon slug must be unique.');
}
@ -315,14 +290,13 @@ final class ManagingTaxonsContext implements Context
*/
public function iShouldBeNotifiedThatIsRequired($element)
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
$currentPage = $this->resolveCurrentPage();
Assert::same($currentPage->getValidationMessage($element), sprintf('Please enter taxon %s.', $element));
}
/**
* @Then /^there should still be only one taxon with code "([^"]+)"$/
* @Then /^there should(?:| still) be only one taxon with code "([^"]+)"$/
*/
public function thereShouldStillBeOnlyOneTaxonWithCode($code)
{
@ -330,7 +304,7 @@ final class ManagingTaxonsContext implements Context
}
/**
* @Then /^Taxon named "([^"]+)" should not be added$/
* @Then /^taxon named "([^"]+)" should not be added$/
* @Then the taxon named :name should no longer exist in the registry
*/
public function taxonNamedShouldNotBeAdded($name)
@ -355,46 +329,38 @@ final class ManagingTaxonsContext implements Context
}
/**
* @When I attach the :path image with a code :code
* @When I attach the :path image with :type type
* @When I attach the :path image
*/
public function iAttachImageWithACode($path, $code)
public function iAttachImageWithType($path, $type = null)
{
/** @var CreatePageInterface|UpdatePageInterface $currentPage */
$currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
$currentPage = $this->resolveCurrentPage();
$currentPage->attachImage($path, $code);
$currentPage->attachImage($path, $type);
}
/**
* @When I attach the :path image without a code
* @Then /^(?:it|this taxon) should(?:| also) have an image with "([^"]*)" type$/
*/
public function iAttachImageWithoutACode($path)
public function thisTaxonShouldHaveAnImageWithType($type)
{
$this->updatePage->attachImage($path);
Assert::true($this->updatePage->isImageWithTypeDisplayed($type));
}
/**
* @Then /^this taxon should have(?:| also) an image with a code "([^"]*)"$/
* @Then /^(?:this taxon|it) should not have(?:| also) any images with "([^"]*)" type$/
*/
public function thisTaxonShouldHaveAnImageWithCode($code)
public function thisTaxonShouldNotHaveAnImageWithType($code)
{
Assert::true($this->updatePage->isImageWithCodeDisplayed($code));
Assert::false($this->updatePage->isImageWithTypeDisplayed($code));
}
/**
* @Then /^this taxon should not have(?:| also) an image with a code "([^"]*)"$/
* @When /^I(?:| also) remove an image with "([^"]*)" type$/
*/
public function thisTaxonShouldNotHaveAnImageWithCode($code)
public function iRemoveAnImageWithType($code)
{
Assert::false($this->updatePage->isImageWithCodeDisplayed($code));
}
/**
* @When /^I remove(?:| also) an image with a code "([^"]*)"$/
*/
public function iRemoveAnImageWithACode($code)
{
$this->updatePage->removeImageWithCode($code);
$this->updatePage->removeImageWithType($code);
}
/**
@ -408,7 +374,7 @@ final class ManagingTaxonsContext implements Context
/**
* @Then /^(this taxon) should not have any images$/
*/
public function thisTaxonShouldNotHaveImages(TaxonInterface $taxon)
public function thisTaxonShouldNotHaveAnyImages(TaxonInterface $taxon)
{
$this->iWantToModifyATaxon($taxon);
@ -416,60 +382,41 @@ final class ManagingTaxonsContext implements Context
}
/**
* @When I change the image with the :code code to :path
* @When I change the image with the :type type to :path
*/
public function iChangeItsImageToPathForTheCode($path, $code)
public function iChangeItsImageToPathForTheType($path, $type)
{
$this->updatePage->changeImageWithCode($code, $path);
$this->updatePage->changeImageWithType($type, $path);
}
/**
* @Then I should be notified that the image with this code already exists
* @When I change the first image type to :type
*/
public function iShouldBeNotifiedThatTheImageWithThisCodeAlreadyExists()
public function iChangeTheFirstImageTypeTo($type)
{
Assert::same($this->updatePage->getValidationMessageForImage(), 'Image code must be unique within this taxon.');
$this->updatePage->modifyFirstImageType($type);
}
/**
* @Then I should be notified that an image code is required
* @Then /^(this taxon) should have only one image$/
* @Then /^(this taxon) should(?:| still) have (\d+) images?$/
*/
public function iShouldBeNotifiedThatAnImageCodeIsRequired()
{
Assert::same(
$this->updatePage->getValidationMessageForImage(),
'Please enter an image code.'
);
}
/**
* @Then there should still be only one image in the :taxon taxon
*/
public function thereShouldStillBeOnlyOneImageInThisTaxon(TaxonInterface $taxon)
public function thereShouldStillBeOnlyOneImageInThisTaxon(TaxonInterface $taxon, $count = 1)
{
$this->iWantToModifyATaxon($taxon);
Assert::same($this->updatePage->countImages(), 1);
Assert::same($this->updatePage->countImages(), (int) $count);
}
/**
* @Then the image code field should be disabled
* @return SymfonyPageInterface|CreatePageInterface|CreateForParentPageInterface|UpdatePageInterface
*/
public function theImageCodeFieldShouldBeDisabled()
private function resolveCurrentPage()
{
Assert::true($this->updatePage->isImageCodeDisabled());
}
/**
* @Then I should be notified that the :imageNumber image should have an unique code
*/
public function iShouldBeNotifiedThatTheFirstImageShouldHaveAnUniqueCode($imageNumber)
{
preg_match_all('!\d+!', $imageNumber, $matches);
Assert::same(
$this->updatePage->getValidationMessageForImageAtPlace(((int) $matches[0][0]) - 1),
'Image code must be unique within this taxon.'
);
return $this->currentPageResolver->getCurrentPageWithForm([
$this->createPage,
$this->createForParentPage,
$this->updatePage,
]);
}
}

View file

@ -47,7 +47,7 @@ class CreateConfigurableProductPage extends BaseCreatePage implements CreateConf
/**
* {@inheritdoc}
*/
public function attachImage($path, $code = null)
public function attachImage($path, $type = null)
{
$this->clickTabIfItsNotActive('media');
@ -56,8 +56,8 @@ class CreateConfigurableProductPage extends BaseCreatePage implements CreateConf
$this->getDocument()->clickLink('Add');
$imageForm = $this->getLastImageElement();
if (null !== $code) {
$imageForm->fillField('Code', $code);
if (null !== $type) {
$imageForm->fillField('Type', $type);
}
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);

View file

@ -22,7 +22,7 @@ interface CreateConfigurableProductPageInterface extends BaseCreatePageInterface
* @param string $optionName
*/
public function selectOption($optionName);
/**
* @param string $code
*/
@ -36,7 +36,7 @@ interface CreateConfigurableProductPageInterface extends BaseCreatePageInterface
/**
* @param string $path
* @param string $code
* @param string $type
*/
public function attachImage($path, $code = null);
public function attachImage($path, $type = null);
}

View file

@ -94,7 +94,7 @@ class CreateSimpleProductPage extends BaseCreatePage implements CreateSimpleProd
/**
* {@inheritdoc}
*/
public function attachImage($path, $code = null)
public function attachImage($path, $type = null)
{
$this->clickTabIfItsNotActive('media');
@ -103,8 +103,8 @@ class CreateSimpleProductPage extends BaseCreatePage implements CreateSimpleProd
$this->getDocument()->clickLink('Add');
$imageForm = $this->getLastImageElement();
if (null !== $code) {
$imageForm->fillField('Code', $code);
if (null !== $type) {
$imageForm->fillField('Type', $type);
}
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);

View file

@ -76,9 +76,9 @@ interface CreateSimpleProductPageInterface extends BaseCreatePageInterface
/**
* @param string $path
* @param string $code
* @param string $type
*/
public function attachImage($path, $code = null);
public function attachImage($path, $type = null);
/**
* @param ProductAssociationTypeInterface $productAssociationType

View file

@ -13,7 +13,6 @@ namespace Sylius\Behat\Page\Admin\Product;
use Behat\Mink\Driver\Selenium2Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\ElementNotFoundException;
use Sylius\Behat\Behaviour\ChecksCodeImmutability;
use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
use Sylius\Component\Taxonomy\Model\TaxonInterface;
@ -69,9 +68,9 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
public function selectMainTaxon(TaxonInterface $taxon)
{
$this->openTaxonBookmarks();
Assert::isInstanceOf($this->getDriver(), Selenium2Driver::class);
$this->getDriver()->executeScript(sprintf('$(\'input.search\').val(\'%s\')', $taxon->getName()));
$this->getElement('search')->click();
$this->getElement('search')->waitFor(10, function () {
@ -92,9 +91,9 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
/**
* {@inheritdoc}
*/
public function isImageWithCodeDisplayed($code)
public function isImageWithTypeDisplayed($type)
{
$imageElement = $this->getImageElementByCode($code);
$imageElement = $this->getImageElementByType($type);
if (null === $imageElement) {
return false;
@ -111,7 +110,7 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
/**
* {@inheritdoc}
*/
public function attachImage($path, $code = null)
public function attachImage($path, $type = null)
{
$this->clickTabIfItsNotActive('media');
@ -120,8 +119,8 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
$this->getDocument()->clickLink('Add');
$imageForm = $this->getLastImageElement();
if (null !== $code) {
$imageForm->fillField('Code', $code);
if (null !== $type) {
$imageForm->fillField('Type', $type);
}
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
@ -130,22 +129,22 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
/**
* {@inheritdoc}
*/
public function changeImageWithCode($code, $path)
public function changeImageWithType($type, $path)
{
$filesPath = $this->getParameter('files_path');
$imageForm = $this->getImageElementByCode($code);
$imageForm = $this->getImageElementByType($type);
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
}
/**
* {@inheritdoc}
*/
public function removeImageWithCode($code)
public function removeImageWithType($type)
{
$this->clickTabIfItsNotActive('media');
$imageElement = $this->getImageElementByCode($code);
$imageElement = $this->getImageElementByType($type);
$imageElement->clickLink('Delete');
}
@ -158,36 +157,22 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
/**
* {@inheritdoc}
*/
public function countImages()
public function modifyFirstImageType($type)
{
$imageElements = $this->getImageElements();
$this->clickTabIfItsNotActive('media');
return count($imageElements);
}
/**
* @return bool
*/
public function isImageCodeDisabled()
{
return 'disabled' === $this->getLastImageElement()->findField('Code')->getAttribute('disabled');
$firstImage = $this->getFirstImageElement();
$this->setImageType($firstImage, $type);
}
/**
* {@inheritdoc}
*/
public function getValidationMessageForImage()
public function countImages()
{
$this->clickTabIfItsNotActive('media');
$imageElements = $this->getImageElements();
$imageForm = $this->getLastImageElement();
$foundElement = $imageForm->find('css', '.sylius-validation-error');
if (null === $foundElement) {
throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
}
return $foundElement->getText();
return count($imageElements);
}
/**
@ -235,20 +220,20 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
}
/**
* @param string $code
* @param string $type
*
* @return NodeElement
*/
private function getImageElementByCode($code)
private function getImageElementByType($type)
{
$images = $this->getElement('images');
$inputCode = $images->find('css', 'input[value="'.$code.'"]');
$typeInput = $images->find('css', 'input[value="'.$type.'"]');
if (null === $inputCode) {
if (null === $typeInput) {
return null;
}
return $inputCode->getParent()->getParent()->getParent();
return $typeInput->getParent()->getParent()->getParent();
}
/**
@ -284,4 +269,14 @@ class UpdateConfigurableProductPage extends BaseUpdatePage implements UpdateConf
return reset($imageElements);
}
/**
* @param NodeElement $imageElement
* @param string $type
*/
private function setImageType(NodeElement $imageElement, $type)
{
$typeField = $imageElement->findField('Type');
$typeField->setValue($type);
}
}

View file

@ -11,7 +11,6 @@
namespace Sylius\Behat\Page\Admin\Product;
use Behat\Mink\Exception\ElementNotFoundException;
use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface;
use Sylius\Component\Taxonomy\Model\TaxonInterface;
@ -35,19 +34,19 @@ interface UpdateConfigurableProductPageInterface extends UpdatePageInterface
* @param string $option
*/
public function isProductOptionChosen($option);
/**
* @return bool
*/
public function isProductOptionsDisabled();
/**
* @param string $taxonName
*
* @return bool
*/
public function isMainTaxonChosen($taxonName);
/**
* @param TaxonInterface $taxon
*/
@ -59,45 +58,38 @@ interface UpdateConfigurableProductPageInterface extends UpdatePageInterface
public function checkChannel($channelName);
/**
* @param string $code
* @param string $type
*
* @return bool
*/
public function isImageWithCodeDisplayed($code);
public function isImageWithTypeDisplayed($type);
/**
* @param string $path
* @param string $code
* @param string $type
*/
public function attachImage($path, $code = null);
public function attachImage($path, $type = null);
/**
* @param string $code
* @param string $type
* @param string $path
*/
public function changeImageWithCode($code, $path);
public function changeImageWithType($type, $path);
/**
* @param string $code
* @param string $type
*/
public function removeImageWithCode($code);
public function removeImageWithType($type);
public function removeFirstImage();
/**
* @param string $type
*/
public function modifyFirstImageType($type);
/**
* @return int
*/
public function countImages();
/**
* @return bool
*/
public function isImageCodeDisabled();
/**
* @return string
*
* @throws ElementNotFoundException
*/
public function getValidationMessageForImage();
}

View file

@ -13,7 +13,6 @@ namespace Sylius\Behat\Page\Admin\Product;
use Behat\Mink\Driver\Selenium2Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\ElementNotFoundException;
use Sylius\Behat\Behaviour\ChecksCodeImmutability;
use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
use Sylius\Component\Core\Model\ChannelInterface;
@ -155,9 +154,9 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
/**
* {@inheritdoc}
*/
public function isImageWithCodeDisplayed($code)
public function isImageWithTypeDisplayed($type)
{
$imageElement = $this->getImageElementByCode($code);
$imageElement = $this->getImageElementByType($type);
if (null === $imageElement) {
return false;
@ -174,7 +173,7 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
/**
* {@inheritdoc}
*/
public function attachImage($path, $code = null)
public function attachImage($path, $type = null)
{
$this->clickTabIfItsNotActive('media');
@ -183,8 +182,8 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
$this->getDocument()->clickLink('Add');
$imageForm = $this->getLastImageElement();
if (null !== $code) {
$imageForm->fillField('Code', $code);
if (null !== $type) {
$imageForm->fillField('Type', $type);
}
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
@ -193,31 +192,44 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
/**
* {@inheritdoc}
*/
public function changeImageWithCode($code, $path)
public function changeImageWithType($type, $path)
{
$filesPath = $this->getParameter('files_path');
$imageForm = $this->getImageElementByCode($code);
$imageForm = $this->getImageElementByType($type);
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
}
/**
* {@inheritdoc}
*/
public function removeImageWithCode($code)
public function removeImageWithType($type)
{
$this->clickTabIfItsNotActive('media');
$imageElement = $this->getImageElementByCode($code);
$imageElement = $this->getImageElementByType($type);
$imageElement->clickLink('Delete');
}
public function removeFirstImage()
{
$this->clickTabIfItsNotActive('media');
$imageElement = $this->getFirstImageElement();
$imageElement->clickLink('Delete');
}
/**
* {@inheritdoc}
*/
public function modifyFirstImageType($type)
{
$this->clickTabIfItsNotActive('media');
$firstImage = $this->getFirstImageElement();
$this->setImageType($firstImage, $type);
}
/**
* {@inheritdoc}
*/
@ -228,14 +240,6 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
return count($imageElements);
}
/**
* {@inheritdoc}
*/
public function isImageCodeDisabled()
{
return 'disabled' === $this->getLastImageElement()->findField('Code')->getAttribute('disabled');
}
/**
* {@inheritdoc}
*/
@ -244,23 +248,6 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
return 'readonly' === $this->getElement('slug', ['%locale%' => $locale])->getAttribute('readonly');
}
/**
* {@inheritdoc}
*/
public function getValidationMessageForImage()
{
$this->clickTabIfItsNotActive('media');
$imageForm = $this->getLastImageElement();
$foundElement = $imageForm->find('css', '.sylius-validation-error');
if (null === $foundElement) {
throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
}
return $foundElement->getText();
}
/**
* {@inheritdoc}
*/
@ -368,6 +355,19 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
}
}
public function getPriceForChannel($channelName)
{
return $this->getElement('price', ['%channel%' => $channelName])->getValue();
}
/**
* {@inheritdoc}
*/
protected function getCodeElement()
{
return $this->getElement('code');
}
/**
* {@inheritdoc}
*/
@ -380,36 +380,6 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
return parent::getElement($name, $parameters);
}
public function getPriceForChannel($channelName)
{
return $this->getElement('price', ['%channel%' => $channelName])->getValue();
}
/**
* {@inheritdoc}
*/
public function getValidationMessageForImageAtPosition($position)
{
$this->clickTabIfItsNotActive('media');
$images = $this->getImageElements();
$foundElement = $images[$position]->find('css', '.sylius-validation-error');
if (null === $foundElement) {
throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
}
return $foundElement->getText();
}
/**
* {@inheritdoc}
*/
protected function getCodeElement()
{
return $this->getElement('code');
}
/**
* {@inheritdoc}
*/
@ -475,20 +445,20 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
}
/**
* @param string $code
* @param string $type
*
* @return NodeElement
*/
private function getImageElementByCode($code)
private function getImageElementByType($type)
{
$images = $this->getElement('images');
$inputCode = $images->find('css', 'input[value="'.$code.'"]');
$typeInput = $images->find('css', 'input[value="'.$type.'"]');
if (null === $inputCode) {
if (null === $typeInput) {
return null;
}
return $inputCode->getParent()->getParent()->getParent();
return $typeInput->getParent()->getParent()->getParent();
}
/**
@ -544,4 +514,14 @@ class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProd
return $value !== $slugElement->getValue();
});
}
/**
* @param NodeElement $imageElement
* @param string $type
*/
private function setImageType(NodeElement $imageElement, $type)
{
$typeField = $imageElement->findField('Type');
$typeField->setValue($type);
}
}

View file

@ -32,7 +32,7 @@ interface UpdateSimpleProductPageInterface extends BaseUpdatePageInterface
* @return bool
*/
public function isSlugReadOnlyIn($locale);
/**
* @param string $channelName
* @param int $price
@ -100,48 +100,41 @@ interface UpdateSimpleProductPageInterface extends BaseUpdatePageInterface
public function enableSlugModification($locale);
/**
* @param string $code
* @param string $type
*
* @return bool
*/
public function isImageWithCodeDisplayed($code);
public function isImageWithTypeDisplayed($type);
/**
* @param string $path
* @param string $code
* @param string $type
*/
public function attachImage($path, $code = null);
public function attachImage($path, $type = null);
/**
* @param string $code
* @param string $type
* @param string $path
*/
public function changeImageWithCode($code, $path);
public function changeImageWithType($type, $path);
/**
* @param string $code
* @param string $type
*/
public function removeImageWithCode($code);
public function removeImageWithType($type);
public function removeFirstImage();
/**
* @param string $type
*/
public function modifyFirstImageType($type);
/**
* @return int
*/
public function countImages();
/**
* @return bool
*/
public function isImageCodeDisabled();
/**
* @return string
*
* @throws ElementNotFoundException
*/
public function getValidationMessageForImage();
/**
* @param ProductAssociationTypeInterface $productAssociationType
* @param string[] $productsNames
@ -194,13 +187,4 @@ interface UpdateSimpleProductPageInterface extends BaseUpdatePageInterface
* @return string
*/
public function getPriceForChannel($channelName);
/**
* @param int $position
*
* @return string
*
* @throws ElementNotFoundException
*/
public function getValidationMessageForImageAtPosition($position);
}

View file

@ -105,14 +105,14 @@ class CreatePage extends BaseCreatePage implements CreatePageInterface
/**
* {@inheritdoc}
*/
public function attachImage($path, $code = null)
public function attachImage($path, $type = null)
{
$filesPath = $this->getParameter('files_path');
$this->getDocument()->find('css', '[data-form-collection="add"]')->click();
$imageForm = $this->getLastImageElement();
$imageForm->fillField('Code', $code);
$imageForm->fillField('Type', $type);
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
}

View file

@ -70,9 +70,9 @@ interface CreatePageInterface extends BaseCreatePageInterface
/**
* @param string $path
* @param string $code
* @param string $type
*/
public function attachImage($path, $code = null);
public function attachImage($path, $type = null);
/**
* @param TaxonInterface|null $parentTaxon

View file

@ -64,15 +64,15 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
/**
* {@inheritdoc}
*/
public function attachImage($path, $code = null)
public function attachImage($path, $type = null)
{
$filesPath = $this->getParameter('files_path');
$this->getDocument()->find('css', '[data-form-collection="add"]')->click();
$imageForm = $this->getLastImageElement();
if (null !== $code) {
$imageForm->fillField('Code', $code);
if (null !== $type) {
$imageForm->fillField('Type', $type);
}
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
@ -81,9 +81,9 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
/**
* {@inheritdoc}
*/
public function isImageWithCodeDisplayed($code)
public function isImageWithTypeDisplayed($type)
{
$imageElement = $this->getImageElementByCode($code);
$imageElement = $this->getImageElementByType($type);
if (null === $imageElement) {
return false;
@ -108,9 +108,9 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
/**
* {@inheritdoc}
*/
public function removeImageWithCode($code)
public function removeImageWithType($type)
{
$imageElement = $this->getImageElementByCode($code);
$imageElement = $this->getImageElementByType($type);
$imageElement->clickLink('Delete');
}
@ -141,14 +141,25 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
/**
* {@inheritdoc}
*/
public function changeImageWithCode($code, $path)
public function changeImageWithType($type, $path)
{
$filesPath = $this->getParameter('files_path');
$imageForm = $this->getImageElementByCode($code);
$imageForm = $this->getImageElementByType($type);
$imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
}
/**
* {@inheritdoc}
*/
public function modifyFirstImageType($type)
{
$firstImage = $this->getFirstImageElement();
$typeField = $firstImage->findField('Type');
$typeField->setValue($type);
}
/**
* {@inheritdoc}
*/
@ -170,9 +181,9 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
*/
public function getValidationMessageForImage()
{
$provinceForm = $this->getLastImageElement();
$lastImageElement = $this->getLastImageElement();
$foundElement = $provinceForm->find('css', '.sylius-validation-error');
$foundElement = $lastImageElement->find('css', '.sylius-validation-error');
if (null === $foundElement) {
throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
}
@ -186,7 +197,7 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
public function getValidationMessageForImageAtPlace($place)
{
$images = $this->getImageElements();
$foundElement = $images[$place]->find('css', '.sylius-validation-error');
if (null === $foundElement) {
throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
@ -195,14 +206,6 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
return $foundElement->getText();
}
/**
* @return bool
*/
public function isImageCodeDisabled()
{
return 'disabled' === $this->getLastImageElement()->findField('Code')->getAttribute('disabled');
}
/**
* {@inheritdoc}
*/
@ -278,6 +281,8 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
{
$imageElements = $this->getImageElements();
Assert::notEmpty($imageElements);
return reset($imageElements);
}
@ -292,20 +297,20 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
}
/**
* @param string $code
* @param string $type
*
* @return NodeElement
*/
private function getImageElementByCode($code)
private function getImageElementByType($type)
{
$images = $this->getElement('images');
$inputCode = $images->find('css', 'input[value="'.$code.'"]');
$typeInput = $images->find('css', 'input[value="'.$type.'"]');
if (null === $inputCode) {
if (null === $typeInput) {
return null;
}
return $inputCode->getParent()->getParent()->getParent();
return $typeInput->getParent()->getParent()->getParent();
}
/**

View file

@ -48,23 +48,18 @@ interface UpdatePageInterface extends BaseUpdatePageInterface
*/
public function specifySlug($slug, $languageCode);
/**
* @return bool
*/
public function isImageCodeDisabled();
/**
* @param string $path
* @param string $code
* @param string $type
*/
public function attachImage($path, $code = null);
public function attachImage($path, $type = null);
/**
* @param string $code
* @param string $type
*
* @return bool
*/
public function isImageWithCodeDisplayed($code);
public function isImageWithTypeDisplayed($type);
/**
* @param string $languageCode
@ -74,9 +69,9 @@ interface UpdatePageInterface extends BaseUpdatePageInterface
public function isSlugReadOnly($languageCode = 'en_US');
/**
* @param string $code
* @param string $type
*/
public function removeImageWithCode($code);
public function removeImageWithType($type);
public function removeFirstImage();
@ -91,10 +86,15 @@ interface UpdatePageInterface extends BaseUpdatePageInterface
public function countImages();
/**
* @param string $code
* @param string $type
* @param string $path
*/
public function changeImageWithCode($code, $path);
public function changeImageWithType($type, $path);
/**
* @param string $type
*/
public function modifyFirstImageType($type);
/**
* @return string

View file

@ -1,5 +1,5 @@
{% if product.imageByCode('thumbnail') is not null %}
{% set path = product.imageByCode('thumbnail').path|imagine_filter(filter|default('sylius_admin_product_thumbnail')) %}
{% if product.imagesByType('thumbnail') is not empty %}
{% set path = product.imagesByType('thumbnail').first.path|imagine_filter(filter|default('sylius_admin_product_thumbnail')) %}
{% elseif product.images.first %}
{% set path = product.images.first.path|imagine_filter(filter|default('sylius_admin_product_thumbnail')) %}
{% else %}

View file

@ -117,8 +117,8 @@ class BookProductFixture extends AbstractFixture
'book_pages' => $this->faker->numberBetween(42, 1024),
],
'images' => [
'main' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 'books.jpg'),
'thumbnail' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 'books.jpg'),
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 'books.jpg'), 'main'],
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 'books.jpg'), 'thumbnail'],
],
];
}

View file

@ -356,11 +356,14 @@ class ProductExampleFactory extends AbstractExampleFactory implements ExampleFac
*/
private function createImages(ProductInterface $product, array $options)
{
foreach ($options['images'] as $imageCode => $imagePath) {
foreach ($options['images'] as $image) {
$imagePath = array_shift($image);
$uploadedImage = new UploadedFile($imagePath, basename($imagePath));
/** @var ImageInterface $productImage */
$productImage = $this->productImageFactory->createNew();
$productImage->setCode($imageCode);
$productImage->setFile(new UploadedFile($imagePath, basename($imagePath)));
$productImage->setFile($uploadedImage);
$productImage->setType(end($image) ?: null);
$this->imageUploader->upload($productImage);

View file

@ -131,8 +131,8 @@ class MugProductFixture extends AbstractFixture
],
'product_options' => ['mug_type'],
'images' => [
'main' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 'mugs.jpg'),
'thumbnail' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 'mugs.jpg'),
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 'mugs.jpg'), 'main'],
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 'mugs.jpg'), 'thumbnail'],
],
];
}

View file

@ -135,8 +135,8 @@ class StickerProductFixture extends AbstractFixture
],
'product_options' => ['sticker_size'],
'images' => [
'main' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 'stickers.jpg'),
'thumbnail' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 'stickers.jpg'),
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 'stickers.jpg'), 'main'],
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 'stickers.jpg'), 'thumbnail'],
],
];
}

View file

@ -161,8 +161,8 @@ class TshirtProductFixture extends AbstractFixture
],
'product_options' => ['t_shirt_color', 't_shirt_size'],
'images' => [
'main' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 't-shirts.jpg'),
'thumbnail' => sprintf('%s/../Resources/fixtures/%s', __DIR__, 't-shirts.jpg'),
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 't-shirts.jpg'), 'main'],
[sprintf('%s/../Resources/fixtures/%s', __DIR__, 't-shirts.jpg'), 'thumbnail'],
],
];
}

View file

@ -11,9 +11,9 @@
namespace Sylius\Bundle\CoreBundle\Form\Type;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
/**
@ -27,7 +27,10 @@ abstract class ImageType extends AbstractResourceType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->addEventSubscriber(new AddCodeFormSubscriber())
->add('type', TextType::class, [
'label' => 'sylius.form.image.type',
'required' => false,
])
->add('file', FileType::class, [
'label' => 'sylius.form.image.file',
])

View file

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

View file

@ -11,19 +11,10 @@
-->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<mapped-superclass name="Sylius\Component\Core\Model\ProductImage" table="sylius_product_image">
<unique-constraints>
<unique-constraint columns="owner_id,code" name="product_image_code_idx" />
</unique-constraints>
<many-to-one field="owner" target-entity="Sylius\Component\Product\Model\ProductInterface" inversed-by="images">
<join-column name="owner_id" referenced-column-name="id" nullable="false" on-delete="CASCADE"/>
</many-to-one>
</mapped-superclass>
</doctrine-mapping>

View file

@ -11,19 +11,10 @@
-->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<mapped-superclass name="Sylius\Component\Core\Model\TaxonImage" table="sylius_taxon_image">
<unique-constraints>
<unique-constraint columns="owner_id,code" name="taxon_image_code_idx" />
</unique-constraints>
<many-to-one field="owner" target-entity="Sylius\Component\Taxonomy\Model\TaxonInterface" inversed-by="images">
<join-column name="owner_id" referenced-column-name="id" nullable="false" on-delete="CASCADE"/>
</many-to-one>
</mapped-superclass>
</doctrine-mapping>

View file

@ -15,10 +15,6 @@
<class name="Sylius\Component\Core\Model\Product">
<property name="images">
<constraint name="Valid" />
<constraint name="Sylius\Bundle\ResourceBundle\Validator\Constraints\UniqueWithinCollectionConstraint">
<option name="message">sylius.product_image.code.unique</option>
<option name="groups">sylius</option>
</constraint>
</property>
<constraint name="Sylius\Bundle\CoreBundle\Validator\Constraints\HasAllVariantPricesDefined">
<option name="groups">sylius</option>

View file

@ -13,26 +13,6 @@
<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\Core\Model\ProductImage">
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">
<value>code</value>
<value>owner</value>
</option>
<option name="errorPath">code</option>
<option name="message">sylius.product_image.code.unique</option>
<option name="groups">sylius</option>
</constraint>
<property name="code">
<constraint name="NotBlank">
<option name="message">sylius.product_image.code.not_blank</option>
<option name="groups">sylius</option>
</constraint>
<constraint name="Regex">
<option name="message">sylius.product_image.code.regex</option>
<option name="pattern">/^[\w-]*$/</option>
<option name="groups">sylius</option>
</constraint>
</property>
<property name="file">
<constraint name="Image">
<option name="maxSize">2M</option>

View file

@ -15,10 +15,6 @@
<class name="Sylius\Component\Core\Model\Taxon">
<property name="images">
<constraint name="Valid" />
<constraint name="Sylius\Bundle\ResourceBundle\Validator\Constraints\UniqueWithinCollectionConstraint">
<option name="message">sylius.taxon_image.code.unique</option>
<option name="groups">sylius</option>
</constraint>
</property>
</class>
</constraint-mapping>

View file

@ -13,26 +13,6 @@
<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\Core\Model\TaxonImage">
<constraint name="Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity">
<option name="fields">
<value>code</value>
<value>owner</value>
</option>
<option name="errorPath">code</option>
<option name="message">sylius.taxon_image.code.unique</option>
<option name="groups">sylius</option>
</constraint>
<property name="code">
<constraint name="NotBlank">
<option name="message">sylius.taxon_image.code.not_blank</option>
<option name="groups">sylius</option>
</constraint>
<constraint name="Regex">
<option name="message">sylius.taxon_image.code.regex</option>
<option name="pattern">/^[\w-]*$/</option>
<option name="groups">sylius</option>
</constraint>
</property>
<property name="file">
<constraint name="Image">
<option name="maxSize">2M</option>

View file

@ -35,7 +35,7 @@ sylius:
theme: Theme
hostname: Hostname
image:
code: Code
type: Type
file: Image
locale:
code: Code

View file

@ -44,10 +44,6 @@ sylius:
product_attribute:
invalid: Position must be an integer.
product_image:
code:
not_blank: Please enter an image code.
regex: Image code can only be comprised of letters, numbers, dashes and underscores.
unique: Image code must be unique within this product.
file:
max_size: The image is too big - {{ size }}{{ suffix }}. Maximum allowed size is {{ limit }}{{ suffix }}.
upload_ini_size: The image is too big. Maximum allowed size is {{ limit }}{{ suffix }}.
@ -76,10 +72,6 @@ sylius:
short_description:
max: Short description must not be longer then {{ limit }} characters.
taxon_image:
code:
not_blank: Please enter an image code.
regex: Image code can only be comprised of letters, numbers, dashes and underscores.
unique: Image code must be unique within this taxon.
file:
max_size: The image is too big - {{ size }}{{ suffix }}. Maximum allowed size is {{ limit }}{{ suffix }}.
upload_ini_size: The image is too big. Maximum allowed size is {{ limit }}{{ suffix }}.

View file

@ -1,5 +1,5 @@
{% if product.imageByCode('main') is not null %}
{% set source_path = product.imageByCode('main').path %}
{% if product.imagesByType('main') is not empty %}
{% set source_path = product.imagesByType('main').first.path %}
{% set original_path = source_path|imagine_filter('sylius_shop_product_original') %}
{% set path = source_path|imagine_filter(filter|default('sylius_shop_product_large_thumbnail')) %}
{% elseif product.images.first %}

View file

@ -1,5 +1,5 @@
{% if product.imageByCode('thumbnail') is not null %}
{% set path = product.imageByCode('thumbnail').path|imagine_filter(filter|default('sylius_shop_product_thumbnail')) %}
{% if product.imagesByType('thumbnail') is not empty %}
{% set path = product.imagesByType('thumbnail').first.path|imagine_filter(filter|default('sylius_shop_product_thumbnail')) %}
{% elseif product.images.first %}
{% set path = product.images.first.path|imagine_filter(filter|default('sylius_shop_product_thumbnail')) %}
{% else %}

View file

@ -50,11 +50,11 @@
{% block sylius_product_image_widget %}
<div class="ui upload box segment">
{{ form_row(form.code) }}
{{ form_row(form.type) }}
{% if form.vars.value.path|default(null) is null %}
<label for="{{ form.file.vars.id }}" class="ui icon labeled button"><i class="cloud upload icon"></i> {{ 'sylius.ui.choose_file'|trans }}</label>
{% else %}
<img class="ui small bordered image" src="{{ form.vars.value.path|imagine_filter('sylius_small') }}" alt="{{ form.vars.value.code }}" />
<img class="ui small bordered image" src="{{ form.vars.value.path|imagine_filter('sylius_small') }}" alt="{{ form.vars.value.type }}" />
<label for="{{ form.file.vars.id }}" class="ui icon labeled button"><i class="cloud upload icon"></i> {{ 'sylius.ui.change_file'|trans }}</label>
{% endif %}
<div class="ui hidden element">
@ -68,11 +68,11 @@
{% block sylius_taxon_image_widget %}
<div class="ui upload box segment">
{{ form_row(form.code) }}
{{ form_row(form.type) }}
{% if form.vars.value.path|default(null) is null %}
<label for="{{ form.file.vars.id }}" class="ui icon labeled button"><i class="cloud upload icon"></i> {{ 'sylius.ui.choose_file'|trans }}</label>
{% else %}
<img class="ui small bordered image" src="{{ form.vars.value.path|imagine_filter('sylius_small') }}" alt="{{ form.vars.value.code }}" />
<img class="ui small bordered image" src="{{ form.vars.value.path|imagine_filter('sylius_small') }}" alt="{{ form.vars.value.type }}" />
<label for="{{ form.file.vars.id }}" class="ui icon labeled button"><i class="cloud upload icon"></i> {{ 'sylius.ui.change_file'|trans }}</label>
{% endif %}
<div class="ui hidden element">

View file

@ -24,7 +24,7 @@ abstract class Image implements ImageInterface
/**
* @var string
*/
protected $code;
protected $type;
/**
* @var \SplFileInfo
@ -57,17 +57,17 @@ abstract class Image implements ImageInterface
/**
* {@inheritdoc}
*/
public function getCode()
public function getType()
{
return $this->code;
return $this->type;
}
/**
* {@inheritdoc}
*/
public function setCode($code)
public function setType($type)
{
$this->code = $code;
$this->type = $type;
}
/**

View file

@ -24,11 +24,11 @@ interface ImageAwareInterface
public function getImages();
/**
* @param $code
* @param string $type
*
* @return ImageInterface|null;
* @return Collection|ImageInterface[]
*/
public function getImageByCode($code);
public function getImagesByType($type);
/**
* @return bool

View file

@ -17,8 +17,18 @@ use Sylius\Component\Resource\Model\ResourceInterface;
/**
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
*/
interface ImageInterface extends ResourceInterface, CodeAwareInterface
interface ImageInterface extends ResourceInterface
{
/**
* @return string
*/
public function getType();
/**
* @param string $type
*/
public function setType($type);
/**
* @return null|\SplFileInfo
*/

View file

@ -37,7 +37,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
protected $productTaxons;
/**
* @var ChannelInterface[]|Collection
* @var Collection|ChannelInterface[]
*/
protected $channels;
@ -298,15 +298,11 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
/**
* {@inheritdoc}
*/
public function getImageByCode($code)
public function getImagesByType($type)
{
foreach ($this->images as $image) {
if ($code === $image->getCode()) {
return $image;
}
}
return null;
return $this->images->filter(function (ImageInterface $image) use ($type) {
return $type === $image->getType();
});
}
/**

View file

@ -23,7 +23,7 @@ use Sylius\Component\Taxonomy\Model\TaxonTranslation;
class Taxon extends BaseTaxon implements TaxonInterface
{
use TimestampableTrait;
/**
* @var Collection|ImageInterface[]
*/
@ -49,15 +49,11 @@ class Taxon extends BaseTaxon implements TaxonInterface
/**
* {@inheritdoc}
*/
public function getImageByCode($code)
public function getImagesByType($type)
{
foreach ($this->images as $image) {
if ($code === $image->getCode()) {
return $image;
}
}
return null;
return $this->images->filter(function (ImageInterface $image) use ($type) {
return $type === $image->getType();
});
}
/**

View file

@ -19,37 +19,5 @@ use Sylius\Component\Taxonomy\Model\TaxonInterface as BaseTaxonInterface;
*/
interface TaxonInterface extends BaseTaxonInterface, ImageAwareInterface
{
/**
* @return bool
*/
public function hasImages();
/**
* @param ImageInterface $image
*
* @return bool
*/
public function hasImage(ImageInterface $image);
/**
* @return Collection|ImageInterface[]
*/
public function getImages();
/**
* @param string $code
*
* @return ImageInterface|null
*/
public function getImageByCode($code);
/**
* @param ImageInterface $image
*/
public function removeImage(ImageInterface $image);
/**
* @param ImageInterface $image
*/
public function addImage(ImageInterface $image);
}

View file

@ -55,15 +55,15 @@ final class ProductImageSpec extends ObjectBehavior
$this->getPath()->shouldReturn(__FILE__);
}
function it_does_not_have_code_by_default()
function it_does_not_have_type_by_default()
{
$this->getCode()->shouldReturn(null);
$this->getType()->shouldReturn(null);
}
function its_code_is_mutable()
function its_type_is_mutable()
{
$this->setCode('banner');
$this->getCode()->shouldReturn('banner');
$this->setType('banner');
$this->getType()->shouldReturn('banner');
}
function it_does_not_have_owner_by_default()

View file

@ -60,7 +60,7 @@ final class ProductSpec extends ObjectBehavior
{
$this->getProductTaxons()->shouldHaveType(Collection::class);
}
function it_adds_a_product_taxons(ProductTaxonInterface $productTaxon)
{
$this->addProductTaxon($productTaxon);
@ -71,7 +71,7 @@ final class ProductSpec extends ObjectBehavior
{
$this->addProductTaxon($productTaxon);
$this->removeProductTaxon($productTaxon);
$this->hasProductTaxon($productTaxon)->shouldReturn(false);
}
@ -123,19 +123,19 @@ final class ProductSpec extends ObjectBehavior
$this->hasImage($image)->shouldReturn(false);
}
function it_returns_an_image_by_code(ImageInterface $image)
function it_returns_images_by_type(ImageInterface $image)
{
$image->getCode()->willReturn('thumbnail');
$image->getType()->willReturn('thumbnail');
$image->setOwner($this)->shouldBeCalled();
$this->addImage($image);
$this->getImageByCode('thumbnail')->shouldReturn($image);
$this->getImagesByType('thumbnail')->shouldBeLike(new ArrayCollection([$image->getWrappedObject()]));
}
function it_filters_product_taxons_by_taxon(
ProductTaxonInterface $firstProductTaxon,
ProductTaxonInterface $secondProductTaxon,
ProductTaxonInterface $firstProductTaxon,
ProductTaxonInterface $secondProductTaxon,
TaxonInterface $firstTaxon,
TaxonInterface $secondTaxon
) {
@ -144,11 +144,11 @@ final class ProductSpec extends ObjectBehavior
$firstProductTaxon->getTaxon()->willReturn($firstTaxon);
$secondProductTaxon->getTaxon()->willReturn($secondTaxon);
$this->filterProductTaxonsByTaxon($firstTaxon)->shouldBeCollection(new ArrayCollection([$firstProductTaxon->getWrappedObject()]));
$this->filterProductTaxonsByTaxon($firstTaxon)->shouldBeLike(new ArrayCollection([$firstProductTaxon->getWrappedObject()]));
}
function it_returns_null_if_no_product_taxon_has_taxon_durign_filtering(
function it_returns_null_if_no_product_taxon_has_taxon_during_filtering(
ProductTaxonInterface $firstProductTaxon,
ProductTaxonInterface $secondProductTaxon,
TaxonInterface $firstTaxon,
@ -161,32 +161,6 @@ final class ProductSpec extends ObjectBehavior
$firstProductTaxon->getTaxon()->willReturn($firstTaxon);
$secondProductTaxon->getTaxon()->willReturn($secondTaxon);
$this->filterProductTaxonsByTaxon($thirdTaxon)->shouldBeCollection(new ArrayCollection());
}
/**
* {@inheritdoc}
*/
public function getMatchers()
{
return [
'beCollection' => function ($subject, $key) {
if (!$subject instanceof Collection || !$key instanceof Collection) {
return false;
}
if ($subject->count() !== $key->count()) {
return false;
}
foreach ($subject as $subjectElement) {
if (!$key->contains($subjectElement)) {
return false;
}
}
return true;
},
];
$this->filterProductTaxonsByTaxon($thirdTaxon)->shouldBeLike(new ArrayCollection());
}
}

View file

@ -55,15 +55,15 @@ final class TaxonImageSpec extends ObjectBehavior
$this->getPath()->shouldReturn(__FILE__);
}
function it_does_not_have_code_by_default()
function it_does_not_have_type_by_default()
{
$this->getCode()->shouldReturn(null);
$this->getType()->shouldReturn(null);
}
function its_code_is_mutable()
function its_type_is_mutable()
{
$this->setCode('banner');
$this->getCode()->shouldReturn('banner');
$this->setType('banner');
$this->getType()->shouldReturn('banner');
}
function it_does_not_have_owner_by_default()

View file

@ -11,6 +11,7 @@
namespace spec\Sylius\Component\Core\Model;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Model\ImageAwareInterface;
@ -57,13 +58,13 @@ final class TaxonSpec extends ObjectBehavior
$this->hasImage($image)->shouldReturn(false);
}
function it_returns_an_image_by_code(ImageInterface $image)
function it_returns_images_by_type(ImageInterface $image)
{
$image->getCode()->willReturn('thumbnail');
$image->getType()->willReturn('thumbnail');
$image->setOwner($this)->shouldBeCalled();
$this->addImage($image);
$this->getImageByCode('thumbnail')->shouldReturn($image);
$this->getImagesByType('thumbnail')->shouldBeLike(new ArrayCollection([$image->getWrappedObject()]));
}
}

View file

@ -19,10 +19,7 @@ use Sylius\Component\Resource\Model\TranslatableInterface;
* @author Paweł Jędrzejewski <pawel@sylius.org>
* @author Gonzalo Vilaseca <gvilaseca@reiss.co.uk>
*/
interface TaxonInterface extends
CodeAwareInterface,
TaxonTranslationInterface,
TranslatableInterface
interface TaxonInterface extends CodeAwareInterface, TaxonTranslationInterface, TranslatableInterface
{
/**
* @return bool