partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit fc2d74aac6a6ee6b63cae6d057784ae5e7359fde
parent 1186069188d996003f1a298f02cf93a8e2791455
Author: Felicitus <felicitus@felicitus.org>
Date:   Sun, 19 Jul 2015 23:30:29 +0200

Implemented listener to update category paths

Diffstat:
Mapp/config/config.yml | 9++++++++-
Msrc/PartKeepr/CategoryBundle/Entity/AbstractCategory.php | 68+++++++++++++-------------------------------------------------------
Msrc/PartKeepr/CoreBundle/DoctrineMigrations/Version20150708120022.php | 44++++++++++++++++++++++++++++++++++++--------
Asrc/PartKeepr/CoreBundle/DoctrineMigrations/Version20150719213922.php | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FootprintBundle/Controller/FootprintCategoryController.php | 2--
Msrc/PartKeepr/FootprintBundle/Entity/Footprint.php | 30++++++++++++++++++++++++++++++
Msrc/PartKeepr/FootprintBundle/Entity/FootprintCategory.php | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/FootprintBundle/Listeners/CategoryPathListener.php | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/Footprint/FootprintEditorComponent.js | 14++++++++++----
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/Footprint/FootprintGrid.js | 8+++++++-
10 files changed, 241 insertions(+), 71 deletions(-)

diff --git a/app/config/config.yml b/app/config/config.yml @@ -125,8 +125,15 @@ nelmio_api_doc: json: "application/json" services: + my.listener: + class: PartKeepr\FootprintBundle\Listeners\CategoryPathListener + arguments: + - "@service_container" + tags: + - { name: doctrine.event_listener, event: onFlush } + my_event_listener: - class: "PartKeepr\\UploadedFileBundle\\EventListener\\TemporaryFileEventListener" + class: PartKeepr\UploadedFileBundle\EventListener\TemporaryFileEventListener arguments: - "@partkeepr_uploadedfile_service" - "@annotation_reader" diff --git a/src/PartKeepr/CategoryBundle/Entity/AbstractCategory.php b/src/PartKeepr/CategoryBundle/Entity/AbstractCategory.php @@ -16,9 +16,15 @@ use Symfony\Component\Serializer\Annotation\Groups; * * If you are interested on how NestedSets work, please read http://en.wikipedia.org/wiki/Nested_set_model */ -class AbstractCategory extends BaseEntity +abstract class AbstractCategory extends BaseEntity { /** + * The parent category. This needs to be re-defined in the class with the proper relations + * @var + */ + protected $parent; + + /** * The "left" property of the nested set * @ORM\Column(type="integer") * @@ -68,15 +74,6 @@ class AbstractCategory extends BaseEntity private $description; /** - * Holds the category path. - * - * @ORM\Column(type="text",nullable=true) - * - * @var string - */ - private $categoryPath; - - /** * @Groups({"default"}) * @var bool */ @@ -186,58 +183,19 @@ class AbstractCategory extends BaseEntity $this->rgt = $rgt; } - public function setRoot($root) - { - $this->root = $root; - } - - /** - * Serializes the entity. - */ - public function serialize() - { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription(), - ); - } - - /** - * Returns a string representation of the current node. - * - * @return string The node name - * - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::__toString() - */ - public function __toString() - { - return $this->getName(); - } - /** - * Retrieves the category path - * - * @return string The category path + * Sets the root of the tree + * @param $root */ - public function getCategoryPath() + public function setRoot($root) { - return $this->categoryPath; + $this->root = $root; } /** - * Sets the category path. - * - * THIS IS ONLY TO BE CALLED FROM THE CATEGORYMANAGER! DON'T MESS WITH IT! - * - * @param string $categoryPath + * Returns the root of the tree + * @return mixed */ - public function setCategoryPath($categoryPath) - { - $this->categoryPath = $categoryPath; - } - public function getRoot() { return $this->root; diff --git a/src/PartKeepr/CoreBundle/DoctrineMigrations/Version20150708120022.php b/src/PartKeepr/CoreBundle/DoctrineMigrations/Version20150708120022.php @@ -3,9 +3,8 @@ namespace PartKeepr\CoreBundle\DoctrineMigrations; use Doctrine\DBAL\Schema\Schema; - /** - * Auto-generated Migration: Please modify to your needs! + * Fixes the category trees due to the migration of doctrine2-nestedset to DoctrineExtensions */ class Version20150708120022 extends BaseMigration { @@ -18,10 +17,15 @@ class Version20150708120022 extends BaseMigration $this->fixTree("PartCategory"); $this->fixTree("FootprintCategory"); - - } + /** + * Fixes the tree for a given table due to the migration of doctrine2-nestedset to DoctrineExtensions + * + * @param string $table The table name to fix + * + * @throws \Doctrine\DBAL\DBALException + */ public function fixTree($table) { $nodes = $this->getNodeIds($table); @@ -38,25 +42,36 @@ class Version20150708120022 extends BaseMigration $level = $this->getLevel($table, $node["id"]); if ($parent !== false) { - $this->connection->executeUpdate($queryBuilder->getSQL(), + $this->connection->executeUpdate( + $queryBuilder->getSQL(), array( ":parent" => $parent, ":id" => $node["id"], ":level" => $level, ":root" => 1, - )); + ) + ); } else { - $this->connection->executeUpdate($queryBuilder->getSQL(), + $this->connection->executeUpdate( + $queryBuilder->getSQL(), array( ":parent" => null, ":id" => $node["id"], ":root" => 1, ":level" => 0, - )); + ) + ); } } } + /** + * Fetches the parent node for a table and ID + * @param $table + * @param $id + * + * @return mixed + */ public function fetchParent($table, $id) { $queryBuilder = $this->connection->createQueryBuilder(); @@ -73,6 +88,12 @@ class Version20150708120022 extends BaseMigration return $this->connection->fetchColumn($queryBuilder->getSQL(), array(":nodeid" => $id), 0); } + /** + * Returns the node IDs for the table + * @param $table + * + * @return array + */ public function getNodeIds($table) { $qb = $this->connection->createQueryBuilder(); @@ -84,6 +105,13 @@ class Version20150708120022 extends BaseMigration return $this->connection->fetchAll($qb->getSQL()); } + /** + * Returns the level for a given table and ID + * @param $table + * @param $id + * + * @return mixed + */ public function getLevel($table, $id) { $qb = $this->connection->createQueryBuilder(); diff --git a/src/PartKeepr/CoreBundle/DoctrineMigrations/Version20150719213922.php b/src/PartKeepr/CoreBundle/DoctrineMigrations/Version20150719213922.php @@ -0,0 +1,49 @@ +<?php + +namespace PartKeepr\CoreBundle\DoctrineMigrations; + +use Doctrine\DBAL\Schema\Schema; +use Gedmo\Tree\Entity\Repository\NestedTreeRepository; +use PartKeepr\FootprintBundle\Entity\FootprintCategory; + +/** + * + */ +class Version20150719213922 extends BaseMigration +{ + /** + * Re-generates the category paths. It is enough to trigger an update on the root node, as the event listener + * will recursively update the child categories. + * + * @param Schema $schema + */ + public function up(Schema $schema) + { + $repository = $this->getEM()->getRepository( + 'PartKeepr\FootprintBundle\Entity\FootprintCategory' + ); + + /** + * @var $repository NestedTreeRepository + */ + $rootNodes = $repository->getRootNodes(); + + foreach ($rootNodes as $rootNode) { + /** + * @var $rootNode FootprintCategory + */ + $rootNode->setCategoryPath($rootNode->generateCategoryPath()); + } + + $this->getEM()->flush(); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + // this down() migration is auto-generated, please modify it to your needs + + } +} diff --git a/src/PartKeepr/FootprintBundle/Controller/FootprintCategoryController.php b/src/PartKeepr/FootprintBundle/Controller/FootprintCategoryController.php @@ -44,7 +44,5 @@ class FootprintCategoryController extends ResourceController $this->get("doctrine")->getManager()->flush(); return new Response($request->request->get("parent")); - - } } diff --git a/src/PartKeepr/FootprintBundle/Entity/Footprint.php b/src/PartKeepr/FootprintBundle/Entity/Footprint.php @@ -68,6 +68,36 @@ class Footprint extends BaseEntity private $attachments; /** + * @Groups({"default"}) + * @var + */ + private $categoryPath; + + /** + * Sets the category path for the entity + * + * @param string $categoryPath The category path to set + */ + public function setCategoryPath($categoryPath) + { + $this->categoryPath = $categoryPath; + } + + /** + * Returns the category path for the entity + * + * @return string The Category Path + */ + public function getCategoryPath() + { + if ($this->getCategory() !== null) { + return $this->getCategory()->generateCategoryPath(); + } + + return ""; + } + + /** * Constructs a new Footprint entity */ public function __construct() diff --git a/src/PartKeepr/FootprintBundle/Entity/FootprintCategory.php b/src/PartKeepr/FootprintBundle/Entity/FootprintCategory.php @@ -39,6 +39,13 @@ class FootprintCategory extends AbstractCategory protected $footprints; /** + * @ORM\Column(type="text",nullable=true) + * @Groups({"default"}) + * @var string + */ + protected $categoryPath; + + /** * Sets the parent category * * @param AbstractCategory|null $parent @@ -77,4 +84,38 @@ class FootprintCategory extends AbstractCategory { return $this->children; } + + /** + * Returns the category path + * + * @return string + */ + public function getCategoryPath() + { + return $this->categoryPath; + } + + /** + * Sets the category path + * + * @param string $categoryPath The category path + */ + public function setCategoryPath($categoryPath) + { + $this->categoryPath = $categoryPath; + } + + /** + * Generates the category path + * + * @return string The category path + */ + public function generateCategoryPath() + { + if ($this->getParent() !== null) { + return $this->getParent()->generateCategoryPath()." / ".$this->getName(); + } else { + return $this->getName(); + } + } } diff --git a/src/PartKeepr/FootprintBundle/Listeners/CategoryPathListener.php b/src/PartKeepr/FootprintBundle/Listeners/CategoryPathListener.php @@ -0,0 +1,47 @@ +<?php +namespace PartKeepr\FootprintBundle\Listeners; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Event\OnFlushEventArgs; +use PartKeepr\FootprintBundle\Entity\FootprintCategory; +use Symfony\Component\DependencyInjection\ContainerAware; + +class CategoryPathListener extends ContainerAware +{ + /** + * Updates the child category paths when their parent name has changed. + * + * @param OnFlushEventArgs $eventArgs The event arguments as given by Doctrine + */ + public function onFlush(OnFlushEventArgs $eventArgs) + { + $entityManager = $eventArgs->getEntityManager(); + $uow = $entityManager->getUnitOfWork(); + + foreach ($uow->getScheduledEntityUpdates() as $updated) { + if ($updated instanceof FootprintCategory) { + $this->updateCategoryPaths($updated, $entityManager); + } + } + } + + /** + * Recursively updates the category paths. + * + * @param FootprintCategory $footprintCategory The footprint category to update + * @param EntityManager $entityManager The entity manager + */ + public function updateCategoryPaths(FootprintCategory $footprintCategory, EntityManager $entityManager) + { + $footprintCategory->setCategoryPath($footprintCategory->generateCategoryPath()); + + $entityManager->getUnitOfWork()->recomputeSingleEntityChangeSet( + $entityManager->getClassMetadata(get_class($footprintCategory)), + $footprintCategory + ); + + foreach ($footprintCategory->getChildren() as $child) { + $this->updateCategoryPaths($child, $entityManager); + } + } +} diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Footprint/FootprintEditorComponent.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Footprint/FootprintEditorComponent.js @@ -7,10 +7,16 @@ Ext.define('PartKeepr.FootprintEditorComponent', { model: 'PartKeepr.FootprintBundle.Entity.Footprint', initComponent: function () { this.createStore({ - sorters: [{ - property: 'name', - direction:'ASC' - }] + sorters: [ + { + property: 'category', + direction: 'ASC' + },{ + property: 'name', + direction:'ASC' + } + ], + groupField: 'categoryPath' }); this.callParent(); diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Footprint/FootprintGrid.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Footprint/FootprintGrid.js @@ -6,5 +6,11 @@ Ext.define('PartKeepr.FootprintGrid', { ], addButtonText: i18n("Add Footprint"), deleteButtonText: i18n("Delete Footprint"), - automaticPageSize: true + automaticPageSize: true, + + features: [{ + ftype: 'grouping', + groupHeaderTpl: '{name} ({children.length})', + enableNoGroups:true + }] }); \ No newline at end of file