public function testValueChangedEvents() { $listener = Mockery::mock(ValueChangedListenerInterface::CLASS); $listener->shouldReceive('onValueChanged')->with(ValueChangedEvent::CLASS)->twice(); $article_type = $this->getTypeMock(); $embed_type = new ParagraphType($article_type, $article_type->getAttribute('content_objects')); $embedd_entity = $embed_type->createEntity(['title' => 'Hello world', 'content' => 'Foobar lorem ipsum...']); $embed_attribute = new EmbeddedEntityListAttribute(self::ATTR_NAME, $this->getTypeMock(), [EmbeddedEntityListAttribute::OPTION_ENTITY_TYPES => [ParagraphType::CLASS]]); $value = $embed_attribute->createValueHolder(); $value->addValueChangedListener($listener); $entity_list = $value->getValue(); $entity_list->push($embedd_entity); $embedd_entity->setValue('title', 'Kthxbye'); $this->assertInstanceOf(EntityList::CLASS, $entity_list); $this->assertEquals(1, $entity_list->getSize()); }
protected function createEmbeddedTypeMap() { $entity_type_map = parent::createEmbeddedTypeMap(); foreach ($entity_type_map as $embedded_type) { $entity_implementor = $embedded_type->getEntityImplementor(); $entity_reflection = new ReflectionClass($entity_implementor); if (!$entity_reflection->implementsInterface(EntityReferenceInterface::CLASS)) { throw new RuntimeException(sprintf('Invalid reference-type (%s) given to %s. Only instance of %s accepted.', $this->getName(), $entity_implementor, EntityReferenceInterface::CLASS)); } } return $entity_type_map; }
protected function buildFieldFilterSpec(EmbeddedEntityListAttribute $embed_attribute) { $filter_parts = []; $parent_attribute = $embed_attribute->getParent(); while ($parent_attribute) { $filter_parts[] = $parent_attribute->getName(); $parent_attribute = $parent_attribute->getParent(); } $filter_parts[] = $embed_attribute->getName(); $filter_parts[] = 'referenced_identifier'; return implode('.', $filter_parts); }
/** * Generates and adds fake data for a embed entities. * * @param EntityInterface $entity an instance of the entity to fill with fake data. * @param EmbeddedEntityListAttribute $attribute instance of the EmbeddedEntityListAttribute to fill with fake data. * @param array $options array of options to customize fake data creation. * * @return void */ protected function addEmbeddedEntityList(EntityInterface $entity, EmbeddedEntityListAttribute $attribute, array $options = array()) { $options_clone = $options; $entity_collection = new EntityList(); $embedded_type_map = $attribute->getEmbeddedEntityTypeMap(); $min_count = $attribute->getOption('min_count', 0); $max_count = $attribute->getOption('max_count', 3); $inline_mode = $attribute->getOption('inline_mode', false); if (true === $inline_mode) { $number_of_new_embed_entries = 1; } else { $number_of_new_embed_entries = $this->faker->numberBetween($min_count, $max_count); } // add new entities to collection for embed types for ($i = 0; $i < $number_of_new_embed_entries; $i++) { $embed_type = $this->faker->randomElement($embedded_type_map->getValues()); $new_entity = $this->createFakeEntity($embed_type, $options_clone, $entity); $entity_collection->addItem($new_entity); } $this->setValue($entity, $attribute, $entity_collection, $options); }
/** * @return array */ protected function getEmbeddedCommands(EmbeddedEntityListAttribute $attribute, array $values, EntityInterface $parent_entity = null) { $errors = []; $affected_identifiers = []; $attribute_name = $attribute->getName(); $embedded_entity_list = $parent_entity ? $parent_entity->getValue($attribute_name) : new EntityList(); $builder_list = new CommandBuilderList(); foreach ($values as $position => $embedded_values) { if (!isset($embedded_values['@type'])) { $value_path = sprintf('%s.%d.@type', $attribute_name, $position); $errors[$value_path]['@incidents'][] = ['path' => $attribute->getPath(), 'incidents' => ['invalid_type' => ['reason' => 'missing']]]; continue; } $embed_type_prefix = $embedded_values['@type']; unset($embedded_values['@type']); $embed_type = $attribute->getEmbeddedTypeByPrefix($embed_type_prefix); if (!$embed_type) { $value_path = sprintf('%s.%d.@type', $attribute_name, $position); $errors[$value_path]['@incidents'][] = ['path' => $attribute->getPath(), 'incidents' => ['invalid_type' => ['reason' => 'unknown']]]; continue; } /* * Filter entities from the entity by incoming payload identifiers. If the * identifier is not matched then prepare an 'add' command, otherwise a 'modify'. */ $affected_entity = $embedded_entity_list->filter(function ($embedded_entity) use($embedded_values) { return $embedded_entity instanceof EntityInterface && isset($embedded_values['identifier']) && $embedded_entity->getIdentifier() === $embedded_values['identifier']; })->getFirst(); if (!$affected_entity) { $builder_list->push((new self($embed_type, AddEmbeddedEntityCommand::CLASS))->withParentAttributeName($attribute_name)->withPosition($position)->withValues($embedded_values)); } else { $affected_identifiers[] = $affected_entity->getIdentifier(); $modified_values = $this->filterUnmodifiedValues($affected_entity, $embedded_values); // prepare a modify command if values or position has changed if (!empty($modified_values) || $embedded_entity_list->getKey($affected_entity) != $position) { $builder_list->push((new self($embed_type, ModifyEmbeddedEntityCommand::CLASS))->fromEntity($affected_entity)->withParentAttributeName($attribute_name)->withPosition($position)->withValues($modified_values)); } } } /* * Iterate the attribute entity list and prepare remove commands for * any embedded entities with no incoming payload, or compensate for commands * which already exist. */ foreach ($embedded_entity_list as $embedded_entity) { // if an entity is not found in the payload then we do compensation checks to make // sure we don't inadvertently add an existing entity if (!in_array($embedded_entity->getIdentifier(), $affected_identifiers)) { // look for any add command which has no difference in values for the current entity $command_key = null; foreach ($builder_list as $key => $command_builder) { if ($command_builder->getCommandClass() === AddEmbeddedEntityCommand::CLASS && empty($this->filterUnmodifiedValues($embedded_entity, $command_builder->getValues()))) { $command_key = $key; break; } } if (!is_null($command_key)) { // remove the unnecessary add command if the entity already exists in the entity $builder_list->splice($command_key); } else { // the entity was not found in the payload so we can prepare removal $builder_list->push((new self($embedded_entity->getType(), RemoveEmbeddedEntityCommand::CLASS))->fromEntity($embedded_entity)->withParentAttributeName($attribute_name)); } } } $build_result = $builder_list->build(); if (!empty($errors)) { if ($build_result instanceof Error) { $errors = array_merge($errors, $build_result->get()); } return Error::unit($errors); } return $build_result; }
public function testGetEmbedByPrefix() { $embed_attribute = new EmbeddedEntityListAttribute(self::ATTR_NAME, $this->getTypeMock(), [EmbeddedEntityListAttribute::OPTION_ENTITY_TYPES => [WorkflowStateType::CLASS]]); $workflow_state_type = $embed_attribute->getEmbeddedTypeByPrefix('workflow_state'); $this->assertInstanceOf(WorkflowStateType::CLASS, $workflow_state_type); }