/** * {@inheritdoc} */ public function getDerivativeDefinitions($base_plugin_definition) { foreach ($this->typedDataManager->getDefinitions() as $data_type_id => $data_type_definition) { if (is_subclass_of($data_type_definition['class'], ComplexDataInterface::class, TRUE)) { /** @var \Drupal\Core\TypedData\ComplexDataDefinitionInterface $base_definition */ $base_definition = $this->typedDataManager->createDataDefinition($data_type_id); foreach ($base_definition->getPropertyDefinitions() as $property_name => $property_definition) { if ($property_definition instanceof BaseFieldDefinition || $property_definition instanceof FieldConfig) { $this->generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, $base_definition, $property_name, $property_definition); } } } } return $this->derivatives; }
/** * @cover \Drupal\rules\Plugin\TypedDataFilter\FormatDateFilter */ public function testFormatDateFilter() { $filter = $this->dataFilterManager->createInstance('format_date'); $data = $this->typedDataManager->create(DataDefinition::create('timestamp'), 3700); $this->assertTrue($filter->canFilter($data->getDataDefinition())); $this->assertFalse($filter->canFilter(DataDefinition::create('any'))); $this->assertEquals('string', $filter->filtersTo($data->getDataDefinition(), [])->getDataType()); $fails = $filter->validateArguments($data->getDataDefinition(), []); $this->assertEquals(0, count($fails)); $fails = $filter->validateArguments($data->getDataDefinition(), ['medium']); $this->assertEquals(0, count($fails)); $fails = $filter->validateArguments($data->getDataDefinition(), ['invalid-format']); $this->assertEquals(1, count($fails)); $fails = $filter->validateArguments($data->getDataDefinition(), ['custom']); $this->assertEquals(1, count($fails)); $fails = $filter->validateArguments($data->getDataDefinition(), ['custom', 'Y']); $this->assertEquals(0, count($fails)); /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */ $date_formatter = $this->container->get('date.formatter'); $this->assertEquals($date_formatter->format(3700), $filter->filter($data->getDataDefinition(), $data->getValue(), [])); $this->assertEquals($date_formatter->format(3700, 'short'), $filter->filter($data->getDataDefinition(), $data->getValue(), ['short'])); $this->assertEquals('1970', $filter->filter($data->getDataDefinition(), $data->getValue(), ['custom', 'Y'])); // Verify the filter works with non-timestamp data as well. $data = $this->typedDataManager->create(DataDefinition::create('datetime_iso8601'), "1970-01-01T10:10:10+00:00"); $this->assertTrue($filter->canFilter($data->getDataDefinition())); $this->assertEquals('string', $filter->filtersTo($data->getDataDefinition(), [])->getDataType()); $this->assertEquals('1970', $filter->filter($data->getDataDefinition(), $data->getValue(), ['custom', 'Y'])); // Test cache dependencies of date format config entities are added in. $metadata = new BubbleableMetadata(); $filter->filter($data->getDataDefinition(), $data->getValue(), ['short'], $metadata); $this->assertEquals(DateFormat::load('short')->getCacheTags(), $metadata->getCacheTags()); $metadata = new BubbleableMetadata(); $filter->filter($data->getDataDefinition(), $data->getValue(), ['custom', 'Y'], $metadata); $this->assertEquals([], $metadata->getCacheTags()); }
/** * Tests the getAllBundleInfo() method. * * @covers ::getAllBundleInfo */ public function testGetAllBundleInfo() { $this->moduleHandler->invokeAll('entity_bundle_info')->willReturn([]); $this->moduleHandler->alter('entity_bundle_info', Argument::type('array'))->willReturn(NULL); $apple = $this->prophesize(EntityTypeInterface::class); $apple->getLabel()->willReturn('Apple'); $apple->getBundleOf()->willReturn(NULL); $banana = $this->prophesize(EntityTypeInterface::class); $banana->getLabel()->willReturn('Banana'); $banana->getBundleOf()->willReturn(NULL); $this->setUpEntityTypeDefinitions(['apple' => $apple, 'banana' => $banana]); $this->cacheBackend->get('entity_bundle_info:en')->willReturn(FALSE); $this->cacheBackend->set('entity_bundle_info:en', Argument::any(), Cache::PERMANENT, ['entity_types', 'entity_bundles'])->will(function () { $this->get('entity_bundle_info:en')->willReturn((object) ['data' => 'cached data'])->shouldBeCalled(); })->shouldBeCalled(); $this->cacheTagsInvalidator->invalidateTags(['entity_bundles'])->shouldBeCalled(); $this->typedDataManager->clearCachedDefinitions()->shouldBeCalled(); $expected = ['apple' => ['apple' => ['label' => 'Apple']], 'banana' => ['banana' => ['label' => 'Banana']]]; $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame($expected, $bundle_info); $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame($expected, $bundle_info); $this->entityTypeBundleInfo->clearCachedBundles(); $bundle_info = $this->entityTypeBundleInfo->getAllBundleInfo(); $this->assertSame('cached data', $bundle_info); }
/** * {@inheritdoc} */ public function clearCachedBundles() { $this->bundleInfo = []; Cache::invalidateTags(['entity_bundles']); // Entity bundles are exposed as data types, clear that cache too. $this->typedDataManager->clearCachedDefinitions(); }
/** * Returns a typed data object. * * This helper for quick creation of typed data objects. * * @param string $data_type * The data type to create an object for. * @param mixed[] $value * The value to set. * * @return \Drupal\Core\TypedData\TypedDataInterface * The created object. */ protected function getTypedData($data_type, $value) { $definition = $this->typedDataManager->createDataDefinition($data_type); $data = $this->typedDataManager->create($definition); $data->setValue($value); return $data; }
/** * Tests the clearCachedFieldDefinitions() method. * * @covers ::clearCachedFieldDefinitions */ public function testClearCachedFieldDefinitions() { $this->setUpEntityTypeDefinitions(); $this->cacheTagsInvalidator->invalidateTags(['entity_field_info'])->shouldBeCalled(); $this->container->get('cache_tags.invalidator')->willReturn($this->cacheTagsInvalidator->reveal())->shouldBeCalled(); $this->typedDataManager->clearCachedDefinitions()->shouldBeCalled(); $this->entityFieldManager->clearCachedFieldDefinitions(); }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $cached_values = $form_state->getTemporaryValue('wizard'); $this->machine_name = $cached_values['id']; $form['items'] = array('#type' => 'markup', '#prefix' => '<div id="configured-contexts">', '#suffix' => '</div>', '#theme' => 'table', '#header' => array($this->t('Context ID'), $this->t('Label'), $this->t('Data Type'), $this->t('Options')), '#rows' => $this->renderRows($cached_values), '#empty' => t('No contexts or relationships have been added.')); foreach ($this->typedDataManager->getDefinitions() as $type => $definition) { $types[$type] = $definition['label']; } if (isset($types['entity'])) { unset($types['entity']); } asort($types); $form['context'] = ['#type' => 'select', '#options' => $types]; $form['add'] = ['#type' => 'submit', '#name' => 'add', '#value' => $this->t('Add new context'), '#ajax' => ['callback' => [$this, 'addContext'], 'event' => 'click'], '#submit' => ['callback' => [$this, 'submitForm']]]; $form['relationships'] = ['#type' => 'select', '#title' => $this->t('Add a relationship'), '#options' => $this->getAvailableRelationships($cached_values), '#access' => $this->relationships]; $form['add_relationship'] = ['#type' => 'submit', '#name' => 'add_relationship', '#value' => t('Add Relationship'), '#ajax' => ['callback' => [$this, 'addRelationship'], 'event' => 'click'], '#submit' => ['callback' => [$this, 'submitForm']], '#access' => $this->relationships]; return $form; }
/** * {@inheritdoc} */ public function clearCachedFieldDefinitions() { $this->baseFieldDefinitions = []; $this->fieldDefinitions = []; $this->fieldStorageDefinitions = []; $this->fieldMap = []; $this->fieldMapByFieldType = []; $this->entityDisplayRepository->clearDisplayModeInfo(); $this->extraFields = []; Cache::invalidateTags(['entity_field_info']); // The typed data manager statically caches prototype objects with injected // definitions, clear those as well. $this->typedDataManager->clearCachedDefinitions(); }
/** * Builds an array of options for the parameter type. * * @return array[] * A multidimensional array. The top level is keyed by group ('Content', * 'Configuration', 'Typed Data'). Those values are an array of type labels, * keyed by the machine name. */ protected function buildParameterTypeOptions() { $options = [static::NO_CONTEXT_KEY => $this->t('No context selected')]; // Make a grouped, sorted list of entity type options. Key the inner array // to use the typed data format of 'entity:$entity_type_id'. foreach ($this->entityTypeRepository->getEntityTypeLabels(TRUE) as $group_label => $grouped_options) { foreach ($grouped_options as $key => $label) { $options[$group_label]['entity:' . $key] = $label; } } $primitives_label = (string) $this->t('Primitives'); foreach ($this->typedDataManager->getDefinitions() as $key => $definition) { if (is_subclass_of($definition['class'], PrimitiveInterface::class)) { $options[$primitives_label][$key] = $definition['label']; } } asort($options[$primitives_label], SORT_NATURAL); return $options; }
/** * @cover replacePlaceHolders */ public function testApplyingFilters() { $this->node->field_integer = [1, 2, NULL]; $this->node->title->value = NULL; $result = $this->placeholderResolver->replacePlaceHolders("test {{node.field_integer.2.value|default('0')}}", ['node' => $this->node->getTypedData()]); $this->assertEquals('test 0', $result); $result = $this->placeholderResolver->replacePlaceHolders("test {{node.title.value|default('tEsT')|lower}}", ['node' => $this->node->getTypedData()]); $this->assertEquals('test test', $result); // Test filter expressions with whitespaces. $result = $this->placeholderResolver->replacePlaceHolders("test {{ node.title.value | default('tEsT') | lower }}", ['node' => $this->node->getTypedData()]); $this->assertEquals('test test', $result); // Test a filter expression on data without accessing a property. $text = 'test {{string | lower}}'; $result = $this->placeholderResolver->replacePlaceHolders($text, ['string' => $this->typedDataManager->create(DataDefinition::create('string'), 'Replacement')]); $this->assertEquals('test replacement', $result); $text = "The year is {{ date | format_date('custom', 'Y') }}."; $result = $this->placeholderResolver->replacePlaceHolders($text, ['date' => $this->typedDataManager->create(DataDefinition::create('timestamp'), '3600')]); $this->assertEquals('The year is 1970.', $result); }
/** * Extracts an array of tokens and labels of the required data type. * * This method can specify a data type to extract from contexts. A classic * example of this would be wanting to find all the 'entity_reference' * properties on an entity. This method will iterate over all supplied * contexts returning an array of tokens of type 'entity_reference' with a * corresponding label that denotes their relationship to the provided * array of contexts. * * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts * The array of contexts with which we are currently dealing. * @param mixed string|array $data_types * Data types to extract from the array of contexts. * * @return array * An array of token keys and corresponding labels. */ public function getTokensOfDataType($contexts, $data_types) { if (!is_array($data_types)) { $data_types = [$data_types]; } $tokens = []; foreach ($contexts as $context_id => $context) { $data_definition = $this->manager->createDataDefinition($context->getContextDefinition()->getDataType()); /** * @var \Drupal\Core\Field\BaseFieldDefinition $property */ if ($data_definition instanceof ComplexDataDefinitionInterface) { foreach ($data_definition->getPropertyDefinitions() as $property_name => $property) { if (in_array($property->getType(), $data_types)) { $tokens["{$context_id}:{$property_name}"] = $this->getRelatedPropertyLabel($property, $context, $context_id); } } } } return $tokens; }
/** * {@inheritdoc} */ public function createFieldItem(FieldItemListInterface $items, $index, $values = NULL) { // Leverage prototyping of the Typed Data API for fast instantiation. return $this->typedDataManager->getPropertyInstance($items, $index, $values); }
/** * @covers ::fetchDefinitionByPropertyPath * @expectedException \InvalidArgumentException * @expectedExceptionMessage The data selector 'unknown_property' cannot be applied because the definition of type 'integer' is not a list or a complex structure */ public function testFetchingAtInvalidPosition() { $list_definition = $this->typedDataManager->createListDataDefinition('integer'); // This should trigger an exception. $this->dataFetcher->fetchDefinitionByPropertyPath($list_definition, 'unknown_property'); }
/** * @cover fetchDataByPropertyPath * @expectedException \Drupal\Core\TypedData\Exception\MissingDataException * @expectedExceptionMessageRegExp #Unable to apply data selector 'field_integer.0.value' at 'field_integer':.*# */ public function testFetchingFromEmptyData() { $data_empty = $this->typedDataManager->create(EntityDataDefinition::create('node')); // This should trigger an exception. $this->dataFetcher->fetchDataByPropertyPath($data_empty, 'field_integer.0.value')->getValue(); }