Skip to content

Commit

Permalink
Merge pull request #6 from akeneo-labs/tree_deletion_improvement
Browse files Browse the repository at this point in the history
Tree deletion improvement
  • Loading branch information
damien-carcel committed Jul 22, 2015
2 parents b02a697 + d507340 commit 414ce76
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 33 deletions.
59 changes: 43 additions & 16 deletions Engine/ProductRuleApplier/ProductsUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Akeneo\Bundle\RuleEngineBundle\Model\RuleInterface;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\EntityNotFoundException;
use Pim\Bundle\CatalogBundle\Model\CategoryInterface;
use Pim\Bundle\CatalogBundle\Model\ProductInterface;
use Pim\Bundle\CatalogBundle\Repository\CategoryRepositoryInterface;
use Pim\Bundle\CatalogBundle\Updater\ProductTemplateUpdaterInterface;
use Pim\Bundle\CatalogBundle\Updater\ProductUpdaterInterface;
Expand Down Expand Up @@ -64,18 +67,16 @@ public function updateFromRule(array $products, RuleInterface $rule)
/**
* Applies a add category action on a subject set, if this category exists.
*
* @param \Pim\Bundle\CatalogBundle\Model\ProductInterface[] $products
* @param ProductAddCategoryActionInterface $action
* @param ProductInterface[] $products
* @param ProductAddCategoryActionInterface $action
*
* @return ProductsUpdater
*/
protected function applyAddCategoryAction(array $products, ProductAddCategoryActionInterface $action)
{
$category = $this->getCategory($action->getCategoryCode());
foreach ($products as $product) {
$category = $this->categoryRepository->findOneByIdentifier($action->getCategoryCode());
if (null !== $category) {
$product->addCategory($category);
}
$product->addCategory($category);
}

return $this;
Expand All @@ -84,27 +85,53 @@ protected function applyAddCategoryAction(array $products, ProductAddCategoryAct
/**
* Applies a set category action on a subject set, if this category exists.
*
* @param \Pim\Bundle\CatalogBundle\Model\ProductInterface[] $products
* @param ProductSetCategoryActionInterface $action
* @param ProductInterface[] $products
* @param ProductSetCategoryActionInterface $action
*
* @return ProductsUpdater
*/
protected function applySetCategoryAction(array $products, ProductSetCategoryActionInterface $action)
{
$category = ($action->getCategoryCode()) ? $this->getCategory($action->getCategoryCode()) : null;
$tree = ($action->getTreeCode()) ? $this->getCategory($action->getTreeCode()) : null;

foreach ($products as $product) {
$previousCategories = $product->getCategories();
foreach ($previousCategories as $category) {
$product->removeCategory($category);
// Remove categories (only a tree if asked) from the product
foreach ($product->getCategories() as $currentCategory) {
if (null === $tree) {
$product->removeCategory($currentCategory);
} elseif ($currentCategory->getRoot() === $tree->getId()) {
$product->removeCategory($currentCategory);
}
}

if (null !== $action->getCategoryCode()) {
$newCategory = $this->categoryRepository->findOneByIdentifier($action->getCategoryCode());
if (null !== $newCategory) {
$product->addCategory($newCategory);
}
if (null !== $category) {
$product->addCategory($category);
}
}

return $this;
}

/**
* @param string $categoryCode
*
* @return CategoryInterface
*
* @throws \Exception
*/
protected function getCategory($categoryCode)
{
$category = $this->categoryRepository->findOneByIdentifier($categoryCode);
if (null === $category) {
throw new EntityNotFoundException(
sprintf(
'Impossible to apply rule to on this category cause the category "%s" does not exist',
$categoryCode
)
);
}

return $category;
}
}
1 change: 1 addition & 0 deletions Model/ProductAddCategoryActionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
interface ProductAddCategoryActionInterface extends ActionInterface
{
/** @staticvar string */
const ACTION_TYPE = 'add_category';

/**
Expand Down
30 changes: 30 additions & 0 deletions Model/ProductSetCategoryAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,34 @@
*/
class ProductSetCategoryAction extends AbstractCategoryAction implements ProductSetCategoryActionInterface
{
/** @var string */
protected $treeCode;

/**
* @param array $data
*/
public function __construct(array $data)
{
parent::__construct($data);

$this->treeCode = isset($data['treeCode']) ? $data['treeCode'] : null;
}

/**
* {@inheritdoc}
*/
public function getTreeCode()
{
return $this->treeCode;
}

/**
* {@inheritdoc}
*/
public function setTreeCode($treeCode)
{
$this->treeCode = $treeCode;

return $this;
}
}
17 changes: 15 additions & 2 deletions Model/ProductSetCategoryActionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,30 @@
*/
interface ProductSetCategoryActionInterface extends ActionInterface
{
/** @staticvar string */
const ACTION_TYPE = 'set_category';

/**
* @return string
* @return string|null
*/
public function getCategoryCode();

/**
* @param string $categoryCode
*
* @return ProductAddCategoryActionInterface
* @return ProductSetCategoryActionInterface
*/
public function setCategoryCode($categoryCode);

/**
* @return string|null
*/
public function getTreeCode();

/**
* @param string $treeCode
*
* @return ProductSetCategoryActionInterface
*/
public function setTreeCode($treeCode);
}
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,7 @@ A bundle that extend the Pim Enterprise CatalogRuleBundle, adding the possibilit

## Installation

As the Git repository is private, you need to add it to the composer.json of your project:

"repositories": [
{
"type": "vcs",
"url": "https://github.com/akeneo-labs/ClassificationRuleBundle.git",
"branch": "master"
}
]

Then install the bundle with composer:
You can install the bundle with composer:

$ php composer.phar require akeneo-labs/classification-rule-bundle:1.0.*

Expand All @@ -40,7 +30,9 @@ Then clean the cache:
This bundle is an extension of the CatalogRuleBundle, so it uses the same conditions, and add a new set of actions:

* `add_category`: add a product to a category,
* `set_category`: add a product to a category and remove it from all other category. If you set the category code to `null`, it will declassify the product.
* `set_category`: add a product to a category and remove it from all other category.
If you set the category code to `null`, it will declassify the product.
You can also define a tree to declassify only the product's categories of this tree.

The category must exists, or the rule will not apply.

Expand Down Expand Up @@ -84,5 +76,15 @@ The category must exists, or the rule will not apply.
actions:
- type: set_category
categoryCode: null
led_tvs_remove_category_on_master_tree:
conditions:
- field: family.code
operator: IN
value:
- led_tvs
actions:
- type: set_category
treeCode: master


Take a look to [icecat_demo_dev rule fixtures](https://github.com/akeneo/pim-enterprise-dev/blob/1.3/src/PimEnterprise/Bundle/InstallerBundle/Resources/fixtures/icecat_demo_dev/rules.yml) to see more examples of conditions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace spec\PimEnterprise\Bundle\ClassificationRuleBundle\Engine\ProductRuleApplier;

use Akeneo\Bundle\RuleEngineBundle\Model\RuleInterface;
use Doctrine\ORM\EntityNotFoundException;
use PhpSpec\ObjectBehavior;
use Pim\Bundle\CatalogBundle\Model\CategoryInterface;
use Pim\Bundle\CatalogBundle\Model\GroupInterface;
Expand Down Expand Up @@ -104,16 +105,17 @@ function it_updates_product_when_the_rule_has_a_copy_action(

function it_classifies_product_when_the_rule_has_an_add_category_action(
$templateUpdater,
$categoryRepository,
CategoryInterface $category,
CategoryRepositoryInterface $categoryRepository,
RuleInterface $rule,
ProductInterface $product,
ProductAddCategoryActionInterface $action
) {
$action->getCategoryCode()->willReturn('categoryCode');
$rule->getActions()->willReturn([$action]);

$action->getCategoryCode()->willReturn('categoryCode');
$categoryRepository->findOneByIdentifier('categoryCode')->willReturn($category);

$product->addCategory($category)->shouldBeCalled();

$product->getVariantGroup()->willReturn(null);
Expand All @@ -125,14 +127,15 @@ function it_classifies_product_when_the_rule_has_an_add_category_action(

function it_classifies_product_when_the_rule_has_an_set_category_action(
$templateUpdater,
$categoryRepository,
CategoryInterface $category,
CategoryInterface $currentCategory,
CategoryRepositoryInterface $categoryRepository,
RuleInterface $rule,
ProductInterface $product,
ProductSetCategoryActionInterface $action
) {
$action->getCategoryCode()->willReturn('categoryCode');
$action->getTreeCode()->willReturn(null);
$rule->getActions()->willReturn([$action]);

$categoryRepository->findOneByIdentifier('categoryCode')->willReturn($category);
Expand All @@ -155,6 +158,7 @@ function it_declassifies_product_when_the_rule_has_an_set_category_action_withou
ProductSetCategoryActionInterface $action
) {
$action->getCategoryCode()->willReturn(null);
$action->getTreeCode()->willReturn(null);
$rule->getActions()->willReturn([$action]);

$product->getCategories()->willReturn([$currentCategory]);
Expand All @@ -168,6 +172,79 @@ function it_declassifies_product_when_the_rule_has_an_set_category_action_withou
$this->update($rule, [$product]);
}

function it_declassifies_product_on_a_tree_when_the_rule_has_an_set_action_with_tree(
$templateUpdater,
$categoryRepository,
CategoryInterface $currentCategory1,
CategoryInterface $currentCategory2,
CategoryInterface $tree,
RuleInterface $rule,
ProductInterface $product,
ProductSetCategoryActionInterface $action
) {
$action->getCategoryCode()->willReturn(null);
$action->getTreeCode()->willReturn('TreeCode');
$rule->getActions()->willReturn([$action]);

$categoryRepository->findOneByIdentifier('TreeCode')->willReturn($tree);
$tree->getId()->willReturn(1);
$currentCategory1->getRoot()->willReturn(1);
$currentCategory2->getRoot()->willReturn(2);

$product->getCategories()->willReturn([$currentCategory1, $currentCategory2]);
$product->removeCategory($currentCategory1)->shouldBeCalled();
$product->removeCategory($currentCategory2)->shouldNotBeCalled();
$product->addCategory(Argument::any())->shouldNotBeCalled();

$product->getVariantGroup()->willReturn(null);
$templateUpdater->update(Argument::any(), Argument::any())
->shouldNotBeCalled();

$this->update($rule, [$product]);
}

function it_throws_exception_when_category_code_does_not_exist(
$categoryRepository,
RuleInterface $rule,
ProductSetCategoryActionInterface $action,
ProductInterface $product
) {
$rule->getActions()->willReturn([$action]);
$action->getCategoryCode()->willReturn('UnknownCode');
$action->getTreeCode()->willReturn(null);

$categoryRepository->findOneByIdentifier('UnknownCode')->willReturn(null);

$this
->shouldThrow(
new EntityNotFoundException(
'Impossible to apply rule to on this category cause the category "UnknownCode" does not exist'
)
)
->during('update', [$rule, [$product]]);
}

function it_throws_exception_when_tree_code_does_not_exist(
$categoryRepository,
RuleInterface $rule,
ProductSetCategoryActionInterface $action,
ProductInterface $product
) {
$rule->getActions()->willReturn([$action]);
$action->getCategoryCode()->willReturn(null);
$action->getTreeCode()->willReturn('UnknownCode');

$categoryRepository->findOneByIdentifier('UnknownCode')->willReturn(null);

$this
->shouldThrow(
new EntityNotFoundException(
'Impossible to apply rule to on this category cause the category "UnknownCode" does not exist'
)
)
->during('update', [$rule, [$product]]);
}

function it_throws_exception_when_update_a_product_with_an_unknown_action(
RuleInterface $rule,
ProductInterface $product
Expand Down

0 comments on commit 414ce76

Please sign in to comment.