From 4abae710ca12becfbb89ec859c70aed44706254a Mon Sep 17 00:00:00 2001 From: gggeek Date: Mon, 14 Nov 2016 23:22:11 +0000 Subject: [PATCH] Add support for creating attributes with values of type eztags --- API/Collection/TagCollection.php | 11 ++ Core/ComplexField/EzTags.php | 44 +++++++ Core/Executor/TagManager.php | 9 +- Core/Matcher/AbstractMatcher.php | 12 -- Core/Matcher/ContentMatcher.php | 2 +- Core/Matcher/ContentTypeGroupMatcher.php | 2 +- Core/Matcher/ContentTypeMatcher.php | 2 +- Core/Matcher/LocationMatcher.php | 2 +- Core/Matcher/ObjectStateGroupMatcher.php | 2 +- Core/Matcher/ObjectStateMatcher.php | 2 +- Core/Matcher/RepositoryMatcher.php | 19 +++ Core/Matcher/RoleMatcher.php | 2 +- Core/Matcher/SectionMatcher.php | 2 +- Core/Matcher/TagMatcher.php | 145 +++++++++++++++++++++++ Core/Matcher/UserGroupMatcher.php | 2 +- Core/Matcher/UserMatcher.php | 2 +- Core/ReferenceResolver/TagResolver.php | 8 +- Resources/config/services.yml | 16 +++ Resources/doc/DSL/ManageContent.yml | 12 ++ WHATSNEW.md | 2 + 20 files changed, 271 insertions(+), 27 deletions(-) create mode 100644 API/Collection/TagCollection.php create mode 100644 Core/ComplexField/EzTags.php create mode 100644 Core/Matcher/RepositoryMatcher.php create mode 100644 Core/Matcher/TagMatcher.php diff --git a/API/Collection/TagCollection.php b/API/Collection/TagCollection.php new file mode 100644 index 00000000..eb27a86a --- /dev/null +++ b/API/Collection/TagCollection.php @@ -0,0 +1,11 @@ +tagMatcher = $tagMatcher; + } + + /** + * Creates a value object to use as the field value when setting an eztags field type. + * + * @param array $fieldValue + * @param array $context The context for execution of the current migrations. Contains f.e. the path to the migration + * @return \Netgen\TagsBundle\Core\FieldType\Tags\Value + * @throws \Exception + */ + public function createValue($fieldValue, array $context = array()) + { + $tags = array(); + foreach($fieldValue as $def) + { + if (!is_array($def) || count($def) != 1) { + throw new \Exception('Definition of EzTags field is incorrect: each element of the tags array must be an array with one element'); + } + $identifier = reset($def); + $type = key($def); + + + foreach($this->tagMatcher->match(array($type => $identifier)) as $id => $tag) { + $tags[$id] = $tag; + } + } + + return new \Netgen\TagsBundle\Core\FieldType\Tags\Value(array_values($tags)); + } +} diff --git a/Core/Executor/TagManager.php b/Core/Executor/TagManager.php index dadc991b..752c5ddb 100644 --- a/Core/Executor/TagManager.php +++ b/Core/Executor/TagManager.php @@ -3,8 +3,6 @@ namespace Kaliop\eZMigrationBundle\Core\Executor; use Kaliop\eZMigrationBundle\Core\ReferenceResolver\ReferenceHandler; -use Netgen\TagsBundle\Core\SignalSlot\TagsService; -use Netgen\TagsBundle\API\Repository\Values\Tags\TagCreateStruct; class TagManager extends RepositoryExecutor { @@ -12,7 +10,10 @@ class TagManager extends RepositoryExecutor protected $tagService; - public function __construct(TagsService $tagService=null) + /** + * @param \Netgen\TagsBundle\Core\SignalSlot\TagsService $tagService + */ + public function __construct($tagService=null) { $this->tagService = $tagService; } @@ -42,7 +43,7 @@ protected function create() 'mainLanguageCode' => $lang, 'alwaysAvailable' => $alwaysAvail, ); - $tagCreateStruct = new TagCreateStruct($tagCreateArray); + $tagCreateStruct = new \Netgen\TagsBundle\API\Repository\Values\Tags\TagCreateStruct($tagCreateArray); foreach ($this->dsl['keywords'] as $langCode => $keyword) { diff --git a/Core/Matcher/AbstractMatcher.php b/Core/Matcher/AbstractMatcher.php index dd31d132..6055e981 100644 --- a/Core/Matcher/AbstractMatcher.php +++ b/Core/Matcher/AbstractMatcher.php @@ -2,7 +2,6 @@ namespace Kaliop\eZMigrationBundle\Core\Matcher; -use eZ\Publish\API\Repository\Repository; use Kaliop\eZMigrationBundle\API\MatcherInterface; abstract class AbstractMatcher implements MatcherInterface @@ -14,17 +13,6 @@ abstract class AbstractMatcher implements MatcherInterface /** @var int $maxConditions the maximum number of conditions we allow to match on for a single match request */ protected $maxConditions = 1; - protected $repository; - - /** - * @param Repository $repository - * @todo inject the services needed, not the whole repository - */ - public function __construct(Repository $repository) - { - $this->repository = $repository; - } - protected function validateConditions(array $conditions) { if (count($conditions) == 0) { diff --git a/Core/Matcher/ContentMatcher.php b/Core/Matcher/ContentMatcher.php index 7ca411be..d1417d4d 100644 --- a/Core/Matcher/ContentMatcher.php +++ b/Core/Matcher/ContentMatcher.php @@ -10,7 +10,7 @@ * @todo extend to allow matching by visibility, subtree, depth, object state, section, creation/modification date... * @todo extend to allow matching on multiple conditions (AND) */ -class ContentMatcher extends AbstractMatcher +class ContentMatcher extends RepositoryMatcher { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/ContentTypeGroupMatcher.php b/Core/Matcher/ContentTypeGroupMatcher.php index 17c263b7..40ea0b2e 100644 --- a/Core/Matcher/ContentTypeGroupMatcher.php +++ b/Core/Matcher/ContentTypeGroupMatcher.php @@ -6,7 +6,7 @@ use Kaliop\eZMigrationBundle\API\Collection\ContentTypeGroupCollection; use Kaliop\eZMigrationBundle\API\KeyMatcherInterface; -class ContentTypeGroupMatcher extends AbstractMatcher implements KeyMatcherInterface +class ContentTypeGroupMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/ContentTypeMatcher.php b/Core/Matcher/ContentTypeMatcher.php index 2d4d7158..a1e20c65 100644 --- a/Core/Matcher/ContentTypeMatcher.php +++ b/Core/Matcher/ContentTypeMatcher.php @@ -10,7 +10,7 @@ * Note: disallowing matches by remote_id allows us to implement KeyMatcherInterface without the risk of users getting * confused as to what they are matching... */ -class ContentTypeMatcher extends AbstractMatcher implements KeyMatcherInterface +class ContentTypeMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/LocationMatcher.php b/Core/Matcher/LocationMatcher.php index 7ea89052..4ff141e1 100644 --- a/Core/Matcher/LocationMatcher.php +++ b/Core/Matcher/LocationMatcher.php @@ -10,7 +10,7 @@ * @todo extend to allow matching by visibility, subtree, depth, object state, section, creation/modification date... * @todo extend to allow matching on multiple conditions (AND) */ -class LocationMatcher extends AbstractMatcher +class LocationMatcher extends RepositoryMatcher { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/ObjectStateGroupMatcher.php b/Core/Matcher/ObjectStateGroupMatcher.php index c24c339f..52633e4f 100644 --- a/Core/Matcher/ObjectStateGroupMatcher.php +++ b/Core/Matcher/ObjectStateGroupMatcher.php @@ -6,7 +6,7 @@ use \eZ\Publish\API\Repository\Values\ObjectState\ObjectStateGroup; use Kaliop\eZMigrationBundle\API\KeyMatcherInterface; -class ObjectStateGroupMatcher extends AbstractMatcher implements KeyMatcherInterface +class ObjectStateGroupMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/ObjectStateMatcher.php b/Core/Matcher/ObjectStateMatcher.php index c036c67f..f7c9b79f 100644 --- a/Core/Matcher/ObjectStateMatcher.php +++ b/Core/Matcher/ObjectStateMatcher.php @@ -7,7 +7,7 @@ use Kaliop\eZMigrationBundle\API\KeyMatcherInterface; use eZ\Publish\Core\Base\Exceptions\NotFoundException; -class ObjectStateMatcher extends AbstractMatcher implements KeyMatcherInterface +class ObjectStateMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/RepositoryMatcher.php b/Core/Matcher/RepositoryMatcher.php new file mode 100644 index 00000000..f51d417d --- /dev/null +++ b/Core/Matcher/RepositoryMatcher.php @@ -0,0 +1,19 @@ +repository = $repository; + } +} \ No newline at end of file diff --git a/Core/Matcher/RoleMatcher.php b/Core/Matcher/RoleMatcher.php index a12115a3..bd4dae54 100644 --- a/Core/Matcher/RoleMatcher.php +++ b/Core/Matcher/RoleMatcher.php @@ -6,7 +6,7 @@ use Kaliop\eZMigrationBundle\API\Collection\RoleCollection; use Kaliop\eZMigrationBundle\API\KeyMatcherInterface; -class RoleMatcher extends AbstractMatcher implements KeyMatcherInterface +class RoleMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/SectionMatcher.php b/Core/Matcher/SectionMatcher.php index 6d8046fe..7887cdec 100644 --- a/Core/Matcher/SectionMatcher.php +++ b/Core/Matcher/SectionMatcher.php @@ -6,7 +6,7 @@ use Kaliop\eZMigrationBundle\API\Collection\SectionCollection; use Kaliop\eZMigrationBundle\API\KeyMatcherInterface; -class SectionMatcher extends AbstractMatcher implements KeyMatcherInterface +class SectionMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/TagMatcher.php b/Core/Matcher/TagMatcher.php new file mode 100644 index 00000000..df78e379 --- /dev/null +++ b/Core/Matcher/TagMatcher.php @@ -0,0 +1,145 @@ +translationHelper = $translationHelper; + $this->tagService = $tagService; + } + + /** + * @param array $conditions key: condition, value: int / string / int[] / string[] + * @return TagCollection + */ + public function match(array $conditions) + { + return $this->matchTag($conditions); + } + + /** + * @param array $conditions key: condition, value: int / string / int[] / string[] + * @return TagCollection + * @throws \Exception + */ + public function matchTag(array $conditions) + { + if ($this->tagService == null) { + throw new \Exception('Netgen TAG Bundle is required to use tag matching'); + } + + $this->validateConditions($conditions); + + foreach ($conditions as $key => $values) { + + if (!is_array($values)) { + $values = array($values); + } + + switch ($key) { + case 'id': + case self::MATCH_TAG_ID: + return new TagCollection($this->findTagsByIds($values)); + + case 'remote_id': + case self::MATCH_TAG_REMOTE_ID: + return new TagCollection($this->findTagsByRemoteIds($values)); + + case 'keyword': + case self::MATCH_TAG_KEYWORD: + return new TagCollection($this->findTagsByKeywords($values)); + } + } + } + + protected function getConditionsFromKey($key) + { + if (is_int($key) || ctype_digit($key)) { + return array(self::MATCH_TAG_ID => $key); + } + + throw new \Exception("Tag matcher can not uniquely identify the type of key used to match: ".key); + } + + /** + * @param int[] $tagIds + * @return \Netgen\TagsBundle\API\Repository\Values\Tags\Tag[] + */ + protected function findTagsByIds(array $tagIds) + { + $tags = []; + + foreach ($tagIds as $tagId) { + // return unique contents + $tag = $this->tagService->loadTag($tagId); + $tags[$tag->id] = $tag; + } + + return $tags; + } + + /** + * @param string[] $tagRemoteIds + * @return \Netgen\TagsBundle\API\Repository\Values\Tags\Tag[] + */ + protected function findTagsByRemoteIds(array $tagRemoteIds) + { + $tags = []; + + foreach ($tagRemoteIds as $tagRemoteId) { + // return unique contents + $tag = $this->tagService->loadTagByRemoteId($tagRemoteId); + $tags[$tag->id] = $tag; + } + + return $tags; + } + + /** + * @param string[] $tagKeywords + * @return \Netgen\TagsBundle\API\Repository\Values\Tags\Tag[] + */ + protected function findTagsByKeywords(array $tagKeywords) + { + $tags = []; + + $availableLanguages = $this->translationHelper->getAvailableLanguages(); + + foreach ($tagKeywords as $tagKeyword) { + // return unique contents + foreach($this->tagService->loadTagsByKeyword($tagKeyword, $availableLanguages[0]) as $tag) { + $tags[$tag->id] = $tag; + } + } + + return $tags; + } +} diff --git a/Core/Matcher/UserGroupMatcher.php b/Core/Matcher/UserGroupMatcher.php index b2b65ea2..e82cbebc 100644 --- a/Core/Matcher/UserGroupMatcher.php +++ b/Core/Matcher/UserGroupMatcher.php @@ -9,7 +9,7 @@ /** * @todo add matching all groups of a user, all child groups of a group */ -class UserGroupMatcher extends AbstractMatcher implements KeyMatcherInterface +class UserGroupMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/Matcher/UserMatcher.php b/Core/Matcher/UserMatcher.php index 2fc932e4..27a5551a 100644 --- a/Core/Matcher/UserMatcher.php +++ b/Core/Matcher/UserMatcher.php @@ -6,7 +6,7 @@ use Kaliop\eZMigrationBundle\API\Collection\UserCollection; use Kaliop\eZMigrationBundle\API\KeyMatcherInterface; -class UserMatcher extends AbstractMatcher implements KeyMatcherInterface +class UserMatcher extends RepositoryMatcher implements KeyMatcherInterface { use FlexibleKeyMatcherTrait; diff --git a/Core/ReferenceResolver/TagResolver.php b/Core/ReferenceResolver/TagResolver.php index 1d60dd13..996a0235 100644 --- a/Core/ReferenceResolver/TagResolver.php +++ b/Core/ReferenceResolver/TagResolver.php @@ -4,6 +4,8 @@ /** * Handles references to tags + * + * @todo support custom languages */ class TagResolver extends AbstractResolver { @@ -15,7 +17,11 @@ class TagResolver extends AbstractResolver protected $translationHelper; protected $tagService; - public function __construct($translationHelper, $tagService) + /** + * @param $translationHelper + * @param \Netgen\TagsBundle\API\Repository\TagsService $tagService + */ + public function __construct($translationHelper, $tagService=null) { parent::__construct(); diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 3b3fff52..9612b1fe 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -55,6 +55,7 @@ parameters: ez_migration_bundle.object_state_matcher.class: Kaliop\eZMigrationBundle\Core\Matcher\ObjectStateMatcher ez_migration_bundle.object_state_group_matcher.class: Kaliop\eZMigrationBundle\Core\Matcher\ObjectStateGroupMatcher ez_migration_bundle.content_type_group_matcher.class: Kaliop\eZMigrationBundle\Core\Matcher\ContentTypeGroupMatcher + ez_migration_bundle.tag_matcher.class: Kaliop\eZMigrationBundle\Core\Matcher\TagMatcher ez_migration_bundle.complex_field_manager.class: Kaliop\eZMigrationBundle\Core\ComplexField\ComplexFieldManager ez_migration_bundle.complex_field.ezauthor.class: Kaliop\eZMigrationBundle\Core\ComplexField\EzAuthor @@ -65,6 +66,7 @@ parameters: ez_migration_bundle.complex_field.ezrelationlist.class: Kaliop\eZMigrationBundle\Core\ComplexField\EzRelationList ez_migration_bundle.complex_field.ezrichtext.class: Kaliop\eZMigrationBundle\Core\ComplexField\EzRichText ez_migration_bundle.complex_field.ezxmltext.class: Kaliop\eZMigrationBundle\Core\ComplexField\EzXmlText + ez_migration_bundle.complex_field.eztags.class: Kaliop\eZMigrationBundle\Core\ComplexField\EzTags ez_migration_bundle.reference_resolver.chain.class: Kaliop\eZMigrationBundle\Core\ReferenceResolver\ChainResolver ez_migration_bundle.reference_resolver.customreference.class: Kaliop\eZMigrationBundle\Core\ReferenceResolver\CustomReferenceResolver @@ -300,6 +302,12 @@ services: arguments: - '@ezpublish.api.repository' + ez_migration_bundle.tag_matcher: + class: '%ez_migration_bundle.tag_matcher.class%' + arguments: + - '@ezpublish.translation_helper' + - '@?ezpublish.api.service.tags' + ### field handlers ez_migration_bundle.complex_field_manager: @@ -375,6 +383,14 @@ services: tags: - { name: ez_migration_bundle.complex_field, fieldtype: ezxmltext } + ez_migration_bundle.complex_field.eztags: + parent: ez_migration_bundle.complex_field + class: '%ez_migration_bundle.complex_field.eztags.class%' + arguments: + - '@ez_migration_bundle.tag_matcher' + tags: + - { name: ez_migration_bundle.complex_field, fieldtype: eztags } + ### reference resolvers # A service that will resolve *any* possible reference. To be used with care diff --git a/Resources/doc/DSL/ManageContent.yml b/Resources/doc/DSL/ManageContent.yml index 272f9368..1b3866e6 100644 --- a/Resources/doc/DSL/ManageContent.yml +++ b/Resources/doc/DSL/ManageContent.yml @@ -58,6 +58,18 @@ latitude: 1.0 longitude: 2.0 address: 'Angel, London' + # ezgmaplocation - NULL value + attribute13: + latitude: null + longitude: null + # eztags, setting 2-or-more tags + attribute14: + # one tag + - id: 12 + # one tag + - remote_id: abc + # zero or more tags + - keyword: hello # Optionally assign object states to the content object_states: - xxx # int|string an object state id or identifier. If the identifier is not unique, use obj-state-gorup-identifier/obj-state-identifier diff --git a/WHATSNEW.md b/WHATSNEW.md index 88e65211..76d8d503 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -3,6 +3,8 @@ Version 3.0.0-beta4 * New: It is now possible to replace the executor and step definition in a BeforeStepExecutionEvent +* New: it is now possible to set values to content fields of type eztags + Version 3.0.0-beta3 ===================