Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Posts an article with a taxonomy term and a date prior to 1970.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class EarlyDateTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['node', 'datetime'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create a tags vocabulary for the 'article' content type.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Tags',
|
||||
'vid' => 'tags',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
$field_name = 'field_' . $vocabulary->id();
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$vocabulary->id() => $vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $field_name, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
\Drupal::service('entity_display.repository')
|
||||
->getFormDisplay('node', 'article')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
])
|
||||
->save();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'administer nodes',
|
||||
'bypass node access',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests taxonomy functionality with nodes prior to 1970.
|
||||
*/
|
||||
public function testTaxonomyEarlyDateNode(): void {
|
||||
// Posts an article with a taxonomy term and a date prior to 1970.
|
||||
$date = new DrupalDateTime('1969-01-01 00:00:00');
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['created[0][value][date]'] = $date->format('Y-m-d');
|
||||
$edit['created[0][value][time]'] = $date->format('H:i:s');
|
||||
$edit['body[0][value]'] = $this->randomMachineName();
|
||||
$edit['field_tags[target_id]'] = $this->randomMachineName();
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
// Checks that the node has been saved.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$this->assertEquals($date->getTimestamp(), $node->getCreatedTime(), 'Legacy node was saved with the right date.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
|
||||
|
||||
/**
|
||||
* Generic module test for taxonomy.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class GenericTest extends GenericModuleTestBase {}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermJsonAnonTest extends TermResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermJsonBasicAuthTest extends TermResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
* @group #slow
|
||||
*/
|
||||
class TermJsonCookieTest extends TermResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,404 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use PHPUnit\Framework\Attributes\Before;
|
||||
|
||||
/**
|
||||
* Resource test base for taxonomy term entity.
|
||||
*/
|
||||
abstract class TermResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['content_translation', 'path', 'taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'taxonomy_term';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed' => NULL,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Drupal\taxonomy\TermInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* Marks some tests as skipped because XML cannot be deserialized.
|
||||
*/
|
||||
#[Before]
|
||||
public function termResourceTestBaseSkipTests(): void {
|
||||
if (static::$format === 'xml' && $this->name() === 'testPatchPath') {
|
||||
$this->markTestSkipped('Deserialization of the XML format is not supported.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->grantPermissionsToTestedRole(['access content']);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$this->grantPermissionsToTestedRole(['create terms in camelids']);
|
||||
break;
|
||||
|
||||
case 'PATCH':
|
||||
// Grant the 'create url aliases' permission to test the case when
|
||||
// the path field is accessible, see
|
||||
// \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase
|
||||
// for a negative test.
|
||||
$this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['delete terms in camelids']);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$vocabulary = Vocabulary::load('camelids');
|
||||
if (!$vocabulary) {
|
||||
// Create a "Camelids" vocabulary.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Camelids',
|
||||
'vid' => 'camelids',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
}
|
||||
|
||||
// Create a "Llama" taxonomy term.
|
||||
$term = Term::create(['vid' => $vocabulary->id()])
|
||||
->setName('Llama')
|
||||
->setDescription("It is a little known fact that llamas cannot count higher than seven.")
|
||||
->setChangedTime(123456789)
|
||||
->set('path', '/llama');
|
||||
$term->save();
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
// We test with multiple parent terms, and combinations thereof.
|
||||
// @see ::createEntity()
|
||||
// @see ::testGet()
|
||||
// @see ::testGetTermWithParent()
|
||||
// @see ::providerTestGetTermWithParent()
|
||||
$parent_term_ids = [];
|
||||
for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
|
||||
$parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
|
||||
}
|
||||
|
||||
$expected_parent_normalization = FALSE;
|
||||
switch ($parent_term_ids) {
|
||||
case [0]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => NULL,
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case [2]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => 2,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(2)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/2',
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case [0, 2]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => NULL,
|
||||
],
|
||||
[
|
||||
'target_id' => 2,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(2)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/2',
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case [3, 2]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => 3,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(3)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/3',
|
||||
],
|
||||
[
|
||||
'target_id' => 2,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(2)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/2',
|
||||
],
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
'tid' => [
|
||||
['value' => 1],
|
||||
],
|
||||
'revision_id' => [
|
||||
['value' => 1],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $this->entity->uuid()],
|
||||
],
|
||||
'vid' => [
|
||||
[
|
||||
'target_id' => 'camelids',
|
||||
'target_type' => 'taxonomy_vocabulary',
|
||||
'target_uuid' => Vocabulary::load('camelids')->uuid(),
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
['value' => 'Llama'],
|
||||
],
|
||||
'description' => [
|
||||
[
|
||||
'value' => 'It is a little known fact that llamas cannot count higher than seven.',
|
||||
'format' => NULL,
|
||||
'processed' => "<p>It is a little known fact that llamas cannot count higher than seven.</p>\n",
|
||||
],
|
||||
],
|
||||
'parent' => $expected_parent_normalization,
|
||||
'weight' => [
|
||||
['value' => 0],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'changed' => [
|
||||
[
|
||||
'value' => (new \DateTime())->setTimestamp($this->entity->getChangedTime())->setTimezone(new \DateTimeZone('UTC'))->format(\DateTime::RFC3339),
|
||||
'format' => \DateTime::RFC3339,
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'path' => [
|
||||
[
|
||||
'alias' => '/llama',
|
||||
'pid' => 1,
|
||||
'langcode' => 'en',
|
||||
],
|
||||
],
|
||||
'status' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'revision_created' => [
|
||||
[
|
||||
'value' => (new \DateTime())->setTimestamp((int) $this->entity->getRevisionCreationTime())
|
||||
->setTimezone(new \DateTimeZone('UTC'))
|
||||
->format(\DateTime::RFC3339),
|
||||
'format' => \DateTime::RFC3339,
|
||||
],
|
||||
],
|
||||
'revision_user' => [],
|
||||
'revision_translation_affected' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'vid' => [
|
||||
[
|
||||
'target_id' => 'camelids',
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
[
|
||||
'value' => 'Drama llama',
|
||||
],
|
||||
],
|
||||
'description' => [
|
||||
[
|
||||
'value' => 'Drama llamas are the coolest camelids.',
|
||||
'format' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
return "The 'access content' permission is required and the taxonomy term must be published.";
|
||||
|
||||
case 'POST':
|
||||
return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
|
||||
|
||||
case 'PATCH':
|
||||
return "The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.";
|
||||
|
||||
case 'DELETE':
|
||||
return "The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.";
|
||||
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests PATCHing a term's path.
|
||||
*
|
||||
* For a negative test, see the similar test coverage for Node.
|
||||
*
|
||||
* @see \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase::testPatchPath()
|
||||
*/
|
||||
public function testPatchPath(): void {
|
||||
$this->initAuthentication();
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$this->setUpAuthorization('PATCH');
|
||||
|
||||
$url = $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]);
|
||||
|
||||
// GET term's current normalization.
|
||||
$response = $this->request('GET', $url, $this->getAuthenticationRequestOptions('GET'));
|
||||
$normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
|
||||
// Change term's path alias.
|
||||
$normalization['path'][0]['alias'] .= 's-rule-the-world';
|
||||
|
||||
// Create term PATCH request.
|
||||
$request_options = [];
|
||||
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// PATCH request: 200.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$updated_normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
$this->assertSame($normalization['path'], $updated_normalization['path']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text', 'config:filter.settings']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests GETting a term with a parent term other than the default <root> (0).
|
||||
*
|
||||
* @see ::getExpectedNormalizedEntity()
|
||||
*
|
||||
* @dataProvider providerTestGetTermWithParent
|
||||
*/
|
||||
public function testGetTermWithParent(array $parent_term_ids): void {
|
||||
// Create all possible parent terms.
|
||||
Term::create(['vid' => Vocabulary::load('camelids')->id()])
|
||||
->setName('Lamoids')
|
||||
->save();
|
||||
Term::create(['vid' => Vocabulary::load('camelids')->id()])
|
||||
->setName('Camels')
|
||||
->save();
|
||||
|
||||
// Modify the entity under test to use the provided parent terms.
|
||||
$this->entity->set('parent', $parent_term_ids)->save();
|
||||
|
||||
$this->initAuthentication();
|
||||
$url = $this->getEntityResourceUrl();
|
||||
$url->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = $this->getAuthenticationRequestOptions('GET');
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$expected = $this->getExpectedNormalizedEntity();
|
||||
static::recursiveKSort($expected);
|
||||
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
static::recursiveKSort($actual);
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testGetTermWithParent().
|
||||
*/
|
||||
public static function providerTestGetTermWithParent() {
|
||||
return [
|
||||
'root parent: [0] (= no parent)' => [
|
||||
[0],
|
||||
],
|
||||
'non-root parent: [2]' => [
|
||||
[2],
|
||||
],
|
||||
'multiple parents: [0,2] (root + non-root parent)' => [
|
||||
[0, 2],
|
||||
],
|
||||
'multiple parents: [3,2] (both non-root parents)' => [
|
||||
[3, 2],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedEntityAccessCacheability($is_authenticated) {
|
||||
// @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedEntityAccessCacheability($is_authenticated)
|
||||
->addCacheTags(['taxonomy_term:1']);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermXmlAnonTest extends TermResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermXmlBasicAuthTest extends TermResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermXmlCookieTest extends TermResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyJsonAnonTest extends VocabularyResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyJsonBasicAuthTest extends VocabularyResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyJsonCookieTest extends VocabularyResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigEntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* Resource test base for the TaxonomyVocabulary entity.
|
||||
*/
|
||||
abstract class VocabularyResourceTestBase extends ConfigEntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'taxonomy_vocabulary';
|
||||
|
||||
/**
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer taxonomy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Llama',
|
||||
'vid' => 'llama',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
return $vocabulary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'vid' => 'llama',
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'dependencies' => [],
|
||||
'name' => 'Llama',
|
||||
'description' => NULL,
|
||||
'weight' => 0,
|
||||
'new_revision' => FALSE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($method === 'GET') {
|
||||
return "The following permissions are required: 'access taxonomy overview' OR 'administer taxonomy'.";
|
||||
}
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyXmlAnonTest extends VocabularyResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyXmlBasicAuthTest extends VocabularyResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyXmlCookieTest extends VocabularyResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
146
web/core/modules/taxonomy/tests/src/Functional/RssTest.php
Normal file
146
web/core/modules/taxonomy/tests/src/Functional/RssTest.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy RSS display.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class RssTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['node', 'field_ui', 'views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* Name of the taxonomy term reference field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'bypass node access',
|
||||
'administer content types',
|
||||
'administer node display',
|
||||
]));
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
$this->fieldName = 'taxonomy_' . $this->vocabulary->id();
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $this->fieldName, '', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($this->fieldName, [
|
||||
'type' => 'options_select',
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($this->fieldName, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that terms added to nodes are displayed in core RSS feed.
|
||||
*
|
||||
* Create a node and assert that taxonomy terms appear in rss.xml.
|
||||
*/
|
||||
public function testTaxonomyRss(): void {
|
||||
// Create two taxonomy terms.
|
||||
$term1 = $this->createTerm($this->vocabulary);
|
||||
|
||||
// Add the RSS display.
|
||||
$default_display = $this->container->get('entity_display.repository')->getViewDisplay('node', 'article');
|
||||
$rss_display = $default_display->createCopy('rss');
|
||||
$rss_display->save();
|
||||
|
||||
// Change the format to 'RSS category'.
|
||||
$rss_display->setComponent('taxonomy_' . $this->vocabulary->id(), [
|
||||
'type' => 'entity_reference_rss_category',
|
||||
'region' => 'content',
|
||||
]);
|
||||
$rss_display->save();
|
||||
|
||||
// Create an article.
|
||||
$node = $this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
$this->fieldName => $term1->id(),
|
||||
]);
|
||||
|
||||
// Check that the term is displayed when the RSS feed is viewed.
|
||||
$this->drupalGet('rss.xml');
|
||||
$test_element = sprintf(
|
||||
'<category %s>%s</category>',
|
||||
'domain="' . $term1->toUrl('canonical', ['absolute' => TRUE])->toString() . '"',
|
||||
$term1->getName()
|
||||
);
|
||||
$this->assertSession()->responseContains($test_element);
|
||||
|
||||
// Test that the feed icon exists for the term.
|
||||
$this->drupalGet("taxonomy/term/{$term1->id()}");
|
||||
$this->assertSession()->linkByHrefExists("taxonomy/term/{$term1->id()}/feed");
|
||||
|
||||
// Test that the feed page exists for the term.
|
||||
$this->drupalGet("taxonomy/term/{$term1->id()}/feed");
|
||||
$assert = $this->assertSession();
|
||||
$assert->responseHeaderContains('Content-Type', 'application/rss+xml');
|
||||
// Ensure the RSS version is 2.0.
|
||||
$rss_array = $this->getSession()->getDriver()->find('rss');
|
||||
$this->assertEquals('2.0', reset($rss_array)->getAttribute('version'));
|
||||
|
||||
// Check that the "Exception value" is disabled by default.
|
||||
$this->drupalGet('taxonomy/term/all/feed');
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
// Set the exception value to 'all'.
|
||||
$view = Views::getView('taxonomy_term');
|
||||
$arguments = $view->getDisplay()->getOption('arguments');
|
||||
$arguments['tid']['exception']['value'] = 'all';
|
||||
$view->getDisplay()->overrideOption('arguments', $arguments);
|
||||
$view->storage->save();
|
||||
// Check the article is shown in the feed.
|
||||
$raw_xml = '<title>' . $node->label() . '</title>';
|
||||
$this->drupalGet('taxonomy/term/all/feed');
|
||||
$this->assertSession()->responseContains($raw_xml);
|
||||
// Unpublish the article and check that it is not shown in the feed.
|
||||
$node->setUnpublished()->save();
|
||||
$this->drupalGet('taxonomy/term/all/feed');
|
||||
$this->assertSession()->responseNotContains($raw_xml);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\TestFileCreationTrait;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\taxonomy\VocabularyInterface;
|
||||
|
||||
/**
|
||||
* Tests image upload on taxonomy terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyImageTest extends TaxonomyTestBase {
|
||||
|
||||
use TestFileCreationTrait {
|
||||
getTestFiles as drupalGetTestFiles;
|
||||
compareFiles as drupalCompareFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* The taxonomy vocabulary used for the test.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected VocabularyInterface $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['image'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
$entity_type = 'taxonomy_term';
|
||||
$name = 'field_test';
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $name,
|
||||
'entity_type' => $entity_type,
|
||||
'type' => 'image',
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => $name,
|
||||
'entity_type' => $entity_type,
|
||||
'bundle' => $this->vocabulary->id(),
|
||||
'settings' => [],
|
||||
])->save();
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
$display_repository->getFormDisplay($entity_type, $this->vocabulary->id())
|
||||
->setComponent($name, [
|
||||
'type' => 'image_image',
|
||||
'settings' => [],
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a file can be uploaded before the taxonomy term has a name.
|
||||
*/
|
||||
public function testTaxonomyImageUpload(): void {
|
||||
$user = $this->drupalCreateUser(['administer taxonomy']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$image = array_pop($files);
|
||||
|
||||
// Ensure that a file can be uploaded before taxonomy term has a name.
|
||||
$edit = [
|
||||
'files[field_test_0]' => \Drupal::service('file_system')->realpath($image->uri),
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->submitForm($edit, 'Upload');
|
||||
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(),
|
||||
'field_test[0][alt]' => $this->randomMachineName(),
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Created new term');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Taxonomy term revision delete form test.
|
||||
*
|
||||
* @group taxonomy
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Form\RevisionDeleteForm
|
||||
*/
|
||||
class TaxonomyRevisionDeleteTest extends BrowserTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'system',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $permissions = [
|
||||
'view term revisions in test',
|
||||
'delete all taxonomy revisions',
|
||||
];
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
private $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->vocabulary = $this->createVocabulary(['vid' => 'test', 'name' => 'Test']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests revision delete.
|
||||
*/
|
||||
public function testDeleteForm(): void {
|
||||
$termName = $this->randomMachineName();
|
||||
$entity = Term::create([
|
||||
'vid' => $this->vocabulary->id(),
|
||||
'name' => $termName,
|
||||
]);
|
||||
|
||||
$entity->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 4pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE);
|
||||
$entity->setNewRevision();
|
||||
$entity->save();
|
||||
$revisionId = $entity->getRevisionId();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser($this->permissions));
|
||||
|
||||
// Cannot delete latest revision.
|
||||
$this->drupalGet($entity->toUrl('revision-delete-form'));
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a new latest revision.
|
||||
$entity
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 5pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE)
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
// Reload the entity.
|
||||
$revision = \Drupal::entityTypeManager()->getStorage('taxonomy_term')
|
||||
->loadRevision($revisionId);
|
||||
$this->drupalGet($revision->toUrl('revision-delete-form'));
|
||||
$this->assertSession()->pageTextContains('Are you sure you want to delete the revision from Sun, 11 Jan 2009 - 16:00?');
|
||||
$this->assertSession()->buttonExists('Delete');
|
||||
$this->assertSession()->linkExists('Cancel');
|
||||
|
||||
$countRevisions = static function (): int {
|
||||
return (int) \Drupal::entityTypeManager()->getStorage('taxonomy_term')
|
||||
->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->allRevisions()
|
||||
->count()
|
||||
->execute();
|
||||
};
|
||||
|
||||
$count = $countRevisions();
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertEquals($count - 1, $countRevisions());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->addressEquals(sprintf('taxonomy/term/%s/revisions', $entity->id()));
|
||||
$this->assertSession()->pageTextContains(sprintf('Revision from Sun, 11 Jan 2009 - 16:00 of Test %s has been deleted.', $termName));
|
||||
$this->assertSession()->elementsCount('css', 'table tbody tr', 1);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Taxonomy term revision form test.
|
||||
*
|
||||
* @group taxonomy
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Form\RevisionRevertForm
|
||||
*/
|
||||
class TaxonomyRevisionRevertTest extends BrowserTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'system',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $permissions = [
|
||||
'view term revisions in test',
|
||||
'revert all taxonomy revisions',
|
||||
];
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
private $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->vocabulary = $this->createVocabulary(['vid' => 'test', 'name' => 'Test']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests revision revert.
|
||||
*/
|
||||
public function testRevertForm(): void {
|
||||
$termName = $this->randomMachineName();
|
||||
$entity = Term::create([
|
||||
'vid' => $this->vocabulary->id(),
|
||||
'name' => $termName,
|
||||
]);
|
||||
|
||||
$entity->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 4pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE);
|
||||
$entity->setNewRevision();
|
||||
$entity->save();
|
||||
$revisionId = $entity->getRevisionId();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser($this->permissions));
|
||||
|
||||
// Cannot revert latest revision.
|
||||
$this->drupalGet($entity->toUrl('revision-revert-form'));
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a new latest revision.
|
||||
$entity
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 5pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE)
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
// Reload the entity.
|
||||
$revision = \Drupal::entityTypeManager()->getStorage('taxonomy_term')
|
||||
->loadRevision($revisionId);
|
||||
$this->drupalGet($revision->toUrl('revision-revert-form'));
|
||||
$this->assertSession()->pageTextContains('Are you sure you want to revert to the revision from Sun, 11 Jan 2009 - 16:00?');
|
||||
$this->assertSession()->buttonExists('Revert');
|
||||
$this->assertSession()->linkExists('Cancel');
|
||||
|
||||
$countRevisions = static function (): int {
|
||||
return (int) \Drupal::entityTypeManager()->getStorage('taxonomy_term')
|
||||
->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->allRevisions()
|
||||
->count()
|
||||
->execute();
|
||||
};
|
||||
|
||||
$count = $countRevisions();
|
||||
$this->submitForm([], 'Revert');
|
||||
$this->assertEquals($count + 1, $countRevisions());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->addressEquals(sprintf('taxonomy/term/%s/revisions', $entity->id()));
|
||||
$this->assertSession()->pageTextContains(sprintf('Test %s has been reverted to the revision from Sun, 11 Jan 2009 - 16:00.', $termName));
|
||||
$this->assertSession()->elementsCount('css', 'table tbody tr', 3);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the new_revision setting of taxonomy vocabularies.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyRevisionTest extends BrowserTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'system',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests default revision settings on vocabularies.
|
||||
*/
|
||||
public function testVocabularyTermRevision(): void {
|
||||
$assert = $this->assertSession();
|
||||
$vocabulary1 = $this->createVocabulary(['new_revision' => TRUE]);
|
||||
$vocabulary2 = $this->createVocabulary(['new_revision' => FALSE]);
|
||||
$user = $this->createUser([
|
||||
'administer taxonomy',
|
||||
]);
|
||||
$term1 = $this->createTerm($vocabulary1);
|
||||
$term2 = $this->createTerm($vocabulary2);
|
||||
|
||||
// Create some revisions so revision checkbox is visible.
|
||||
$term1 = $this->createTaxonomyTermRevision($term1);
|
||||
$term2 = $this->createTaxonomyTermRevision($term2);
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet($term1->toUrl('edit-form'));
|
||||
$assert->statusCodeEquals(200);
|
||||
$assert->checkboxChecked('Create new revision');
|
||||
$this->drupalGet($term2->toUrl('edit-form'));
|
||||
$assert->statusCodeEquals(200);
|
||||
$assert->checkboxNotChecked('Create new revision');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Taxonomy term version history test.
|
||||
*
|
||||
* @group taxonomy
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Controller\VersionHistoryController
|
||||
*/
|
||||
class TaxonomyRevisionVersionHistoryTest extends BrowserTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'system',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $permissions = [
|
||||
'view term revisions in test',
|
||||
'revert all taxonomy revisions',
|
||||
'delete all taxonomy revisions',
|
||||
];
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
private $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->vocabulary = $this->createVocabulary(['vid' => 'test', 'name' => 'Test']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests version history page.
|
||||
*/
|
||||
public function testVersionHistory(): void {
|
||||
$entity = Term::create([
|
||||
'vid' => $this->vocabulary->id(),
|
||||
'name' => 'Test taxonomy term',
|
||||
]);
|
||||
|
||||
$entity
|
||||
->setDescription('Description 1')
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('1st June 2020 7am'))->getTimestamp())
|
||||
->setRevisionLogMessage('first revision log')
|
||||
->setRevisionUser($this->drupalCreateUser(name: 'first author'))
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
$entity
|
||||
->setDescription('Description 2')
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('2nd June 2020 8am'))->getTimestamp())
|
||||
->setRevisionLogMessage('second revision log')
|
||||
->setRevisionUser($this->drupalCreateUser(name: 'second author'))
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
$entity
|
||||
->setDescription('Description 3')
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('3rd June 2020 9am'))->getTimestamp())
|
||||
->setRevisionLogMessage('third revision log')
|
||||
->setRevisionUser($this->drupalCreateUser(name: 'third author'))
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser($this->permissions));
|
||||
$this->drupalGet($entity->toUrl('version-history'));
|
||||
$this->assertSession()->elementsCount('css', 'table tbody tr', 3);
|
||||
|
||||
// Order is newest to oldest revision by creation order.
|
||||
$row1 = $this->assertSession()->elementExists('css', 'table tbody tr:nth-child(1)');
|
||||
// Latest revision does not have revert or delete revision operation.
|
||||
$this->assertSession()->elementNotExists('named', ['link', 'Revert'], $row1);
|
||||
$this->assertSession()->elementNotExists('named', ['link', 'Delete'], $row1);
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(1)', 'Current revision');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(1)', 'third revision log');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(1)', '3 Jun 2020 - 09:00 by third author');
|
||||
|
||||
$row2 = $this->assertSession()->elementExists('css', 'table tbody tr:nth-child(2)');
|
||||
$this->assertSession()->elementExists('named', ['link', 'Revert'], $row2);
|
||||
$this->assertSession()->elementExists('named', ['link', 'Delete'], $row2);
|
||||
$this->assertSession()->elementTextNotContains('css', 'table tbody tr:nth-child(2)', 'Current revision');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(2)', 'second revision log');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(2)', '2 Jun 2020 - 08:00 by second author');
|
||||
|
||||
$row3 = $this->assertSession()->elementExists('css', 'table tbody tr:nth-child(3)');
|
||||
$this->assertSession()->elementExists('named', ['link', 'Revert'], $row3);
|
||||
$this->assertSession()->elementExists('named', ['link', 'Delete'], $row3);
|
||||
$this->assertSession()->elementTextNotContains('css', 'table tbody tr:nth-child(2)', 'Current revision');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(3)', 'first revision log');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(3)', '1 Jun 2020 - 07:00 by first author');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Tests taxonomy terms with Content Moderation.
|
||||
*
|
||||
* @group content_moderation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyTermContentModerationTest extends TaxonomyTestBase {
|
||||
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The vocabulary used for creating terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['content_moderation'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->createEditorialWorkflow();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'use editorial transition create_new_draft',
|
||||
'use editorial transition publish',
|
||||
'view any unpublished content',
|
||||
'view latest version',
|
||||
]));
|
||||
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
|
||||
// Set the vocabulary as moderated.
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('taxonomy_term', $this->vocabulary->id());
|
||||
$workflow->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests taxonomy term parents on a moderated vocabulary.
|
||||
*/
|
||||
public function testTaxonomyTermParents(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
// Create a simple hierarchy in the vocabulary, a root term and three parent
|
||||
// terms.
|
||||
$root = $this->createTerm($this->vocabulary, ['langcode' => 'en', 'moderation_state' => 'published']);
|
||||
$parent_1 = $this->createTerm($this->vocabulary, [
|
||||
'langcode' => 'en',
|
||||
'moderation_state' => 'published',
|
||||
'parent' => $root->id(),
|
||||
]);
|
||||
$parent_2 = $this->createTerm($this->vocabulary, [
|
||||
'langcode' => 'en',
|
||||
'moderation_state' => 'published',
|
||||
'parent' => $root->id(),
|
||||
]);
|
||||
$parent_3 = $this->createTerm($this->vocabulary, [
|
||||
'langcode' => 'en',
|
||||
'moderation_state' => 'published',
|
||||
'parent' => $root->id(),
|
||||
]);
|
||||
|
||||
// Create a child term and assign one of the parents above.
|
||||
$child = $this->createTerm($this->vocabulary, [
|
||||
'langcode' => 'en',
|
||||
'moderation_state' => 'published',
|
||||
'parent' => $parent_1->id(),
|
||||
]);
|
||||
|
||||
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
|
||||
$taxonomy_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
|
||||
$validation_message = 'You can only change the hierarchy for the published version of this term.';
|
||||
|
||||
// Add a pending revision without changing the term parent.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['moderation_state[0][state]' => 'draft'], 'Save');
|
||||
|
||||
$assert_session->pageTextNotContains($validation_message);
|
||||
|
||||
// Add a pending revision and change the parent.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['parent[]' => [$parent_2->id()], 'moderation_state[0][state]' => 'draft'], 'Save');
|
||||
|
||||
// Check that parents were not changed.
|
||||
$assert_session->pageTextContains($validation_message);
|
||||
$taxonomy_storage->resetCache();
|
||||
$this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
|
||||
|
||||
// Add a pending revision and add a new parent.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['parent[]' => [$parent_1->id(), $parent_3->id()], 'moderation_state[0][state]' => 'draft'], 'Save');
|
||||
|
||||
// Check that parents were not changed.
|
||||
$assert_session->pageTextContains($validation_message);
|
||||
$taxonomy_storage->resetCache();
|
||||
$this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
|
||||
|
||||
// Add a pending revision and use the root term as a parent.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['parent[]' => [$root->id()], 'moderation_state[0][state]' => 'draft'], 'Save');
|
||||
|
||||
// Check that parents were not changed.
|
||||
$assert_session->pageTextContains($validation_message);
|
||||
$taxonomy_storage->resetCache();
|
||||
$this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
|
||||
|
||||
// Add a pending revision and remove the parent.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['parent[]' => [], 'moderation_state[0][state]' => 'draft'], 'Save');
|
||||
|
||||
// Check that parents were not changed.
|
||||
$assert_session->pageTextContains($validation_message);
|
||||
$taxonomy_storage->resetCache();
|
||||
$this->assertEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
|
||||
|
||||
// Add a published revision.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['moderation_state[0][state]' => 'published'], 'Save');
|
||||
|
||||
// Change the parents.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['parent[]' => [$parent_2->id()]], 'Save');
|
||||
|
||||
// Check that parents were changed.
|
||||
$assert_session->pageTextNotContains($validation_message);
|
||||
$taxonomy_storage->resetCache();
|
||||
$this->assertNotEquals([$parent_1->id()], array_keys($taxonomy_storage->loadParents($child->id())));
|
||||
|
||||
// Add a pending revision and change the weight.
|
||||
$this->drupalGet($child->toUrl('edit-form'));
|
||||
$this->submitForm(['weight' => 10, 'moderation_state[0][state]' => 'draft'], 'Save');
|
||||
|
||||
// Check that weight was not changed.
|
||||
$assert_session->pageTextContains($validation_message);
|
||||
|
||||
// Add a new term without any parent and publish it.
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(),
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalGet(Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $this->vocabulary->id()]));
|
||||
$this->submitForm($edit, 'Save');
|
||||
// Add a pending revision without any changes.
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['name' => $edit['name[0][value]']]);
|
||||
$term = reset($terms);
|
||||
$this->drupalGet($term->toUrl('edit-form'));
|
||||
$this->submitForm(['moderation_state[0][state]' => 'draft'], 'Save');
|
||||
$assert_session->pageTextNotContains($validation_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests changing field values in pending revisions of taxonomy terms.
|
||||
*/
|
||||
public function testTaxonomyTermPendingRevisions(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
$default_term_name = 'term - default revision';
|
||||
$default_term_description = 'The default revision of a term.';
|
||||
$term = $this->createTerm($this->vocabulary, [
|
||||
'name' => $default_term_name,
|
||||
'description' => $default_term_description,
|
||||
'langcode' => 'en',
|
||||
'moderation_state' => 'published',
|
||||
]);
|
||||
|
||||
// Add a pending revision without changing the term parent.
|
||||
$this->drupalGet($term->toUrl('edit-form'));
|
||||
$assert_session->pageTextContains($default_term_name);
|
||||
$assert_session->pageTextContains($default_term_description);
|
||||
|
||||
// Check the revision log message field appears on the term edit page.
|
||||
$this->drupalGet($term->toUrl('edit-form'));
|
||||
$assert_session->fieldExists('revision_log_message[0][value]');
|
||||
|
||||
$pending_term_name = 'term - pending revision';
|
||||
$pending_term_description = 'The pending revision of a term.';
|
||||
$edit = [
|
||||
'name[0][value]' => $pending_term_name,
|
||||
'description[0][value]' => $pending_term_description,
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalGet($term->toUrl('edit-form'));
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
$assert_session->pageTextContains($pending_term_name);
|
||||
$assert_session->pageTextContains($pending_term_description);
|
||||
$assert_session->pageTextNotContains($default_term_description);
|
||||
|
||||
// Check that the default revision of the term contains the correct values.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$assert_session->pageTextContains($default_term_name);
|
||||
$assert_session->pageTextContains($default_term_description);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
/**
|
||||
* Ensure that the term indentation works properly.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyTermIndentationTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'bypass node access',
|
||||
]));
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests term indentation.
|
||||
*/
|
||||
public function testTermIndentation(): void {
|
||||
$assert = $this->assertSession();
|
||||
// Create three taxonomy terms.
|
||||
$this->createTerm($this->vocabulary);
|
||||
$term2 = $this->createTerm($this->vocabulary);
|
||||
$this->createTerm($this->vocabulary);
|
||||
|
||||
// Get the taxonomy storage.
|
||||
$taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||
|
||||
// Indent the second term under the first one.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->get('vid') . '/overview');
|
||||
$hidden_edit = [
|
||||
'terms[tid:' . $term2->id() . ':0][term][tid]' => 2,
|
||||
'terms[tid:' . $term2->id() . ':0][term][parent]' => 1,
|
||||
'terms[tid:' . $term2->id() . ':0][term][depth]' => 1,
|
||||
];
|
||||
// Because we can't post hidden form elements, we have to change them in
|
||||
// code here, and then submit.
|
||||
foreach ($hidden_edit as $field => $value) {
|
||||
$node = $assert->hiddenFieldExists($field);
|
||||
$node->setValue($value);
|
||||
}
|
||||
$edit = [
|
||||
'terms[tid:' . $term2->id() . ':0][weight]' => 1,
|
||||
];
|
||||
// Submit the edited form and check for HTML indentation element presence.
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->responseMatches('|<div class="js-indentation indentation"> </div>|');
|
||||
|
||||
// Check explicitly that term 2's parent is term 1.
|
||||
$parents = $taxonomy_storage->loadParents($term2->id());
|
||||
$this->assertEquals(1, key($parents), 'Term 1 is the term 2\'s parent');
|
||||
|
||||
// Move the second term back out to the root level.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->get('vid') . '/overview');
|
||||
$hidden_edit = [
|
||||
'terms[tid:' . $term2->id() . ':0][term][tid]' => 2,
|
||||
'terms[tid:' . $term2->id() . ':0][term][parent]' => 0,
|
||||
'terms[tid:' . $term2->id() . ':0][term][depth]' => 0,
|
||||
];
|
||||
// Because we can't post hidden form elements, we have to change them in
|
||||
// code here, and then submit.
|
||||
foreach ($hidden_edit as $field => $value) {
|
||||
$node = $assert->hiddenFieldExists($field);
|
||||
$node->setValue($value);
|
||||
}
|
||||
$edit = [
|
||||
'terms[tid:' . $term2->id() . ':0][weight]' => 1,
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
// All terms back at the root level, no indentation should be present.
|
||||
$this->assertSession()->responseNotMatches('|<div class="js-indentation indentation"> </div>|');
|
||||
|
||||
// Check explicitly that term 2 has no parents.
|
||||
\Drupal::entityTypeManager()->getStorage('taxonomy_term')->resetCache();
|
||||
$parents = $taxonomy_storage->loadParents($term2->id());
|
||||
$this->assertEmpty($parents, 'Term 2 has no parents now');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
/**
|
||||
* Ensures that the term pager works properly.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyTermPagerTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'taxonomy_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'bypass node access',
|
||||
]));
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the pager is displayed properly on the term overview page.
|
||||
*/
|
||||
public function testTaxonomyTermOverviewPager(): void {
|
||||
// Set limit to 3 terms per page.
|
||||
$this->config('taxonomy.settings')
|
||||
->set('terms_per_page_admin', '3')
|
||||
->save();
|
||||
|
||||
// Create 3 terms.
|
||||
for ($x = 1; $x <= 3; $x++) {
|
||||
$this->createTerm($this->vocabulary);
|
||||
}
|
||||
|
||||
// Get Page 1.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
// Pager should not be visible.
|
||||
$this->assertSession()->responseNotMatches('|<nav class="pager" [^>]*>|');
|
||||
|
||||
// Create 3 more terms to show pager.
|
||||
for ($x = 1; $x <= 3; $x++) {
|
||||
$this->createTerm($this->vocabulary);
|
||||
}
|
||||
|
||||
// Ensure that pager is visible on page 1.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->responseMatches('|<nav class="pager" [^>]*>|');
|
||||
|
||||
// Ensure that pager is visible on page 2.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 1]]);
|
||||
$this->assertSession()->responseMatches('|<nav class="pager" [^>]*>|');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that overview page only loads the necessary terms.
|
||||
*/
|
||||
public function testTaxonomyTermOverviewTermLoad(): void {
|
||||
// Set limit to 3 terms per page.
|
||||
$this->config('taxonomy.settings')
|
||||
->set('terms_per_page_admin', '3')
|
||||
->save();
|
||||
|
||||
$state = $this->container->get('state');
|
||||
|
||||
// Create 5 terms.
|
||||
for ($x = 0; $x <= 10; $x++) {
|
||||
$this->createTerm($this->vocabulary, ['weight' => $x]);
|
||||
}
|
||||
|
||||
// Check the overview page.
|
||||
$state->set('taxonomy_test_taxonomy_term_load', []);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$loaded_terms = $state->get('taxonomy_test_taxonomy_term_load');
|
||||
$this->assertCount(4, $loaded_terms);
|
||||
|
||||
// Check the overview page for submit callback.
|
||||
$state->set('taxonomy_test_taxonomy_term_load', []);
|
||||
$this->submitForm([], 'Save');
|
||||
$loaded_terms = $state->get('taxonomy_test_taxonomy_term_load');
|
||||
$this->assertCount(4, $loaded_terms);
|
||||
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 2]]);
|
||||
$state->set('taxonomy_test_taxonomy_term_load', []);
|
||||
$this->submitForm([], 'Save');
|
||||
$loaded_terms = $state->get('taxonomy_test_taxonomy_term_load');
|
||||
$this->assertCount(4, $loaded_terms);
|
||||
|
||||
// Adding a new term with weight < 0 implies that all root terms are
|
||||
// updated.
|
||||
$this->createTerm($this->vocabulary, ['weight' => -1]);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 2]]);
|
||||
$state->set('taxonomy_test_taxonomy_term_load', []);
|
||||
$this->submitForm([], 'Save');
|
||||
$loaded_terms = $state->get('taxonomy_test_taxonomy_term_load');
|
||||
$this->assertCount(12, $loaded_terms);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Provides common helper methods for Taxonomy module tests.
|
||||
*/
|
||||
abstract class TaxonomyTestBase extends BrowserTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
use EntityReferenceFieldCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_block');
|
||||
|
||||
// Create Basic page and Article node types.
|
||||
if ($this->profile != 'standard') {
|
||||
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
|
||||
|
||||
/**
|
||||
* Provides common testing base for translated taxonomy terms.
|
||||
*/
|
||||
trait TaxonomyTranslationTestTrait {
|
||||
|
||||
use EntityReferenceFieldCreationTrait;
|
||||
|
||||
/**
|
||||
* The vocabulary.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Vocabulary
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* The field name for our taxonomy term field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $termFieldName = 'field_tag';
|
||||
|
||||
/**
|
||||
* The langcode of the source language.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseLangcode = 'en';
|
||||
|
||||
/**
|
||||
* Target langcode for translation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $translateToLangcode = 'hu';
|
||||
|
||||
/**
|
||||
* The node to check the translated value on.
|
||||
*
|
||||
* @var \Drupal\node\Entity\Node
|
||||
*/
|
||||
protected $node;
|
||||
|
||||
/**
|
||||
* Adds additional languages.
|
||||
*/
|
||||
protected function setupLanguages() {
|
||||
ConfigurableLanguage::createFromLangcode($this->translateToLangcode)->save();
|
||||
$this->rebuildContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables translations where it needed.
|
||||
*/
|
||||
protected function enableTranslation() {
|
||||
// Enable translation for the current entity type and ensure the change is
|
||||
// picked up.
|
||||
\Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE);
|
||||
\Drupal::service('content_translation.manager')->setEnabled('taxonomy_term', $this->vocabulary->id(), TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds term reference field for the article content type.
|
||||
*/
|
||||
protected function setUpTermReferenceField() {
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $this->termFieldName, '', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $this->termFieldName);
|
||||
$field_storage->setTranslatable(FALSE);
|
||||
$field_storage->save();
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($this->termFieldName, [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($this->termFieldName, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term access permissions.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermAccessTest extends TaxonomyTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests access control functionality for taxonomy terms.
|
||||
*/
|
||||
public function testTermAccess(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$vocabulary = $this->createVocabulary();
|
||||
|
||||
// Create two terms.
|
||||
$published_term = Term::create([
|
||||
'vid' => $vocabulary->id(),
|
||||
'name' => 'Published term',
|
||||
'status' => 1,
|
||||
]);
|
||||
$published_term->save();
|
||||
$unpublished_term = Term::create([
|
||||
'vid' => $vocabulary->id(),
|
||||
'name' => 'Unpublished term',
|
||||
'status' => 0,
|
||||
]);
|
||||
$unpublished_term->save();
|
||||
|
||||
// Start off logged in as admin.
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
|
||||
|
||||
// Test the 'administer taxonomy' permission.
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id());
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($published_term, 'view', TRUE);
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id());
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($unpublished_term, 'view', TRUE);
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($published_term, 'update', TRUE);
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($unpublished_term, 'update', TRUE);
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($published_term, 'delete', TRUE);
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($unpublished_term, 'delete', TRUE);
|
||||
|
||||
// Test the 'access content' permission.
|
||||
$this->drupalLogin($this->drupalCreateUser(['access content']));
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id());
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$this->assertTermAccess($published_term, 'view', TRUE);
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id());
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->assertTermAccess($unpublished_term, 'view', FALSE, "The 'access content' permission is required and the taxonomy term must be published.");
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->assertTermAccess($published_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->assertTermAccess($unpublished_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->assertTermAccess($published_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->assertTermAccess($unpublished_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
|
||||
|
||||
// Install the Views module and repeat the checks for the 'view' permission.
|
||||
\Drupal::service('module_installer')->install(['views'], TRUE);
|
||||
$this->rebuildContainer();
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $published_term->id());
|
||||
$assert_session->statusCodeEquals(200);
|
||||
|
||||
// @todo Change this assertion to expect a 403 status code when
|
||||
// https://www.drupal.org/project/drupal/issues/2983070 is fixed.
|
||||
$this->drupalGet('taxonomy/term/' . $unpublished_term->id());
|
||||
$assert_session->statusCodeEquals(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks access on taxonomy term.
|
||||
*
|
||||
* @param \Drupal\taxonomy\TermInterface $term
|
||||
* A taxonomy term entity.
|
||||
* @param string $access_operation
|
||||
* The entity operation, e.g. 'view', 'edit', 'delete', etc.
|
||||
* @param bool $access_allowed
|
||||
* Whether the current use has access to the given operation or not.
|
||||
* @param string $access_reason
|
||||
* (optional) The reason of the access result.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertTermAccess(TermInterface $term, string $access_operation, bool $access_allowed, string $access_reason = ''): void {
|
||||
$access_result = $term->access($access_operation, NULL, TRUE);
|
||||
$this->assertSame($access_allowed, $access_result->isAllowed());
|
||||
|
||||
if ($access_reason) {
|
||||
$this->assertSame($access_reason, $access_result->getReason());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests the autocomplete implementation of the taxonomy class.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermAutocompleteTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The vocabulary.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Vocabulary
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* The field to add to the content type for the taxonomy terms.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* The admin user.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* The autocomplete URL to call.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $autocompleteUrl;
|
||||
|
||||
/**
|
||||
* The term IDs indexed by term names.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $termIds;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create a vocabulary.
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
|
||||
// Create 11 terms, which have some sub-string in common, in a
|
||||
// non-alphabetical order, so that we will have more than 10 matches later
|
||||
// when we test the correct number of results is returned, and we can test
|
||||
// the order of the results. The location of the sub-string to match varies
|
||||
// also, since it should not be necessary to start with the sub-string to
|
||||
// match it. Save term IDs to reuse later.
|
||||
$termNames = [
|
||||
'aaa 20 bbb',
|
||||
'aaa 70 bbb',
|
||||
'aaa 10 bbb',
|
||||
'aaa 12 bbb',
|
||||
'aaa 40 bbb',
|
||||
'aaa 11 bbb',
|
||||
'aaa 30 bbb',
|
||||
'aaa 50 bbb',
|
||||
'aaa 80',
|
||||
'aaa 90',
|
||||
'bbb 60 aaa',
|
||||
];
|
||||
foreach ($termNames as $termName) {
|
||||
$term = $this->createTerm($this->vocabulary, ['name' => $termName]);
|
||||
$this->termIds[$termName] = $term->id();
|
||||
}
|
||||
|
||||
// Create a taxonomy_term_reference field on the article Content Type that
|
||||
// uses a taxonomy_autocomplete widget.
|
||||
$this->fieldName = $this->randomMachineName();
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'entity_reference',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
'settings' => [
|
||||
'target_type' => 'taxonomy_term',
|
||||
],
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'bundle' => 'article',
|
||||
'entity_type' => 'node',
|
||||
'settings' => [
|
||||
'handler' => 'default',
|
||||
'handler_settings' => [
|
||||
// Restrict selection of terms to a single vocabulary.
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
EntityFormDisplay::load('node.article.default')
|
||||
->setComponent($this->fieldName, [
|
||||
'type' => 'entity_reference_autocomplete',
|
||||
])
|
||||
->save();
|
||||
EntityViewDisplay::load('node.article.default')
|
||||
->setComponent($this->fieldName, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a user and then login.
|
||||
$this->adminUser = $this->drupalCreateUser(['create article content']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Retrieve the autocomplete URL.
|
||||
$this->drupalGet('node/add/article');
|
||||
$field = $this->assertSession()->fieldExists("{$this->fieldName}[0][target_id]");
|
||||
$this->autocompleteUrl = $this->getAbsoluteUrl($field->getAttribute('data-autocomplete-path'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for JSON formatted requests.
|
||||
*
|
||||
* @param string|\Drupal\Core\Url $path
|
||||
* Drupal path or URL to load into Mink controlled browser.
|
||||
* @param array $options
|
||||
* (optional) Options to be forwarded to the URL generator.
|
||||
* @param string[] $headers
|
||||
* (optional) An array containing additional HTTP request headers.
|
||||
*
|
||||
* @return string[]
|
||||
* Array representing decoded JSON response.
|
||||
*/
|
||||
protected function drupalGetJson($path, array $options = [], array $headers = []) {
|
||||
$options = array_merge_recursive(['query' => ['_format' => 'json']], $options);
|
||||
return Json::decode($this->drupalGet($path, $options, $headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the autocomplete method returns the good number of results.
|
||||
*
|
||||
* @see \Drupal\taxonomy\Controller\TermAutocompleteController::autocomplete()
|
||||
*/
|
||||
public function testAutocompleteCountResults(): void {
|
||||
// Test that no matching term found.
|
||||
$data = $this->drupalGetJson(
|
||||
$this->autocompleteUrl,
|
||||
['query' => ['q' => 'zzz']]
|
||||
);
|
||||
$this->assertEmpty($data, 'Autocomplete returned no results');
|
||||
|
||||
// Test that only one matching term found, when only one matches.
|
||||
$data = $this->drupalGetJson(
|
||||
$this->autocompleteUrl,
|
||||
['query' => ['q' => 'aaa 10']]
|
||||
);
|
||||
$this->assertCount(1, $data, 'Autocomplete returned 1 result');
|
||||
|
||||
// Test the correct number of matches when multiple are partial matches.
|
||||
$data = $this->drupalGetJson(
|
||||
$this->autocompleteUrl,
|
||||
['query' => ['q' => 'aaa 1']]
|
||||
);
|
||||
$this->assertCount(3, $data, 'Autocomplete returned 3 results');
|
||||
|
||||
// Tests that only 10 results are returned, even if there are more than 10
|
||||
// matches.
|
||||
$data = $this->drupalGetJson(
|
||||
$this->autocompleteUrl,
|
||||
['query' => ['q' => 'aaa']]
|
||||
);
|
||||
$this->assertCount(10, $data, 'Autocomplete returned only 10 results (for over 10 matches)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the autocomplete method returns properly ordered results.
|
||||
*
|
||||
* @see \Drupal\taxonomy\Controller\TermAutocompleteController::autocomplete()
|
||||
*/
|
||||
public function testAutocompleteOrderedResults(): void {
|
||||
$expectedResults = [
|
||||
'aaa 10 bbb',
|
||||
'aaa 11 bbb',
|
||||
'aaa 12 bbb',
|
||||
'aaa 20 bbb',
|
||||
'aaa 30 bbb',
|
||||
'aaa 40 bbb',
|
||||
'aaa 50 bbb',
|
||||
'aaa 70 bbb',
|
||||
'bbb 60 aaa',
|
||||
];
|
||||
// Build $expected to match the autocomplete results.
|
||||
$expected = [];
|
||||
foreach ($expectedResults as $termName) {
|
||||
$expected[] = [
|
||||
'value' => $termName . ' (' . $this->termIds[$termName] . ')',
|
||||
'label' => $termName,
|
||||
];
|
||||
}
|
||||
|
||||
$data = $this->drupalGetJson(
|
||||
$this->autocompleteUrl,
|
||||
['query' => ['q' => 'bbb']]
|
||||
);
|
||||
|
||||
$this->assertSame($expected, $data);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
|
||||
|
||||
/**
|
||||
* Tests the Taxonomy term entity's cache tags.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" vocabulary.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Camelids',
|
||||
'vid' => 'camelids',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
// Create a "Llama" taxonomy term.
|
||||
$term = Term::create([
|
||||
'name' => 'Llama',
|
||||
'vid' => $vocabulary->id(),
|
||||
]);
|
||||
$term->save();
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
/**
|
||||
* Tests views contextual links on terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermContextualLinksTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'contextual',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests contextual links.
|
||||
*/
|
||||
public function testTermContextualLinks(): void {
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$term = $this->createTerm($vocabulary);
|
||||
|
||||
$user = $this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'access contextual links',
|
||||
]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->elementExists('css', 'div[data-contextual-id^="taxonomy_term:taxonomy_term=' . $term->id() . ':"]');
|
||||
}
|
||||
|
||||
}
|
||||
256
web/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php
Normal file
256
web/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php
Normal file
@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Tests the hook implementations that maintain the taxonomy index.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermIndexTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* Name of the taxonomy term reference field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName1;
|
||||
|
||||
/**
|
||||
* Name of the taxonomy term reference field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName2;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create an administrative user.
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'bypass node access',
|
||||
]));
|
||||
|
||||
// Create a vocabulary and add two term reference fields to article nodes.
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
|
||||
$this->fieldName1 = $this->randomMachineName();
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $this->fieldName1, '', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($this->fieldName1, [
|
||||
'type' => 'options_select',
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($this->fieldName1, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
|
||||
$this->fieldName2 = $this->randomMachineName();
|
||||
$this->createEntityReferenceField('node', 'article', $this->fieldName2, '', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($this->fieldName2, [
|
||||
'type' => 'options_select',
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($this->fieldName2, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the taxonomy index is maintained properly.
|
||||
*/
|
||||
public function testTaxonomyIndex(): void {
|
||||
$node_storage = $this->container->get('entity_type.manager')->getStorage('node');
|
||||
// Create terms in the vocabulary.
|
||||
$term_1 = $this->createTerm($this->vocabulary);
|
||||
$term_2 = $this->createTerm($this->vocabulary);
|
||||
|
||||
// Post an article.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['body[0][value]'] = $this->randomMachineName();
|
||||
$edit["{$this->fieldName1}[]"] = $term_1->id();
|
||||
$edit["{$this->fieldName2}[]"] = $term_1->id();
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that the term is indexed, and only once.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$connection = Database::getConnection();
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_1->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 1 is indexed once.');
|
||||
|
||||
// Update the article to change one term.
|
||||
$edit["{$this->fieldName1}[]"] = $term_2->id();
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that both terms are indexed.
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_1->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 1 is indexed.');
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_2->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 2 is indexed.');
|
||||
|
||||
// Update the article to change another term.
|
||||
$edit["{$this->fieldName2}[]"] = $term_2->id();
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that only one term is indexed.
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_1->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(0, $index_count, 'Term 1 is not indexed.');
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_2->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 2 is indexed once.');
|
||||
|
||||
// Redo the above tests without interface.
|
||||
$node = $node_storage->load($node->id());
|
||||
$node->title = $this->randomMachineName();
|
||||
|
||||
// Update the article with no term changed.
|
||||
$node->save();
|
||||
|
||||
// Check that the index was not changed.
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_1->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(0, $index_count, 'Term 1 is not indexed.');
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_2->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 2 is indexed once.');
|
||||
|
||||
// Update the article to change one term.
|
||||
$node->{$this->fieldName1} = [['target_id' => $term_1->id()]];
|
||||
$node->save();
|
||||
|
||||
// Check that both terms are indexed.
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_1->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 1 is indexed.');
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_2->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 2 is indexed.');
|
||||
|
||||
// Update the article to change another term.
|
||||
$node->{$this->fieldName2} = [['target_id' => $term_1->id()]];
|
||||
$node->save();
|
||||
|
||||
// Check that only one term is indexed.
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_1->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(1, $index_count, 'Term 1 is indexed once.');
|
||||
$index_count = $connection->select('taxonomy_index')
|
||||
->condition('nid', $node->id())
|
||||
->condition('tid', $term_2->id())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertEquals(0, $index_count, 'Term 2 is not indexed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that there is a link to the parent term on the child term page.
|
||||
*/
|
||||
public function testTaxonomyTermHierarchyBreadcrumbs(): void {
|
||||
// Create two taxonomy terms and set term2 as the parent of term1.
|
||||
$term1 = $this->createTerm($this->vocabulary);
|
||||
$term2 = $this->createTerm($this->vocabulary);
|
||||
$term1->parent = [$term2->id()];
|
||||
$term1->save();
|
||||
|
||||
// Verify that the page breadcrumbs include a link to the parent term.
|
||||
$this->drupalGet('taxonomy/term/' . $term1->id());
|
||||
// Breadcrumbs are not rendered with a language, prevent the term
|
||||
// language from being added to the options.
|
||||
// Check that parent term link is displayed when viewing the node.
|
||||
$this->assertSession()->responseContains(Link::fromTextAndUrl($term2->getName(), $term2->toUrl('canonical', ['language' => NULL]))->toString());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the language functionality for the taxonomy terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermLanguageTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create an administrative user.
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
|
||||
|
||||
// Create a vocabulary to which the terms will be assigned.
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
|
||||
// Add some custom languages.
|
||||
foreach (['aa', 'bb', 'cc'] as $language_code) {
|
||||
ConfigurableLanguage::create([
|
||||
'id' => $language_code,
|
||||
'label' => $this->randomMachineName(),
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the language of a term.
|
||||
*/
|
||||
public function testTermLanguage(): void {
|
||||
// Configure the vocabulary to not hide the language selector.
|
||||
$edit = [
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id());
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Add a term.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
// Check that we have the language selector.
|
||||
$this->assertSession()->fieldExists('edit-langcode-0-value');
|
||||
// Submit the term.
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(),
|
||||
'langcode[0][value]' => 'aa',
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => $edit['name[0][value]'],
|
||||
]);
|
||||
$term = reset($terms);
|
||||
$this->assertEquals($edit['langcode[0][value]'], $term->language()->getId(), 'The term contains the correct langcode.');
|
||||
|
||||
// Check if on the edit page the language is correct.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', $edit['langcode[0][value]'])->isSelected());
|
||||
|
||||
// Change the language of the term.
|
||||
$edit['langcode[0][value]'] = 'bb';
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check again that on the edit page the language is correct.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', $edit['langcode[0][value]'])->isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the default language selection for taxonomy terms.
|
||||
*/
|
||||
public function testDefaultTermLanguage(): void {
|
||||
// Configure the vocabulary to not hide the language selector, and make the
|
||||
// default language of the terms fixed.
|
||||
$edit = [
|
||||
'default_language[langcode]' => 'bb',
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id());
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', 'bb')->isSelected());
|
||||
|
||||
// Make the default language of the terms to be the current interface.
|
||||
$edit = [
|
||||
'default_language[langcode]' => 'current_interface',
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id());
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->drupalGet('aa/admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', 'aa')->isSelected());
|
||||
$this->drupalGet('bb/admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', 'bb')->isSelected());
|
||||
|
||||
// Change the default language of the site and check if the default terms
|
||||
// language is still correctly selected.
|
||||
$this->config('system.site')->set('default_langcode', 'cc')->save();
|
||||
$edit = [
|
||||
'default_language[langcode]' => LanguageInterface::LANGCODE_SITE_DEFAULT,
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id());
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode-0-value', 'cc')->isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that translated terms are displayed correctly on the term overview.
|
||||
*/
|
||||
public function testTermTranslatedOnOverviewPage(): void {
|
||||
// Configure the vocabulary to not hide the language selector.
|
||||
$edit = [
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id());
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Add a term.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
// Submit the term.
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(),
|
||||
'langcode[0][value]' => 'aa',
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => $edit['name[0][value]'],
|
||||
]);
|
||||
$term = reset($terms);
|
||||
|
||||
// Add a translation for that term.
|
||||
$translated_title = $this->randomMachineName();
|
||||
$term->addTranslation('bb', [
|
||||
'name' => $translated_title,
|
||||
]);
|
||||
$term->save();
|
||||
|
||||
// Overview page in the other language shows the translated term
|
||||
$this->drupalGet('bb/admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->responseMatches('|<a[^>]*>' . $translated_title . '</a>|');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,363 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests managing taxonomy parents through the user interface.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermParentsTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The term storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermStorageInterface
|
||||
*/
|
||||
protected $termStorage;
|
||||
|
||||
/**
|
||||
* The state service.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The ID of the vocabulary used in this test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $vocabularyId = 'test_vocabulary';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$this->termStorage = $entity_type_manager->getStorage('taxonomy_term');
|
||||
$this->state = $this->container->get('state');
|
||||
|
||||
Vocabulary::create(['vid' => $this->vocabularyId, 'name' => 'Test'])->save();
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests specifying parents when creating terms.
|
||||
*/
|
||||
public function testAddWithParents(): void {
|
||||
$this->drupalGet("/admin/structure/taxonomy/manage/{$this->vocabularyId}/add");
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
// Create a term without any parents.
|
||||
$term_1 = $this->submitAddTermForm('Test term 1');
|
||||
$expected = [['target_id' => 0]];
|
||||
$this->assertEquals($expected, $term_1->get('parent')->getValue());
|
||||
|
||||
// Explicitly selecting <root> should have the same effect as not selecting
|
||||
// anything.
|
||||
$page->selectFieldOption('Parent terms', '<root>');
|
||||
$term_2 = $this->submitAddTermForm('Test term 2');
|
||||
$this->assertEquals($expected, $term_2->get('parent')->getValue());
|
||||
|
||||
// Create two terms with the previously created ones as parents,
|
||||
// respectively.
|
||||
$page->selectFieldOption('Parent terms', 'Test term 1');
|
||||
$term_3 = $this->submitAddTermForm('Test term 3');
|
||||
$expected = [['target_id' => $term_1->id()]];
|
||||
$this->assertEquals($expected, $term_3->get('parent')->getValue());
|
||||
$page->selectFieldOption('Parent terms', 'Test term 2');
|
||||
$term_4 = $this->submitAddTermForm('Test term 4');
|
||||
$expected = [['target_id' => $term_2->id()]];
|
||||
$this->assertEquals($expected, $term_4->get('parent')->getValue());
|
||||
|
||||
// Create a term with term 3 as parent.
|
||||
$page->selectFieldOption('Parent terms', '-Test term 3');
|
||||
$term_5 = $this->submitAddTermForm('Test term 5');
|
||||
$expected = [['target_id' => $term_3->id()]];
|
||||
$this->assertEquals($expected, $term_5->get('parent')->getValue());
|
||||
|
||||
// Create a term with multiple parents.
|
||||
$page->selectFieldOption('Parent terms', '--Test term 5');
|
||||
$page->selectFieldOption('Parent terms', '-Test term 4', TRUE);
|
||||
$term_6 = $this->submitAddTermForm('Test term 6');
|
||||
$expected = [
|
||||
['target_id' => $term_5->id()],
|
||||
['target_id' => $term_4->id()],
|
||||
];
|
||||
$this->assertEquals($expected, $term_6->get('parent')->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a term through the user interface and returns it.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the term to create.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface
|
||||
* The newly created taxonomy term.
|
||||
*/
|
||||
protected function submitAddTermForm($name) {
|
||||
$this->getSession()->getPage()->fillField('Name', $name);
|
||||
|
||||
$this->submitForm([], 'Save');
|
||||
|
||||
$result = $this->termStorage
|
||||
->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('name', $name)
|
||||
->execute();
|
||||
/** @var \Drupal\taxonomy\TermInterface $term_1 */
|
||||
$term_1 = $this->termStorage->load(reset($result));
|
||||
$this->assertInstanceOf(TermInterface::class, $term_1);
|
||||
return $term_1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests editing the parents of existing terms.
|
||||
*/
|
||||
public function testEditingParents(): void {
|
||||
$terms = $this->doTestEditingSingleParent();
|
||||
$term_5 = array_pop($terms);
|
||||
$term_4 = array_pop($terms);
|
||||
|
||||
// Create a term with multiple parents.
|
||||
$term_6 = $this->createTerm('Test term 6', [
|
||||
// Term 5 comes before term 4 in the user interface, so add the parents in
|
||||
// the matching order.
|
||||
$term_5->id(),
|
||||
$term_4->id(),
|
||||
]);
|
||||
$this->drupalGet($term_6->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>');
|
||||
$this->assertParentOption('Test term 1');
|
||||
$this->assertParentOption('-Test term 3');
|
||||
$this->assertParentOption('--Test term 5', TRUE);
|
||||
$this->assertParentOption('Test term 2');
|
||||
$this->assertParentOption('-Test term 4', TRUE);
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests specifying parents when creating terms and a disabled parent form.
|
||||
*/
|
||||
public function testEditingParentsWithDisabledFormElement(): void {
|
||||
// Disable the parent form element.
|
||||
$this->state->set('taxonomy_test.disable_parent_form_element', TRUE);
|
||||
$this->drupalGet("/admin/structure/taxonomy/manage/{$this->vocabularyId}/add");
|
||||
$this->assertSession()->fieldDisabled('Parent terms');
|
||||
|
||||
$terms = $this->doTestEditingSingleParent();
|
||||
$term_5 = array_pop($terms);
|
||||
$term_4 = array_pop($terms);
|
||||
|
||||
// Create a term with multiple parents.
|
||||
$term_6 = $this->createTerm('Test term 6', [
|
||||
// When the parent form element is disabled, its default value is used as
|
||||
// the value which gets populated in ascending order of term IDs.
|
||||
$term_4->id(),
|
||||
$term_5->id(),
|
||||
]);
|
||||
$this->drupalGet($term_6->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>');
|
||||
$this->assertParentOption('Test term 1');
|
||||
$this->assertParentOption('-Test term 3');
|
||||
$this->assertParentOption('--Test term 5', TRUE);
|
||||
$this->assertParentOption('Test term 2');
|
||||
$this->assertParentOption('-Test term 4', TRUE);
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs tests that edit terms with a single parent.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* A list of terms created for testing.
|
||||
*/
|
||||
protected function doTestEditingSingleParent(): array {
|
||||
$terms = [];
|
||||
|
||||
// Create two terms without any parents.
|
||||
$term_1 = $this->createTerm('Test term 1');
|
||||
$this->drupalGet($term_1->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>', TRUE);
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_1);
|
||||
$terms[] = $term_1;
|
||||
|
||||
$term_2 = $this->createTerm('Test term 2');
|
||||
$this->drupalGet($term_2->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>', TRUE);
|
||||
$this->assertParentOption('Test term 1');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_2);
|
||||
$terms[] = $term_2;
|
||||
|
||||
// Create two terms with the previously created terms as parents,
|
||||
// respectively.
|
||||
$term_3 = $this->createTerm('Test term 3', [$term_1->id()]);
|
||||
$this->drupalGet($term_3->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>');
|
||||
$this->assertParentOption('Test term 1', TRUE);
|
||||
$this->assertParentOption('Test term 2');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_3);
|
||||
$terms[] = $term_3;
|
||||
|
||||
$term_4 = $this->createTerm('Test term 4', [$term_2->id()]);
|
||||
$this->drupalGet($term_4->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>');
|
||||
$this->assertParentOption('Test term 1');
|
||||
$this->assertParentOption('-Test term 3');
|
||||
$this->assertParentOption('Test term 2', TRUE);
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_4);
|
||||
$terms[] = $term_4;
|
||||
|
||||
// Create a term with term 3 as parent.
|
||||
$term_5 = $this->createTerm('Test term 5', [$term_3->id()]);
|
||||
$this->drupalGet($term_5->toUrl('edit-form'));
|
||||
$this->assertParentOption('<root>');
|
||||
$this->assertParentOption('Test term 1');
|
||||
$this->assertParentOption('-Test term 3', TRUE);
|
||||
$this->assertParentOption('Test term 2');
|
||||
$this->assertParentOption('-Test term 4');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertParentsUnchanged($term_5);
|
||||
$terms[] = $term_5;
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the term add/edit form with parent query parameter.
|
||||
*/
|
||||
public function testParentFromQuery(): void {
|
||||
// Create three terms without any parents.
|
||||
$term_1 = $this->createTerm('Test term 1');
|
||||
$term_2 = $this->createTerm('Test term 2');
|
||||
$term_3 = $this->createTerm('Test term 3');
|
||||
|
||||
// Add term form with one parent.
|
||||
$this->drupalGet("/admin/structure/taxonomy/manage/{$this->vocabularyId}/add", ['query' => ['parent' => $term_1->id()]]);
|
||||
$this->assertParentOption('Test term 1', TRUE);
|
||||
$this->assertParentOption('Test term 2', FALSE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
// Add term form with two parents.
|
||||
$this->drupalGet("/admin/structure/taxonomy/manage/{$this->vocabularyId}/add", ['query' => ['parent[0]' => $term_1->id(), 'parent[1]' => $term_2->id()]]);
|
||||
$this->assertParentOption('Test term 1', TRUE);
|
||||
$this->assertParentOption('Test term 2', TRUE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
// Add term form with no parents.
|
||||
$this->drupalGet("/admin/structure/taxonomy/manage/{$this->vocabularyId}/add", ['query' => ['parent' => '']]);
|
||||
$this->assertParentOption('Test term 1', FALSE);
|
||||
$this->assertParentOption('Test term 2', FALSE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
// Add term form with invalid parent.
|
||||
$this->drupalGet("/admin/structure/taxonomy/manage/{$this->vocabularyId}/add", ['query' => ['parent' => -1]]);
|
||||
$this->assertParentOption('Test term 1', FALSE);
|
||||
$this->assertParentOption('Test term 2', FALSE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
|
||||
// Edit term form with one parent.
|
||||
$this->drupalGet($term_1->toUrl('edit-form'), ['query' => ['parent' => $term_2->id()]]);
|
||||
$this->assertParentOption('Test term 2', TRUE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
// Edit term form with two parents.
|
||||
$this->drupalGet($term_1->toUrl('edit-form'), ['query' => ['parent[0]' => $term_2->id(), 'parent[1]' => $term_3->id()]]);
|
||||
$this->assertParentOption('Test term 2', TRUE);
|
||||
$this->assertParentOption('Test term 3', TRUE);
|
||||
// Edit term form with no parents.
|
||||
$this->drupalGet($term_1->toUrl('edit-form'), ['query' => ['parent' => '']]);
|
||||
$this->assertParentOption('Test term 2', FALSE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
// Edit term form with invalid parent.
|
||||
$this->drupalGet($term_1->toUrl('edit-form'), ['query' => ['parent' => -1]]);
|
||||
$this->assertParentOption('Test term 2', FALSE);
|
||||
$this->assertParentOption('Test term 3', FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a term, saves it and returns it.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the term to create.
|
||||
* @param int[] $parent_ids
|
||||
* (optional) A list of parent term IDs.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface
|
||||
* The created term.
|
||||
*/
|
||||
protected function createTerm($name, array $parent_ids = []) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
$term = $this->termStorage->create([
|
||||
'name' => $name,
|
||||
'vid' => $this->vocabularyId,
|
||||
]);
|
||||
foreach ($parent_ids as $delta => $parent_id) {
|
||||
$term->get('parent')->set($delta, ['target_id' => $parent_id]);
|
||||
}
|
||||
|
||||
$term->save();
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an option in the parent form element of terms exists.
|
||||
*
|
||||
* @param string $option
|
||||
* The label of the parent option.
|
||||
* @param bool $selected
|
||||
* (optional) Whether or not the option should be selected. Defaults to
|
||||
* FALSE.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertParentOption(string $option, bool $selected = FALSE): void {
|
||||
$option = $this->assertSession()->optionExists('Parent terms', $option);
|
||||
if ($selected) {
|
||||
$this->assertTrue($option->hasAttribute('selected'));
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($option->hasAttribute('selected'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the parents of the term have not changed after saving.
|
||||
*
|
||||
* @param \Drupal\taxonomy\TermInterface $term
|
||||
* The term to check.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertParentsUnchanged(TermInterface $term): void {
|
||||
$saved_term = $this->termStorage->load($term->id());
|
||||
|
||||
$expected = $term->get('parent')->getValue();
|
||||
$this->assertEquals($expected, $saved_term->get('parent')->getValue());
|
||||
}
|
||||
|
||||
}
|
||||
707
web/core/modules/taxonomy/tests/src/Functional/TermTest.php
Normal file
707
web/core/modules/taxonomy/tests/src/Functional/TermTest.php
Normal file
@ -0,0 +1,707 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Tags;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\Tests\system\Functional\Menu\AssertBreadcrumbTrait;
|
||||
|
||||
/**
|
||||
* Tests load, save and delete for taxonomy terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTest extends TaxonomyTestBase {
|
||||
|
||||
use AssertBreadcrumbTrait;
|
||||
|
||||
/**
|
||||
* Vocabulary for testing.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* Taxonomy term reference field for testing.
|
||||
*
|
||||
* @var \Drupal\field\FieldConfigInterface
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'taxonomy_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('local_actions_block');
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'access taxonomy overview',
|
||||
'bypass node access',
|
||||
]));
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
|
||||
$field_name = 'taxonomy_' . $this->vocabulary->id();
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $field_name, '', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$this->field = FieldConfig::loadByName('node', 'article', $field_name);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'options_select',
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests terms in a single and multiple hierarchy.
|
||||
*/
|
||||
public function testTaxonomyTermHierarchy(): void {
|
||||
// Create two taxonomy terms.
|
||||
$term1 = $this->createTerm($this->vocabulary);
|
||||
$term2 = $this->createTerm($this->vocabulary);
|
||||
|
||||
// Get the taxonomy storage.
|
||||
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
|
||||
$taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||
|
||||
// Check that hierarchy is flat.
|
||||
$this->assertEquals(0, $taxonomy_storage->getVocabularyHierarchyType($this->vocabulary->id()), 'Vocabulary is flat.');
|
||||
|
||||
// Edit $term2, setting $term1 as parent.
|
||||
$edit = [];
|
||||
$edit['parent[]'] = [$term1->id()];
|
||||
$this->drupalGet('taxonomy/term/' . $term2->id() . '/edit');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check the hierarchy.
|
||||
$children = $taxonomy_storage->loadChildren($term1->id());
|
||||
$parents = $taxonomy_storage->loadParents($term2->id());
|
||||
$this->assertTrue(isset($children[$term2->id()]), 'Child found correctly.');
|
||||
$this->assertTrue(isset($parents[$term1->id()]), 'Parent found correctly.');
|
||||
|
||||
// Load and save a term, confirming that parents are still set.
|
||||
$term = Term::load($term2->id());
|
||||
$term->save();
|
||||
$parents = $taxonomy_storage->loadParents($term2->id());
|
||||
$this->assertTrue(isset($parents[$term1->id()]), 'Parent found correctly.');
|
||||
|
||||
// Create a third term and save this as a parent of term2.
|
||||
$term3 = $this->createTerm($this->vocabulary);
|
||||
$term2->parent = [$term1->id(), $term3->id()];
|
||||
$term2->save();
|
||||
$parents = $taxonomy_storage->loadParents($term2->id());
|
||||
$this->assertArrayHasKey($term1->id(), $parents);
|
||||
$this->assertArrayHasKey($term3->id(), $parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that many terms with parents show on each page.
|
||||
*/
|
||||
public function testTaxonomyTermChildTerms(): void {
|
||||
// Set limit to 10 terms per page. Set variable to 9 so 10 terms appear.
|
||||
$this->config('taxonomy.settings')->set('terms_per_page_admin', '9')->save();
|
||||
$term1 = $this->createTerm($this->vocabulary);
|
||||
$terms_array = [];
|
||||
|
||||
// Create 40 terms. Terms 1-12 get parent of $term1. All others are
|
||||
// individual terms.
|
||||
for ($x = 1; $x <= 40; $x++) {
|
||||
$edit = [];
|
||||
// Set terms in order so we know which terms will be on which pages.
|
||||
$edit['weight'] = $x;
|
||||
|
||||
// Set terms 1-20 to be children of first term created.
|
||||
if ($x <= 12) {
|
||||
$edit['parent'] = $term1->id();
|
||||
}
|
||||
$term = $this->createTerm($this->vocabulary, $edit);
|
||||
$terms_array[$x] = Term::load($term->id());
|
||||
}
|
||||
|
||||
// Get Page 1. Parent term and terms 1-13 are displayed.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->pageTextContains($term1->getName());
|
||||
for ($x = 1; $x <= 13; $x++) {
|
||||
$this->assertSession()->pageTextContains($terms_array[$x]->getName());
|
||||
}
|
||||
|
||||
// Get Page 2. Parent term and terms 1-18 are displayed.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 1]]);
|
||||
$this->assertSession()->pageTextContains($term1->getName());
|
||||
for ($x = 1; $x <= 18; $x++) {
|
||||
$this->assertSession()->pageTextContains($terms_array[$x]->getName());
|
||||
}
|
||||
|
||||
// Get Page 3. No parent term and no terms <18 are displayed. Terms 18-25
|
||||
// are displayed.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview', ['query' => ['page' => 2]]);
|
||||
$this->assertSession()->pageTextNotContains($term1->getName());
|
||||
for ($x = 1; $x <= 17; $x++) {
|
||||
$this->assertSession()->pageTextNotContains($terms_array[$x]->getName());
|
||||
}
|
||||
for ($x = 18; $x <= 25; $x++) {
|
||||
$this->assertSession()->pageTextContains($terms_array[$x]->getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests term creation with a free-tagging vocabulary from the node form.
|
||||
*/
|
||||
public function testNodeTermCreationAndDeletion(): void {
|
||||
// Enable tags in the vocabulary.
|
||||
$field = $this->field;
|
||||
\Drupal::service('entity_display.repository')
|
||||
->getFormDisplay($field->getTargetEntityTypeId(), $field->getTargetBundle())
|
||||
->setComponent($field->getName(), [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
'settings' => [
|
||||
'placeholder' => 'Start typing here.',
|
||||
],
|
||||
])
|
||||
->save();
|
||||
// Prefix the terms with a letter to ensure there is no clash in the first
|
||||
// three letters.
|
||||
// @see https://www.drupal.org/node/2397691
|
||||
$terms = [
|
||||
'term1' => 'a' . $this->randomMachineName(),
|
||||
'term2' => 'b' . $this->randomMachineName(),
|
||||
'term3' => 'c' . $this->randomMachineName() . ', ' . $this->randomMachineName(),
|
||||
'term4' => 'd' . $this->randomMachineName(),
|
||||
];
|
||||
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['body[0][value]'] = $this->randomMachineName();
|
||||
// Insert the terms in a comma separated list. Vocabulary 1 is a
|
||||
// free-tagging field created by the default profile.
|
||||
$edit[$field->getName() . '[target_id]'] = Tags::implode($terms);
|
||||
|
||||
// Verify the placeholder is there.
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertSession()->responseContains('placeholder="Start typing here."');
|
||||
|
||||
// Preview and verify the terms appear but are not created.
|
||||
$this->submitForm($edit, 'Preview');
|
||||
foreach ($terms as $term) {
|
||||
$this->assertSession()->pageTextContains($term);
|
||||
}
|
||||
$tree = $this->container->get('entity_type.manager')->getStorage('taxonomy_term')->loadTree($this->vocabulary->id());
|
||||
$this->assertEmpty($tree, 'The terms are not created on preview.');
|
||||
|
||||
// Save, creating the terms.
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Article ' . $edit['title[0][value]'] . ' has been created.');
|
||||
|
||||
// Verify that the creation message contains a link to a node.
|
||||
$this->assertSession()->elementExists('xpath', '//div[@data-drupal-messages]//a[contains(@href, "node/")]');
|
||||
|
||||
foreach ($terms as $term) {
|
||||
$this->assertSession()->pageTextContains($term);
|
||||
}
|
||||
|
||||
// Get the created terms.
|
||||
$term_objects = [];
|
||||
foreach ($terms as $key => $term) {
|
||||
$term_objects[$key] = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => $term,
|
||||
]);
|
||||
$term_objects[$key] = reset($term_objects[$key]);
|
||||
}
|
||||
|
||||
// Get the node.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
|
||||
// Test editing the node.
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->submitForm($edit, 'Save');
|
||||
foreach ($terms as $term) {
|
||||
$this->assertSession()->pageTextContains($term);
|
||||
}
|
||||
|
||||
// Delete term 1 from the term edit page.
|
||||
$this->drupalGet('taxonomy/term/' . $term_objects['term1']->id() . '/edit');
|
||||
$this->clickLink('Delete');
|
||||
$this->submitForm([], 'Delete');
|
||||
|
||||
// Delete term 2 from the term delete page.
|
||||
$this->drupalGet('taxonomy/term/' . $term_objects['term2']->id() . '/delete');
|
||||
$this->submitForm([], 'Delete');
|
||||
|
||||
// Verify that the terms appear on the node page after the two terms were
|
||||
// deleted.
|
||||
$term_names = [$term_objects['term3']->getName(), $term_objects['term4']->getName()];
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
foreach ($term_names as $term_name) {
|
||||
$this->assertSession()->pageTextContains($term_name);
|
||||
}
|
||||
$this->assertSession()->pageTextNotContains($term_objects['term1']->getName());
|
||||
$this->assertSession()->pageTextNotContains($term_objects['term2']->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save, edit and delete a term using the user interface.
|
||||
*/
|
||||
public function testTermInterface(): void {
|
||||
\Drupal::service('module_installer')->install(['views']);
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(12),
|
||||
'description[0][value]' => $this->randomMachineName(100),
|
||||
];
|
||||
// Explicitly set the parents field to 'root', to ensure that
|
||||
// TermForm::save() handles the invalid term ID correctly.
|
||||
$edit['parent[]'] = [0];
|
||||
|
||||
// Create the term to edit.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Ensure form redirected back to term add page.
|
||||
$this->assertSession()->addressEquals('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => $edit['name[0][value]'],
|
||||
]);
|
||||
$term = reset($terms);
|
||||
$this->assertNotNull($term, 'Term found in database.');
|
||||
|
||||
// Submitting a term takes us to the add page; we need the List page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
|
||||
$this->clickLink('Edit', 1);
|
||||
|
||||
// Verify that the randomly generated term is present.
|
||||
$this->assertSession()->pageTextContains($edit['name[0][value]']);
|
||||
$this->assertSession()->pageTextContains($edit['description[0][value]']);
|
||||
|
||||
// Test the "Add child" link on the overview page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->linkExistsExact('Add child');
|
||||
$this->clickLink('Add child');
|
||||
$edit = [
|
||||
'name[0][value]' => 'Child term',
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => 'Child term',
|
||||
]);
|
||||
$child = reset($terms);
|
||||
$this->assertNotNull($child, 'Child term found in database.');
|
||||
$this->assertEquals($term->id(), $child->get('parent')->getValue()[0]['target_id']);
|
||||
|
||||
// Edit the term.
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(14),
|
||||
'description[0][value]' => $this->randomMachineName(102),
|
||||
];
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Ensure form redirected back to term view.
|
||||
$this->assertSession()->addressEquals('taxonomy/term/' . $term->id());
|
||||
|
||||
// Check that the term is still present at admin UI after edit.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->pageTextContains($edit['name[0][value]']);
|
||||
$this->assertSession()->linkExists('Edit');
|
||||
|
||||
// Unpublish the term.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->submitForm(["status[value]" => 0], 'Save');
|
||||
// Check that the term is now unpublished in the list.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->elementTextContains('css', "#edit-terms-tid{$term->id()}0-status", 'Unpublished');
|
||||
|
||||
// Check the term link can be clicked through to the term page.
|
||||
$this->clickLink($edit['name[0][value]']);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
// View the term and check that it is correct.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->pageTextContains($edit['name[0][value]']);
|
||||
$this->assertSession()->pageTextContains($edit['description[0][value]']);
|
||||
|
||||
// Did this page request display a 'term-listing-heading'?
|
||||
$this->assertSession()->elementExists('xpath', '//div[@class="views-element-container"]/div/header/div/div/p');
|
||||
// Check that it does NOT show a description when description is blank.
|
||||
$term->setDescription(NULL);
|
||||
$term->save();
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->elementNotExists('xpath', '//div[@class="views-element-container"]/div/header/div/div/p');
|
||||
|
||||
// Check that the description value is processed.
|
||||
$value = $this->randomMachineName();
|
||||
$term->setDescription($value);
|
||||
$term->save();
|
||||
$this->assertSame("<p>{$value}</p>\n", (string) $term->description->processed);
|
||||
|
||||
// Check that the term feed page is working.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/feed');
|
||||
|
||||
// Delete the term.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->clickLink('Delete');
|
||||
$this->submitForm([], 'Delete');
|
||||
|
||||
// Assert that the term no longer exists.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
|
||||
// Test "save and go to list" action while creating term.
|
||||
// Create the term to edit.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(12),
|
||||
'description[0][value]' => $this->randomMachineName(100),
|
||||
];
|
||||
|
||||
// Create the term to edit.
|
||||
$this->submitForm($edit, 'Save and go to list');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->addressEquals('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->pageTextContains($edit['name[0][value]']);
|
||||
|
||||
// Validate that "Save and go to list" doesn't exist when destination
|
||||
// parameter is present.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add', ['query' => ['destination' => 'node/add']]);
|
||||
$this->assertSession()->pageTextNotContains('Save and go to list');
|
||||
|
||||
// Validate that "Save and go to list" doesn't exist when missing permission
|
||||
// 'access taxonomy overview'.
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'bypass node access',
|
||||
]));
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->assertSession()->pageTextNotContains('Save and go to list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test UI with override_selector TRUE.
|
||||
*/
|
||||
public function testTermSaveOverrideSelector(): void {
|
||||
$this->config('taxonomy.settings')->set('override_selector', TRUE)->save();
|
||||
|
||||
// Create a Term.
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(12),
|
||||
'description[0][value]' => $this->randomMachineName(100),
|
||||
];
|
||||
// Create the term to edit.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => $edit['name[0][value]'],
|
||||
]);
|
||||
$term = reset($terms);
|
||||
$this->assertNotNull($term, 'Term found in database.');
|
||||
|
||||
// The term appears on the vocab list page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->pageTextContains($term->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save, edit and delete a term using the user interface.
|
||||
*/
|
||||
public function testTermReorder(): void {
|
||||
$assert = $this->assertSession();
|
||||
$this->createTerm($this->vocabulary);
|
||||
$this->createTerm($this->vocabulary);
|
||||
$this->createTerm($this->vocabulary);
|
||||
|
||||
$taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||
|
||||
// Fetch the created terms in the default alphabetical order, i.e. term1
|
||||
// precedes term2 alphabetically, and term2 precedes term3.
|
||||
$taxonomy_storage->resetCache();
|
||||
[$term1, $term2, $term3] = $taxonomy_storage->loadTree($this->vocabulary->id(), 0, NULL, TRUE);
|
||||
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
|
||||
// Each term has four hidden fields, "tid:1:0[tid]", "tid:1:0[parent]",
|
||||
// "tid:1:0[depth]", and "tid:1:0[weight]". Change the order to term2,
|
||||
// term3, term1 by setting weight property, make term3 a child of term2 by
|
||||
// setting the parent and depth properties, and update all hidden fields.
|
||||
$hidden_edit = [
|
||||
'terms[tid:' . $term2->id() . ':0][term][tid]' => $term2->id(),
|
||||
'terms[tid:' . $term2->id() . ':0][term][parent]' => 0,
|
||||
'terms[tid:' . $term2->id() . ':0][term][depth]' => 0,
|
||||
'terms[tid:' . $term3->id() . ':0][term][tid]' => $term3->id(),
|
||||
'terms[tid:' . $term3->id() . ':0][term][parent]' => $term2->id(),
|
||||
'terms[tid:' . $term3->id() . ':0][term][depth]' => 1,
|
||||
'terms[tid:' . $term1->id() . ':0][term][tid]' => $term1->id(),
|
||||
'terms[tid:' . $term1->id() . ':0][term][parent]' => 0,
|
||||
'terms[tid:' . $term1->id() . ':0][term][depth]' => 0,
|
||||
];
|
||||
// Because we can't post hidden form elements, we have to change them in
|
||||
// code here, and then submit.
|
||||
foreach ($hidden_edit as $field => $value) {
|
||||
$node = $assert->hiddenFieldExists($field);
|
||||
$node->setValue($value);
|
||||
}
|
||||
// Edit non-hidden elements within submitForm().
|
||||
$edit = [
|
||||
'terms[tid:' . $term2->id() . ':0][weight]' => 0,
|
||||
'terms[tid:' . $term3->id() . ':0][weight]' => 1,
|
||||
'terms[tid:' . $term1->id() . ':0][weight]' => 2,
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
$taxonomy_storage->resetCache();
|
||||
$terms = $taxonomy_storage->loadTree($this->vocabulary->id());
|
||||
$this->assertEquals($term2->id(), $terms[0]->tid, 'Term 2 was moved above term 1.');
|
||||
$this->assertEquals([$term2->id()], $terms[1]->parents, 'Term 3 was made a child of term 2.');
|
||||
$this->assertEquals($term1->id(), $terms[2]->tid, 'Term 1 was moved below term 2.');
|
||||
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->submitForm([], 'Reset to alphabetical');
|
||||
// Submit confirmation form.
|
||||
$this->submitForm([], 'Reset to alphabetical');
|
||||
// Ensure form redirected back to overview.
|
||||
$this->assertSession()->addressEquals('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
|
||||
$taxonomy_storage->resetCache();
|
||||
$terms = $taxonomy_storage->loadTree($this->vocabulary->id(), 0, NULL, TRUE);
|
||||
$this->assertEquals($term1->id(), $terms[0]->id(), 'Term 1 was moved to back above term 2.');
|
||||
$this->assertEquals($term2->id(), $terms[1]->id(), 'Term 2 was moved to back below term 1.');
|
||||
$this->assertEquals($term3->id(), $terms[2]->id(), 'Term 3 is still below term 2.');
|
||||
$this->assertEquals([$term2->id()], $terms[2]->parents, 'Term 3 is still a child of term 2.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests saving a term with multiple parents through the UI.
|
||||
*/
|
||||
public function testTermMultipleParentsInterface(): void {
|
||||
// Add two new terms to the vocabulary so that we can have multiple parents.
|
||||
// These will be terms with tids of 1 and 2 respectively.
|
||||
$this->createTerm($this->vocabulary);
|
||||
$this->createTerm($this->vocabulary);
|
||||
|
||||
// Add a new term with multiple parents.
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(12),
|
||||
'description[0][value]' => $this->randomMachineName(100),
|
||||
'parent[]' => [0, 1],
|
||||
];
|
||||
// Save the new term.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that the term was successfully created.
|
||||
$term = $this->reloadTermByName($edit['name[0][value]']);
|
||||
$this->assertNotNull($term, 'Term found in database.');
|
||||
$this->assertEquals($edit['name[0][value]'], $term->getName(), 'Term name was successfully saved.');
|
||||
$this->assertEquals($edit['description[0][value]'], $term->getDescription(), 'Term description was successfully saved.');
|
||||
|
||||
// Check that we have the expected parents.
|
||||
$this->assertEquals([0, 1], $this->getParentTids($term), 'Term parents (root plus one) were successfully saved.');
|
||||
|
||||
// Load the edit form and save again to ensure parent are preserved.
|
||||
// Generate a new name, so we know that the term really is saved.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(12),
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']);
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']);
|
||||
|
||||
// Check that we still have the expected parents.
|
||||
$term = $this->reloadTermByName($edit['name[0][value]']);
|
||||
$this->assertEquals([0, 1], $this->getParentTids($term), 'Term parents (root plus one) were successfully saved again.');
|
||||
|
||||
// Save with two real parents. i.e., not including <root>.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(12),
|
||||
'parent[]' => [1, 2],
|
||||
];
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']);
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']);
|
||||
|
||||
// Check that we have the expected parents.
|
||||
$term = $this->reloadTermByName($edit['name[0][value]']);
|
||||
$this->assertEquals([1, 2], $this->getParentTids($term), 'Term parents (two real) were successfully saved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests destination after saving terms.
|
||||
*/
|
||||
public function testRedirects(): void {
|
||||
// Save a new term.
|
||||
$addUrl = Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $this->vocabulary->id()]);
|
||||
$this->drupalGet($addUrl);
|
||||
$this->submitForm([
|
||||
'name[0][value]' => $this->randomMachineName(),
|
||||
], 'Save');
|
||||
|
||||
// Adding a term reloads the form.
|
||||
$this->assertSession()->addressEquals($addUrl->toString());
|
||||
$this->assertSession()->pageTextContains('Created new term');
|
||||
|
||||
// Update a term.
|
||||
$term = Term::create(['vid' => $this->vocabulary->id(), 'name' => $this->randomMachineName()]);
|
||||
$term->save();
|
||||
$this->drupalGet($term->toUrl('edit-form'));
|
||||
$this->submitForm(edit: [], submit: 'Save');
|
||||
|
||||
// Updating a term sends user to view the term.
|
||||
$this->assertSession()->addressEquals($term->toUrl()->setAbsolute());
|
||||
$this->assertSession()->pageTextContains('Updated term');
|
||||
|
||||
// Unless the term is not accessible to the user.
|
||||
// Label triggers forbidden in taxonomy_test_entity_access().
|
||||
$term = Term::create(['vid' => $this->vocabulary->id(), 'name' => 'Inaccessible view']);
|
||||
$term->save();
|
||||
$this->drupalGet($term->toUrl('edit-form'));
|
||||
$this->submitForm(edit: [], submit: 'Save');
|
||||
|
||||
// In which case, the edit form is reloaded.
|
||||
$this->assertSession()->addressEquals($term->toUrl('edit-form')->setAbsolute());
|
||||
$this->assertSession()->pageTextContains('Updated term');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads a term by name.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface
|
||||
* The reloaded term.
|
||||
*/
|
||||
private function reloadTermByName(string $name): TermInterface {
|
||||
\Drupal::entityTypeManager()->getStorage('taxonomy_term')->resetCache();
|
||||
/** @var \Drupal\taxonomy\TermInterface[] $terms */
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['name' => $name]);
|
||||
return reset($terms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent tids for a term including root.
|
||||
*
|
||||
* @param \Drupal\taxonomy\TermInterface $term
|
||||
* The term.
|
||||
*
|
||||
* @return array
|
||||
* A sorted array of tids and 0 if the root is a parent.
|
||||
*/
|
||||
private function getParentTids($term): array {
|
||||
$parent_tids = [];
|
||||
foreach ($term->get('parent') as $item) {
|
||||
$parent_tids[] = (int) $item->target_id;
|
||||
}
|
||||
sort($parent_tids);
|
||||
|
||||
return $parent_tids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that editing and saving a node with no changes works correctly.
|
||||
*/
|
||||
public function testReSavingTags(): void {
|
||||
// Enable tags in the vocabulary.
|
||||
$field = $this->field;
|
||||
\Drupal::service('entity_display.repository')
|
||||
->getFormDisplay($field->getTargetEntityTypeId(), $field->getTargetBundle())
|
||||
->setComponent($field->getName(), [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a term and a node using it.
|
||||
$term = $this->createTerm($this->vocabulary);
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName(8);
|
||||
$edit['body[0][value]'] = $this->randomMachineName(16);
|
||||
$edit[$this->field->getName() . '[target_id]'] = $term->getName();
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that the term is displayed when editing and saving the node with no
|
||||
// changes.
|
||||
$this->clickLink('Edit');
|
||||
$this->assertSession()->responseContains($term->getName());
|
||||
$this->submitForm([], 'Save');
|
||||
$this->assertSession()->responseContains($term->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the breadcrumb on edit and delete a term page.
|
||||
*/
|
||||
public function testTermBreadcrumbs(): void {
|
||||
$edit = [
|
||||
'name[0][value]' => $this->randomMachineName(14),
|
||||
'description[0][value]' => $this->randomMachineName(100),
|
||||
'parent[]' => [0],
|
||||
];
|
||||
|
||||
// Create the term.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
|
||||
'name' => $edit['name[0][value]'],
|
||||
]);
|
||||
$term = reset($terms);
|
||||
$this->assertNotNull($term, 'Term found in database.');
|
||||
|
||||
// Check the breadcrumb on the term edit page.
|
||||
$trail = [
|
||||
'' => 'Home',
|
||||
'taxonomy/term/' . $term->id() => $term->label(),
|
||||
];
|
||||
$this->assertBreadcrumb('taxonomy/term/' . $term->id() . '/edit', $trail);
|
||||
$this->assertSession()->assertEscaped($term->label());
|
||||
|
||||
// Check the breadcrumb on the term delete page.
|
||||
$trail = [
|
||||
'' => 'Home',
|
||||
'taxonomy/term/' . $term->id() => $term->label(),
|
||||
];
|
||||
$this->assertBreadcrumb('taxonomy/term/' . $term->id() . '/delete', $trail);
|
||||
$this->assertSession()->assertEscaped($term->label());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Tests the translation of taxonomy terms field on nodes.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTranslationFieldViewTest extends TaxonomyTestBase {
|
||||
|
||||
use TaxonomyTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* The term that should be translated.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Term
|
||||
*/
|
||||
protected $term;
|
||||
|
||||
/**
|
||||
* The tag in the source language.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseTagName = 'OriginalTagName';
|
||||
|
||||
/**
|
||||
* The translated value for the tag.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $translatedTagName = 'TranslatedTagName';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'content_translation', 'taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->setupLanguages();
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
$this->enableTranslation();
|
||||
$this->setUpTerm();
|
||||
$this->setUpTermReferenceField();
|
||||
$this->setUpNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the translated taxonomy term is displayed.
|
||||
*/
|
||||
public function testTranslatedTaxonomyTermReferenceDisplay(): void {
|
||||
$path = 'node/' . $this->node->id();
|
||||
$translation_path = $this->translateToLangcode . '/' . $path;
|
||||
|
||||
$this->drupalGet($path);
|
||||
$this->assertSession()->pageTextNotContains($this->translatedTagName);
|
||||
$this->assertSession()->pageTextContains($this->baseTagName);
|
||||
$this->drupalGet($translation_path);
|
||||
$this->assertSession()->pageTextContains($this->translatedTagName);
|
||||
$this->assertSession()->pageTextNotContains($this->baseTagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test subject node, with translation.
|
||||
*/
|
||||
protected function setUpNode(): void {
|
||||
/** @var \Drupal\node\Entity\Node $node */
|
||||
$node = Node::create([
|
||||
'title' => $this->randomMachineName(),
|
||||
'type' => 'article',
|
||||
'description' => [
|
||||
[
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'basic_html',
|
||||
],
|
||||
],
|
||||
$this->termFieldName => [['target_id' => $this->term->id()]],
|
||||
'langcode' => $this->baseLangcode,
|
||||
]);
|
||||
$node->save();
|
||||
$node->addTranslation($this->translateToLangcode, $node->toArray());
|
||||
$node->save();
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test subject term, with translation.
|
||||
*/
|
||||
protected function setUpTerm(): void {
|
||||
$this->term = $this->createTerm($this->vocabulary, [
|
||||
'name' => $this->baseTagName,
|
||||
'langcode' => $this->baseLangcode,
|
||||
]);
|
||||
|
||||
$this->term->addTranslation($this->translateToLangcode, [
|
||||
'name' => $this->translatedTagName,
|
||||
]);
|
||||
$this->term->save();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\system\Functional\Menu\AssertBreadcrumbTrait;
|
||||
|
||||
/**
|
||||
* Tests for proper breadcrumb translation.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTranslationTest extends TaxonomyTestBase {
|
||||
|
||||
use AssertBreadcrumbTrait;
|
||||
use TaxonomyTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* Term to translated term mapping.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $termTranslationMap = [
|
||||
'one' => 'translatedOne',
|
||||
'two' => 'translatedTwo',
|
||||
'three' => 'translatedThree',
|
||||
];
|
||||
|
||||
/**
|
||||
* Created terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Term[]
|
||||
*/
|
||||
protected $terms = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'language', 'content_translation'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->setupLanguages();
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
$this->enableTranslation();
|
||||
$this->setUpTerms();
|
||||
$this->setUpTermReferenceField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translated breadcrumbs.
|
||||
*/
|
||||
public function testTranslatedBreadcrumbs(): void {
|
||||
// Ensure non-translated breadcrumb is correct.
|
||||
$breadcrumb = [Url::fromRoute('<front>')->toString() => 'Home'];
|
||||
foreach ($this->terms as $term) {
|
||||
$breadcrumb[$term->toUrl()->toString()] = $term->label();
|
||||
}
|
||||
// The last item will not be in the breadcrumb.
|
||||
array_pop($breadcrumb);
|
||||
|
||||
// Check the breadcrumb on the leaf term page.
|
||||
$term = $this->getLeafTerm();
|
||||
$this->assertBreadcrumb($term->toUrl(), $breadcrumb, $term->label());
|
||||
|
||||
$languages = \Drupal::languageManager()->getLanguages();
|
||||
|
||||
// Construct the expected translated breadcrumb.
|
||||
$breadcrumb = [Url::fromRoute('<front>', [], ['language' => $languages[$this->translateToLangcode]])->toString() => 'Home'];
|
||||
foreach ($this->terms as $term) {
|
||||
$translated = $term->getTranslation($this->translateToLangcode);
|
||||
$url = $translated->toUrl('canonical', ['language' => $languages[$this->translateToLangcode]])->toString();
|
||||
$breadcrumb[$url] = $translated->label();
|
||||
}
|
||||
array_pop($breadcrumb);
|
||||
|
||||
// Check for the translated breadcrumb on the translated leaf term page.
|
||||
$term = $this->getLeafTerm();
|
||||
$translated = $term->getTranslation($this->translateToLangcode);
|
||||
$this->assertBreadcrumb($translated->toUrl('canonical', ['language' => $languages[$this->translateToLangcode]]), $breadcrumb, $translated->label());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation of terms are showed in the node.
|
||||
*/
|
||||
public function testTermsTranslation(): void {
|
||||
|
||||
// Set the display of the term reference field on the article content type
|
||||
// to "Check boxes/radio buttons".
|
||||
\Drupal::service('entity_display.repository')
|
||||
->getFormDisplay('node', 'article')
|
||||
->setComponent($this->termFieldName, [
|
||||
'type' => 'options_buttons',
|
||||
])
|
||||
->save();
|
||||
$this->drupalLogin($this->drupalCreateUser(['create article content']));
|
||||
|
||||
// Test terms are listed.
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertSession()->pageTextContains('one');
|
||||
$this->assertSession()->pageTextContains('two');
|
||||
$this->assertSession()->pageTextContains('three');
|
||||
|
||||
// Test terms translated are listed.
|
||||
$this->drupalGet('hu/node/add/article');
|
||||
$this->assertSession()->pageTextContains('translatedOne');
|
||||
$this->assertSession()->pageTextContains('translatedTwo');
|
||||
$this->assertSession()->pageTextContains('translatedThree');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup translated terms in a hierarchy.
|
||||
*/
|
||||
protected function setUpTerms(): void {
|
||||
$parent_vid = 0;
|
||||
foreach ($this->termTranslationMap as $name => $translation) {
|
||||
|
||||
$term = $this->createTerm($this->vocabulary, [
|
||||
'name' => $name,
|
||||
'langcode' => $this->baseLangcode,
|
||||
'parent' => $parent_vid,
|
||||
]);
|
||||
|
||||
$term->addTranslation($this->translateToLangcode, [
|
||||
'name' => $translation,
|
||||
]);
|
||||
$term->save();
|
||||
|
||||
// Each term is nested under the last.
|
||||
$parent_vid = $term->id();
|
||||
|
||||
$this->terms[] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the final (leaf) term in the hierarchy.
|
||||
*
|
||||
* @return \Drupal\taxonomy\Entity\Term
|
||||
* The final term in the hierarchy.
|
||||
*/
|
||||
protected function getLeafTerm() {
|
||||
return $this->terms[count($this->termTranslationMap) - 1];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Tests\content_translation\Functional\ContentTranslationUITestBase;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the Term Translation UI.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTranslationUITest extends ContentTranslationUITestBase {
|
||||
|
||||
/**
|
||||
* The vocabulary used for creating terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultCacheContexts = [
|
||||
'languages:language_interface',
|
||||
'theme',
|
||||
'url.query_args:_wrapper_format',
|
||||
'user.permissions',
|
||||
'url.site',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'content_translation', 'taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->entityTypeId = 'taxonomy_term';
|
||||
$this->bundle = 'tags';
|
||||
parent::setUp();
|
||||
$this->doSetup();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setupBundle(): void {
|
||||
parent::setupBundle();
|
||||
|
||||
// Create a vocabulary.
|
||||
$this->vocabulary = Vocabulary::create([
|
||||
'name' => $this->bundle,
|
||||
'description' => $this->randomMachineName(),
|
||||
'vid' => $this->bundle,
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'weight' => mt_rand(0, 10),
|
||||
]);
|
||||
$this->vocabulary->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTranslatorPermissions(): array {
|
||||
return array_merge(parent::getTranslatorPermissions(), ['administer taxonomy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNewEntityValues($langcode) {
|
||||
return ['name' => $this->randomMachineName()] + parent::getNewEntityValues($langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an edit array containing the values to be posted.
|
||||
*/
|
||||
protected function getEditValues($values, $langcode, $new = FALSE) {
|
||||
$edit = parent::getEditValues($values, $langcode, $new);
|
||||
|
||||
// To be able to post values for the configurable base fields (name,
|
||||
// description) have to be suffixed with [0][value].
|
||||
foreach ($edit as $property => $value) {
|
||||
foreach (['name', 'description'] as $key) {
|
||||
if ($property == $key) {
|
||||
$edit[$key . '[0][value]'] = $value;
|
||||
unset($edit[$property]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $edit;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testTranslationUI(): void {
|
||||
parent::testTranslationUI();
|
||||
|
||||
// Make sure that no row was inserted for taxonomy vocabularies which do
|
||||
// not have translations enabled.
|
||||
$tids = \Drupal::entityQueryAggregate('taxonomy_term')
|
||||
->accessCheck(FALSE)
|
||||
->aggregate('tid', 'COUNT')
|
||||
->condition('vid', $this->bundle, '<>')
|
||||
->groupBy('tid')
|
||||
->execute();
|
||||
|
||||
foreach ($tids as $tid) {
|
||||
$this->assertTrue($tid['tid_count'] < 2, 'Term does have translations.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translate link on vocabulary term list.
|
||||
*/
|
||||
public function testTranslateLinkVocabularyAdminPage(): void {
|
||||
$this->drupalLogin($this->drupalCreateUser(array_merge(parent::getTranslatorPermissions(), ['access administration pages', 'administer taxonomy'])));
|
||||
|
||||
$values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
];
|
||||
$translatable_tid = $this->createEntity($values, $this->langcodes[0], $this->vocabulary->id());
|
||||
|
||||
// Create an untranslatable vocabulary.
|
||||
$untranslatable_vocabulary = Vocabulary::create([
|
||||
'name' => 'untranslatable_voc',
|
||||
'description' => $this->randomMachineName(),
|
||||
'vid' => 'untranslatable_voc',
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'weight' => mt_rand(0, 10),
|
||||
]);
|
||||
$untranslatable_vocabulary->save();
|
||||
|
||||
$values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
];
|
||||
$untranslatable_tid = $this->createEntity($values, $this->langcodes[0], $untranslatable_vocabulary->id());
|
||||
|
||||
// Verify translation links.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/overview');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->linkByHrefExists('term/' . $translatable_tid . '/translations', 0, 'The translations link exists for a translatable vocabulary.');
|
||||
$this->assertSession()->linkByHrefExists('term/' . $translatable_tid . '/edit', 0, 'The edit link exists for a translatable vocabulary.');
|
||||
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $untranslatable_vocabulary->id() . '/overview');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->linkByHrefExists('term/' . $untranslatable_tid . '/edit');
|
||||
$this->assertSession()->linkByHrefNotExists('term/' . $untranslatable_tid . '/translations');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doTestTranslationEdit(): void {
|
||||
$storage = $this->container->get('entity_type.manager')
|
||||
->getStorage($this->entityTypeId);
|
||||
$entity = $storage->load($this->entityId);
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
// We only want to test the title for non-english translations.
|
||||
if ($langcode != 'en') {
|
||||
$options = ['language' => $languages[$langcode]];
|
||||
$url = $entity->toUrl('edit-form', $options);
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains("{$entity->getTranslation($langcode)->label()} [{$languages[$langcode]->getName()} translation]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doTestPublishedStatus(): void {
|
||||
$storage = $this->container->get('entity_type.manager')
|
||||
->getStorage($this->entityTypeId);
|
||||
$entity = $storage->load($this->entityId);
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
|
||||
$statuses = [
|
||||
TRUE,
|
||||
FALSE,
|
||||
];
|
||||
|
||||
foreach ($statuses as $index => $value) {
|
||||
// (Un)publish the term translations and check that the translation
|
||||
// statuses are (un)published accordingly.
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
$options = ['language' => $languages[$langcode]];
|
||||
$url = $entity->toUrl('edit-form', $options);
|
||||
$this->drupalGet($url, $options);
|
||||
$this->submitForm(['status[value]' => $value], 'Save');
|
||||
}
|
||||
$entity = $storage->load($this->entityId);
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
// The term is created as unpublished thus we switch to the published
|
||||
// status first.
|
||||
$status = !$index;
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
$this->assertEquals($status, $this->manager->getTranslationMetadata($translation)->isPublished(), 'The translation has been correctly unpublished.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
68
web/core/modules/taxonomy/tests/src/Functional/ThemeTest.php
Normal file
68
web/core/modules/taxonomy/tests/src/Functional/ThemeTest.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
/**
|
||||
* Verifies that various taxonomy pages use the expected theme.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class ThemeTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Make sure we are using distinct default and administrative themes for
|
||||
// the duration of these tests.
|
||||
\Drupal::service('theme_installer')->install(['olivero', 'claro']);
|
||||
$this->config('system.theme')
|
||||
->set('default', 'olivero')
|
||||
->set('admin', 'claro')
|
||||
->save();
|
||||
|
||||
// Create and log in as a user who has permission to add and edit taxonomy
|
||||
// terms and view the administrative theme.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'view the administration theme',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the theme used when adding, viewing and editing taxonomy terms.
|
||||
*/
|
||||
public function testTaxonomyTermThemes(): void {
|
||||
// Adding a term to a vocabulary is considered an administrative action and
|
||||
// should use the administrative theme.
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add');
|
||||
// Check that the administrative theme's CSS appears on the page for adding
|
||||
// a taxonomy term.
|
||||
$this->assertSession()->responseContains('claro/css/base/elements.css');
|
||||
|
||||
// Viewing a taxonomy term should use the default theme.
|
||||
$term = $this->createTerm($vocabulary);
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
// Check that the default theme's CSS appears on the page for viewing
|
||||
// a taxonomy term.
|
||||
$this->assertSession()->responseContains('olivero/css/base/base.css');
|
||||
|
||||
// Editing a taxonomy term should use the same theme as adding one.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
// Check that the administrative theme's CSS appears on the page for editing
|
||||
// a taxonomy term.
|
||||
$this->assertSession()->responseContains('claro/css/base/elements.css');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
/**
|
||||
* Tests the representative node relationship for terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyDefaultArgumentTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['taxonomy_default_argument_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests escaping of page title when the taxonomy plugin provides it.
|
||||
*/
|
||||
public function testTermTitleEscaping(): void {
|
||||
$this->term1->setName('<em>Markup</em>')->save();
|
||||
$this->drupalGet('taxonomy_default_argument_test/' . $this->term1->id());
|
||||
$this->assertSession()->assertEscaped($this->term1->label());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the "All terms" taxonomy term field handler.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyFieldAllTermsTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['taxonomy_all_terms_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests the "all terms" field handler.
|
||||
*/
|
||||
public function testViewsHandlerAllTermsField(): void {
|
||||
$this->term1->setName('<em>Markup</em>')->save();
|
||||
$view = Views::getView('taxonomy_all_terms_test');
|
||||
$this->executeView($view);
|
||||
$this->drupalGet('taxonomy_all_terms_test');
|
||||
|
||||
// Test term1 links.
|
||||
$xpath = '//a[@href="' . $this->term1->toUrl()->toString() . '"]';
|
||||
$this->assertSession()->elementsCount('xpath', $xpath, 2);
|
||||
$links = $this->xpath($xpath);
|
||||
$this->assertEquals($this->term1->label(), $links[0]->getText());
|
||||
$this->assertEquals($this->term1->label(), $links[1]->getText());
|
||||
$this->assertSession()->assertEscaped($this->term1->label());
|
||||
|
||||
// Test term2 links.
|
||||
$xpath = '//a[@href="' . $this->term2->toUrl()->toString() . '"]';
|
||||
$this->assertSession()->elementsCount('xpath', $xpath, 2);
|
||||
$links = $this->xpath($xpath);
|
||||
$this->assertEquals($this->term2->label(), $links[0]->getText());
|
||||
$this->assertEquals($this->term2->label(), $links[1]->getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests token replacement in the "all terms" field handler.
|
||||
*/
|
||||
public function testViewsHandlerAllTermsWithTokens(): void {
|
||||
$this->drupalGet('taxonomy_all_terms_token_test');
|
||||
|
||||
// Term itself: {{ term_node_tid }}.
|
||||
$this->assertSession()->pageTextContains('Term: ' . $this->term1->getName());
|
||||
|
||||
// The taxonomy term ID for the term: {{ term_node_tid__tid }}.
|
||||
$this->assertSession()->pageTextContains('The taxonomy term ID for the term: ' . $this->term1->id());
|
||||
|
||||
// The taxonomy term name for the term: {{ term_node_tid__name }}.
|
||||
$this->assertSession()->pageTextContains('The taxonomy term name for the term: ' . $this->term1->getName());
|
||||
|
||||
// The machine name for the vocabulary the term belongs to:
|
||||
// {{ term_node_tid__vocabulary_vid }}.
|
||||
$this->assertSession()->pageTextContains('The machine name for the vocabulary the term belongs to: ' . $this->term1->bundle());
|
||||
|
||||
// The name for the vocabulary the term belongs to: {{
|
||||
// term_node_tid__vocabulary }}.
|
||||
$vocabulary = Vocabulary::load($this->term1->bundle());
|
||||
$this->assertSession()->pageTextContains('The name for the vocabulary the term belongs to: ' . $vocabulary->label());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
|
||||
/**
|
||||
* Tests taxonomy field filters with translations.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyFieldFilterTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'language',
|
||||
'taxonomy',
|
||||
'taxonomy_test_views',
|
||||
'text',
|
||||
'views',
|
||||
'node',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_field_filters'];
|
||||
|
||||
/**
|
||||
* The vocabulary used for creating terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* List of taxonomy term names by language.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $termNames = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
// Add two new languages.
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
|
||||
// Set up term names.
|
||||
$this->termNames = [
|
||||
'en' => 'Food in Paris',
|
||||
'es' => 'Comida en Paris',
|
||||
'fr' => 'Nourriture en Paris',
|
||||
];
|
||||
|
||||
// Create a vocabulary.
|
||||
$this->vocabulary = Vocabulary::create([
|
||||
'name' => 'Views testing tags',
|
||||
'vid' => 'views_testing_tags',
|
||||
]);
|
||||
$this->vocabulary->save();
|
||||
|
||||
// Add a translatable field to the vocabulary.
|
||||
$field = FieldStorageConfig::create([
|
||||
'field_name' => 'field_foo',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'type' => 'text',
|
||||
]);
|
||||
$field->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => 'field_foo',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'label' => 'Foo',
|
||||
'bundle' => 'views_testing_tags',
|
||||
])->save();
|
||||
|
||||
// Create term with translations.
|
||||
$taxonomy = $this->createTermWithProperties(['name' => $this->termNames['en'], 'langcode' => 'en', 'description' => $this->termNames['en'], 'field_foo' => $this->termNames['en']]);
|
||||
foreach (['es', 'fr'] as $langcode) {
|
||||
$translation = $taxonomy->addTranslation($langcode, ['name' => $this->termNames[$langcode]]);
|
||||
$translation->description->value = $this->termNames[$langcode];
|
||||
$translation->field_foo->value = $this->termNames[$langcode];
|
||||
}
|
||||
$taxonomy->save();
|
||||
|
||||
Views::viewsData()->clear();
|
||||
|
||||
ViewTestData::createTestViews(static::class, ['taxonomy_test_views']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests description and term name filters.
|
||||
*/
|
||||
public function testFilters(): void {
|
||||
// Test the name filter page, which filters for name contains 'Comida'.
|
||||
// Should show just the Spanish translation, once.
|
||||
$this->assertPageCounts('test-name-filter', ['es' => 1, 'fr' => 0, 'en' => 0], 'Comida name filter');
|
||||
|
||||
// Test the description filter page, which filters for description contains
|
||||
// 'Comida'. Should show just the Spanish translation, once.
|
||||
$this->assertPageCounts('test-desc-filter', ['es' => 1, 'fr' => 0, 'en' => 0], 'Comida description filter');
|
||||
|
||||
// Test the field filter page, which filters for field_foo contains
|
||||
// 'Comida'. Should show just the Spanish translation, once.
|
||||
$this->assertPageCounts('test-field-filter', ['es' => 1, 'fr' => 0, 'en' => 0], 'Comida field filter');
|
||||
|
||||
// Test the name Paris filter page, which filters for name contains
|
||||
// 'Paris'. Should show each translation once.
|
||||
$this->assertPageCounts('test-name-paris', ['es' => 1, 'fr' => 1, 'en' => 1], 'Paris name filter');
|
||||
|
||||
// Test the description Paris page, which filters for description contains
|
||||
// 'Paris'. Should show each translation, once.
|
||||
$this->assertPageCounts('test-desc-paris', ['es' => 1, 'fr' => 1, 'en' => 1], 'Paris description filter');
|
||||
|
||||
// Test the field Paris filter page, which filters for field_foo contains
|
||||
// 'Paris'. Should show each translation once.
|
||||
$this->assertPageCounts('test-field-paris', ['es' => 1, 'fr' => 1, 'en' => 1], 'Paris field filter');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given taxonomy translation counts are correct.
|
||||
*
|
||||
* @param string $path
|
||||
* Path of the page to test.
|
||||
* @param array $counts
|
||||
* Array whose keys are languages, and values are the number of times
|
||||
* that translation should be shown on the given page.
|
||||
* @param string $message
|
||||
* Message suffix to display.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertPageCounts(string $path, array $counts, string $message): void {
|
||||
// Get the text of the page.
|
||||
$this->drupalGet($path);
|
||||
$text = $this->getTextContent();
|
||||
|
||||
// Check the counts. Note that the title and body are both shown on the
|
||||
// page, and they are the same. So the title/body string should appear on
|
||||
// the page twice as many times as the input count.
|
||||
foreach ($counts as $langcode => $count) {
|
||||
$this->assertEquals(2 * $count, substr_count($text, $this->termNames[$langcode]), 'Translation ' . $langcode . ' has count ' . $count . ' with ' . $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a taxonomy term with specified name and other properties.
|
||||
*
|
||||
* @param array $properties
|
||||
* Array of properties and field values to set.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface
|
||||
* The created taxonomy term.
|
||||
*/
|
||||
protected function createTermWithProperties($properties) {
|
||||
// Use the first available text format.
|
||||
$filter_formats = filter_formats();
|
||||
$format = array_pop($filter_formats);
|
||||
|
||||
$properties += [
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'field_foo' => $this->randomMachineName(),
|
||||
];
|
||||
|
||||
$term = Term::create([
|
||||
'name' => $properties['name'],
|
||||
'description' => $properties['description'],
|
||||
'format' => $format->id(),
|
||||
'vid' => $this->vocabulary->id(),
|
||||
'langcode' => $properties['langcode'],
|
||||
]);
|
||||
$term->field_foo->value = $properties['field_foo'];
|
||||
$term->save();
|
||||
return $term;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,553 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\views_ui\Functional\UITestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\views\Entity\View;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy index filter handler UI.
|
||||
*
|
||||
* @group taxonomy
|
||||
* @see \Drupal\taxonomy\Plugin\views\field\TaxonomyIndexTid
|
||||
*/
|
||||
class TaxonomyIndexTidUiTest extends UITestBase {
|
||||
|
||||
use EntityReferenceFieldCreationTrait;
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = [
|
||||
'test_filter_taxonomy_index_tid',
|
||||
'test_taxonomy_term_name',
|
||||
'test_taxonomy_exposed_grouped_filter',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'taxonomy',
|
||||
'views',
|
||||
'views_ui',
|
||||
'taxonomy_test_views',
|
||||
];
|
||||
|
||||
/**
|
||||
* A nested array of \Drupal\taxonomy\TermInterface objects.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface[][]
|
||||
*/
|
||||
protected $terms = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'administer views',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
Vocabulary::create([
|
||||
'vid' => 'tags',
|
||||
'name' => 'Tags',
|
||||
])->save();
|
||||
|
||||
// Setup a hierarchy which looks like this:
|
||||
// term 0.0
|
||||
// term 1.0
|
||||
// - term 1.1
|
||||
// term 2.0
|
||||
// - term 2.1
|
||||
// - term 2.2
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
for ($j = 0; $j <= $i; $j++) {
|
||||
$this->terms[$i][$j] = $term = Term::create([
|
||||
'vid' => 'tags',
|
||||
'name' => "Term $i.$j",
|
||||
'parent' => isset($this->terms[$i][0]) ? $this->terms[$i][0]->id() : 0,
|
||||
]);
|
||||
$term->save();
|
||||
}
|
||||
}
|
||||
ViewTestData::createTestViews(static::class, ['taxonomy_test_views']);
|
||||
|
||||
// Extra taxonomy and terms.
|
||||
Vocabulary::create([
|
||||
'vid' => 'other_tags',
|
||||
'name' => 'Other tags',
|
||||
])->save();
|
||||
|
||||
$this->terms[3][0] = $term = Term::create([
|
||||
'vid' => 'tags',
|
||||
'name' => "Term 3.0",
|
||||
]);
|
||||
$term->save();
|
||||
|
||||
Vocabulary::create([
|
||||
'vid' => 'empty_vocabulary',
|
||||
'name' => 'Empty Vocabulary',
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the filter UI.
|
||||
*/
|
||||
public function testFilterUI(): void {
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid');
|
||||
|
||||
$result = $this->assertSession()->selectExists('edit-options-value')->findAll('css', 'option');
|
||||
|
||||
// Ensure that the expected hierarchy is available in the UI.
|
||||
$counter = 0;
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
for ($j = 0; $j <= $i; $j++) {
|
||||
$option = $result[$counter++];
|
||||
$prefix = $this->terms[$i][$j]->parent->target_id ? '-' : '';
|
||||
$tid = $option->getAttribute('value');
|
||||
|
||||
$this->assertEquals($prefix . $this->terms[$i][$j]->getName(), $option->getText());
|
||||
$this->assertEquals($this->terms[$i][$j]->id(), $tid);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the autocomplete input element appears when using the 'textfield'
|
||||
// type.
|
||||
$view = View::load('test_filter_taxonomy_index_tid');
|
||||
$display =& $view->getDisplay('default');
|
||||
$display['display_options']['filters']['tid']['type'] = 'textfield';
|
||||
$view->save();
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid');
|
||||
$this->assertSession()->fieldExists('edit-options-value');
|
||||
|
||||
// Tests \Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid::calculateDependencies().
|
||||
$expected = [
|
||||
'config' => [
|
||||
'taxonomy.vocabulary.tags',
|
||||
],
|
||||
'content' => [
|
||||
'taxonomy_term:tags:' . Term::load(2)->uuid(),
|
||||
],
|
||||
'module' => [
|
||||
'node',
|
||||
'taxonomy',
|
||||
'user',
|
||||
],
|
||||
];
|
||||
$this->assertSame($expected, $view->calculateDependencies()->getDependencies());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exposed taxonomy filters.
|
||||
*/
|
||||
public function testExposedFilter(): void {
|
||||
$node_type = $this->drupalCreateContentType(['type' => 'page']);
|
||||
|
||||
// Create the tag field itself.
|
||||
$field_name = 'taxonomy_tags';
|
||||
$this->createEntityReferenceField('node', $node_type->id(), $field_name, '', 'taxonomy_term');
|
||||
|
||||
// Create 4 nodes: 1 without a term, 2 with the same term, and 1 with a
|
||||
// different term.
|
||||
$node1 = $this->drupalCreateNode();
|
||||
$node2 = $this->drupalCreateNode([
|
||||
$field_name => [['target_id' => $this->terms[1][0]->id()]],
|
||||
]);
|
||||
$node3 = $this->drupalCreateNode([
|
||||
$field_name => [['target_id' => $this->terms[1][0]->id()]],
|
||||
]);
|
||||
$node4 = $this->drupalCreateNode([
|
||||
$field_name => [['target_id' => $this->terms[2][0]->id()]],
|
||||
]);
|
||||
|
||||
// Only the nodes with the selected term should be shown.
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
$this->assertSession()->pageTextNotContains($node1->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node1->toUrl()->toString());
|
||||
$xpath_node2_link = $this->assertSession()->buildXPathQuery('//div[@class="views-row"]//a[@href=:url and text()=:label]', [
|
||||
':url' => $node2->toUrl()->toString(),
|
||||
':label' => $node2->label(),
|
||||
]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath_node2_link, 1);
|
||||
$xpath_node3_link = $this->assertSession()->buildXPathQuery('//div[@class="views-row"]//a[@href=:url and text()=:label]', [
|
||||
':url' => $node3->toUrl()->toString(),
|
||||
':label' => $node3->label(),
|
||||
]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath_node3_link, 1);
|
||||
$this->assertSession()->pageTextNotContains($node4->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node4->toUrl()->toString());
|
||||
|
||||
// Expose the filter.
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid');
|
||||
$this->submitForm([], 'Expose filter');
|
||||
// Set the operator to 'empty' and remove the default term ID.
|
||||
$this->submitForm([
|
||||
'options[operator]' => 'empty',
|
||||
'options[value][]' => [],
|
||||
], 'Apply');
|
||||
// Save the view.
|
||||
$this->submitForm([], 'Save');
|
||||
|
||||
// After switching to 'empty' operator, the node without a term should be
|
||||
// shown.
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
$xpath_node1_link = $this->assertSession()->buildXPathQuery('//div[@class="views-row"]//a[@href=:url and text()=:label]', [
|
||||
':url' => $node1->toUrl()->toString(),
|
||||
':label' => $node1->label(),
|
||||
]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath_node1_link, 1);
|
||||
$this->assertSession()->pageTextNotContains($node2->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node2->toUrl()->toString());
|
||||
$this->assertSession()->pageTextNotContains($node3->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node3->toUrl()->toString());
|
||||
$this->assertSession()->pageTextNotContains($node4->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node4->toUrl()->toString());
|
||||
|
||||
// Set the operator to 'not empty'.
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid');
|
||||
$this->submitForm(['options[operator]' => 'not empty'], 'Apply');
|
||||
// Save the view.
|
||||
$this->submitForm([], 'Save');
|
||||
|
||||
// After switching to 'not empty' operator, all nodes with terms should be
|
||||
// shown.
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
$this->assertSession()->pageTextNotContains($node1->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node1->toUrl()->toString());
|
||||
$xpath_node2_link = $this->assertSession()->buildXPathQuery('//div[@class="views-row"]//a[@href=:url and text()=:label]', [
|
||||
':url' => $node2->toUrl()->toString(),
|
||||
':label' => $node2->label(),
|
||||
]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath_node2_link, 1);
|
||||
$xpath_node3_link = $this->assertSession()->buildXPathQuery('//div[@class="views-row"]//a[@href=:url and text()=:label]', [
|
||||
':url' => $node3->toUrl()->toString(),
|
||||
':label' => $node3->label(),
|
||||
]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath_node3_link, 1);
|
||||
$xpath_node4_link = $this->assertSession()->buildXPathQuery('//div[@class="views-row"]//a[@href=:url and text()=:label]', [
|
||||
':url' => $node4->toUrl()->toString(),
|
||||
':label' => $node4->label(),
|
||||
]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath_node4_link, 1);
|
||||
|
||||
// Select 'Term ID' as the field to be displayed.
|
||||
$edit = ['name[taxonomy_term_field_data.tid]' => TRUE];
|
||||
$this->drupalGet('admin/structure/views/nojs/add-handler/test_taxonomy_term_name/default/field');
|
||||
$this->submitForm($edit, 'Add and configure fields');
|
||||
// Select 'Term' and 'Vocabulary' as filters.
|
||||
$edit = [
|
||||
'name[taxonomy_term_field_data.tid]' => TRUE,
|
||||
'name[taxonomy_term_field_data.vid]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/views/nojs/add-handler/test_taxonomy_term_name/default/filter');
|
||||
$this->submitForm($edit, 'Add and configure filter criteria');
|
||||
// Select 'Empty Vocabulary' and 'Autocomplete' from the list of options.
|
||||
$this->drupalGet('admin/structure/views/nojs/handler-extra/test_taxonomy_term_name/default/filter/tid');
|
||||
$this->submitForm([], 'Apply and continue');
|
||||
// Expose the filter.
|
||||
$edit = ['options[expose_button][checkbox][checkbox]' => TRUE];
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_taxonomy_term_name/default/filter/tid');
|
||||
$this->submitForm($edit, 'Expose filter');
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_taxonomy_term_name/default/filter/tid');
|
||||
$this->submitForm($edit, 'Apply');
|
||||
// Filter 'Taxonomy terms' belonging to 'Empty Vocabulary'.
|
||||
$edit = ['options[value][empty_vocabulary]' => TRUE];
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_taxonomy_term_name/default/filter/vid');
|
||||
$this->submitForm($edit, 'Apply');
|
||||
$this->drupalGet('admin/structure/views/view/test_taxonomy_term_name/edit/default');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->submitForm([], 'Update preview');
|
||||
$this->assertSession()->pageTextNotContains($node1->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node1->toUrl()->toString());
|
||||
$this->assertSession()->pageTextNotContains($node2->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node2->toUrl()->toString());
|
||||
$this->assertSession()->pageTextNotContains($node3->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node3->toUrl()->toString());
|
||||
$this->assertSession()->pageTextNotContains($node4->getTitle());
|
||||
$this->assertSession()->linkByHrefNotExists($node4->toUrl()->toString());
|
||||
$this->assertSession()->elementNotExists('xpath', "//div[@class='views-row']");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exposed grouped taxonomy filters.
|
||||
*/
|
||||
public function testExposedGroupedFilter(): void {
|
||||
// Create a content type with a taxonomy field.
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
$field_name = 'field_views_testing_tags';
|
||||
$this->createEntityReferenceField('node', 'article', $field_name, '', 'taxonomy_term');
|
||||
|
||||
$nodes = [];
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$node = [];
|
||||
$node['type'] = 'article';
|
||||
$node['field_views_testing_tags'][0]['target_id'] = $this->terms[$i][0]->id();
|
||||
$nodes[] = $this->drupalCreateNode($node);
|
||||
}
|
||||
|
||||
$this->drupalGet('/admin/structure/views/nojs/handler/test_taxonomy_exposed_grouped_filter/page_1/filter/field_views_testing_tags_target_id');
|
||||
$edit = [
|
||||
'options[group_info][group_items][1][value][]' => [$this->terms[0][0]->id(), $this->terms[1][0]->id()],
|
||||
'options[group_info][group_items][2][value][]' => [$this->terms[1][0]->id(), $this->terms[2][0]->id()],
|
||||
'options[group_info][group_items][3][value][]' => [$this->terms[2][0]->id(), $this->terms[0][0]->id()],
|
||||
];
|
||||
$this->submitForm($edit, 'Apply');
|
||||
$this->submitForm([], 'Save');
|
||||
|
||||
// Visit the view's page URL and validate the results.
|
||||
$this->drupalGet('/test-taxonomy-exposed-grouped-filter');
|
||||
$this->submitForm(['field_views_testing_tags_target_id' => 1], 'Apply');
|
||||
$this->assertSession()->pageTextContains($nodes[0]->getTitle());
|
||||
$this->assertSession()->pageTextContains($nodes[1]->getTitle());
|
||||
$this->assertSession()->pageTextNotContains($nodes[2]->getTitle());
|
||||
|
||||
$this->submitForm(['field_views_testing_tags_target_id' => 2], 'Apply');
|
||||
$this->assertSession()->pageTextContains($nodes[1]->getTitle());
|
||||
$this->assertSession()->pageTextContains($nodes[2]->getTitle());
|
||||
$this->assertSession()->pageTextNotContains($nodes[0]->getTitle());
|
||||
|
||||
$this->submitForm(['field_views_testing_tags_target_id' => 3], 'Apply');
|
||||
$this->assertSession()->pageTextContains($nodes[0]->getTitle());
|
||||
$this->assertSession()->pageTextContains($nodes[2]->getTitle());
|
||||
$this->assertSession()->pageTextNotContains($nodes[1]->getTitle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an exposed taxonomy filter doesn't show unpublished terms.
|
||||
*/
|
||||
public function testExposedUnpublishedFilterOptions(): void {
|
||||
$this->terms[1][0]->setUnpublished()->save();
|
||||
// Expose the filter.
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid');
|
||||
$this->submitForm([], 'Expose filter');
|
||||
$edit = ['options[expose_button][checkbox][checkbox]' => TRUE];
|
||||
$this->submitForm($edit, 'Apply');
|
||||
$this->submitForm([], 'Save');
|
||||
// Make sure the unpublished term is shown to the admin user.
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
$this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]'));
|
||||
$this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]'));
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// Make sure the unpublished term isn't shown to the anonymous user.
|
||||
$this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]'));
|
||||
$this->assertEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]'));
|
||||
|
||||
// Tests that the term also isn't shown when not showing hierarchy.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$edit = [
|
||||
'options[hierarchy]' => FALSE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/views/nojs/handler-extra/test_filter_taxonomy_index_tid/default/filter/tid');
|
||||
$this->submitForm($edit, 'Apply');
|
||||
$this->submitForm([], 'Save');
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
$this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]'));
|
||||
$this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]'));
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// Make sure the unpublished term isn't shown to the anonymous user.
|
||||
$this->assertNotEmpty($this->cssSelect('option[value="' . $this->terms[0][0]->id() . '"]'));
|
||||
$this->assertEmpty($this->cssSelect('option[value="' . $this->terms[1][0]->id() . '"]'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests using the TaxonomyIndexTid in a filter group.
|
||||
*/
|
||||
public function testFilterGrouping(): void {
|
||||
$node_type = $this->drupalCreateContentType(['type' => 'page']);
|
||||
|
||||
// Create the tag field itself.
|
||||
$field_name = 'taxonomy_tags';
|
||||
$this->createEntityReferenceField('node', $node_type->id(), $field_name, '', 'taxonomy_term');
|
||||
|
||||
// Create the other tag field itself.
|
||||
$field_name2 = 'taxonomy_other_tags';
|
||||
$this->createEntityReferenceField('node', $node_type->id(), $field_name2, '', 'taxonomy_term');
|
||||
|
||||
// Create 5 nodes: 1 node without any tagging, 2 nodes tagged with 1 term,
|
||||
// 1 node with 2 tagged terms and 1 with other tags term.
|
||||
$node_no_term = $this->drupalCreateNode();
|
||||
$node_with_term_1_0 = $this->drupalCreateNode([
|
||||
$field_name => [['target_id' => $this->terms[1][0]->id()]],
|
||||
]);
|
||||
$node_with_terms_1_0_and_1_1 = $this->drupalCreateNode([
|
||||
$field_name => [
|
||||
['target_id' => $this->terms[1][0]->id()],
|
||||
['target_id' => $this->terms[1][1]->id()],
|
||||
],
|
||||
]);
|
||||
$node_with_term_2_0 = $this->drupalCreateNode([
|
||||
$field_name => [['target_id' => $this->terms[2][0]->id()]],
|
||||
]);
|
||||
|
||||
$node_with_term_3_0 = $this->drupalCreateNode([
|
||||
$field_name2 => [['target_id' => $this->terms[3][0]->id()]],
|
||||
]);
|
||||
|
||||
// Create two groups. The first group contains the published filter and set
|
||||
// up the second group as an 'OR' group. The first subgroup of the second
|
||||
// filter group will vary as follows:
|
||||
// - multiple values vs single value
|
||||
// - not vs or operator values
|
||||
$view = View::load('test_filter_taxonomy_index_tid');
|
||||
$display =& $view->getDisplay('default');
|
||||
// Case 1:
|
||||
// - filter "tid" with multiple terms as "is none of"
|
||||
// - filter "tid_2" with a single term as "is one of"
|
||||
$display['display_options']['filters']['tid']['value'][0] = $this->terms[1][0]->id();
|
||||
$display['display_options']['filters']['tid']['value'][1] = $this->terms[1][1]->id();
|
||||
$display['display_options']['filters']['tid']['operator'] = 'not';
|
||||
$display['display_options']['filters']['tid']['group'] = 2;
|
||||
$display['display_options']['filters']['tid_2'] = $display['display_options']['filters']['tid'];
|
||||
$display['display_options']['filters']['tid_2']['id'] = 'tid_2';
|
||||
$display['display_options']['filters']['tid_2']['value'][0] = $this->terms[2][0]->id();
|
||||
$display['display_options']['filters']['tid_2']['operator'] = 'or';
|
||||
$display['display_options']['filters']['tid_2']['group'] = 2;
|
||||
$display['display_options']['filter_groups'] = [
|
||||
'operator' => 'AND',
|
||||
'groups' => [
|
||||
1 => 'AND',
|
||||
2 => 'OR',
|
||||
],
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// We expect no nodes tagged with term 1.0 or 1.1. The node tagged with
|
||||
// term 2.0 and the untagged node will be shown.
|
||||
$this->assertSession()->pageTextNotContains($node_with_term_1_0->label());
|
||||
$this->assertSession()->pageTextNotContains($node_with_terms_1_0_and_1_1->label());
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_2_0->label());
|
||||
$this->assertSession()->pageTextContainsOnce($node_no_term->label());
|
||||
|
||||
// Case 2:
|
||||
// - filter "tid" with multiple terms as "is one of"
|
||||
// - filter "tid_2" with a single term as "is one of"
|
||||
$view = View::load('test_filter_taxonomy_index_tid');
|
||||
$display =& $view->getDisplay('default');
|
||||
$display['display_options']['filters']['tid']['value'][0] = $this->terms[1][0]->id();
|
||||
$display['display_options']['filters']['tid']['value'][1] = $this->terms[1][1]->id();
|
||||
$display['display_options']['filters']['tid']['operator'] = 'or';
|
||||
$display['display_options']['filters']['tid']['group'] = 2;
|
||||
$display['display_options']['filters']['tid_2'] = $display['display_options']['filters']['tid'];
|
||||
$display['display_options']['filters']['tid_2']['id'] = 'tid_2';
|
||||
$display['display_options']['filters']['tid_2']['value'][0] = $this->terms[2][0]->id();
|
||||
$display['display_options']['filters']['tid_2']['operator'] = 'or';
|
||||
$display['display_options']['filters']['tid_2']['group'] = 2;
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// We expect all the tagged nodes but not the untagged node.
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_1_0->label());
|
||||
// The view does not have DISTINCT query enabled, the node tagged with
|
||||
// both 1.0 and 1.1 will appear twice.
|
||||
$this->assertSession()->pageTextMatchesCount(2, "/{$node_with_terms_1_0_and_1_1->label()}/");
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_2_0->label());
|
||||
$this->assertSession()->pageTextNotContains($node_no_term->label());
|
||||
|
||||
// Case 3:
|
||||
// - filter "tid" with a single term as "is none of"
|
||||
// - filter "tid_2" with a single term as "is one of"
|
||||
$view = View::load('test_filter_taxonomy_index_tid');
|
||||
$display =& $view->getDisplay('default');
|
||||
$display['display_options']['filters']['tid']['value'] = [];
|
||||
$display['display_options']['filters']['tid']['value'][0] = $this->terms[1][0]->id();
|
||||
$display['display_options']['filters']['tid']['operator'] = 'not';
|
||||
$display['display_options']['filters']['tid']['group'] = 2;
|
||||
$display['display_options']['filters']['tid_2'] = $display['display_options']['filters']['tid'];
|
||||
$display['display_options']['filters']['tid_2']['id'] = 'tid_2';
|
||||
$display['display_options']['filters']['tid_2']['value'][0] = $this->terms[2][0]->id();
|
||||
$display['display_options']['filters']['tid_2']['operator'] = 'or';
|
||||
$display['display_options']['filters']['tid_2']['group'] = 2;
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// We expect none of the nodes tagged with term 1.0. The node tagged with
|
||||
// term 2.0 and the untagged node should be shown.
|
||||
$this->assertSession()->pageTextNotContains($node_with_term_1_0->label());
|
||||
$this->assertSession()->pageTextNotContains($node_with_terms_1_0_and_1_1->label());
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_2_0->label());
|
||||
$this->assertSession()->pageTextContainsOnce($node_no_term->label());
|
||||
|
||||
// Case 4:
|
||||
// - filter "tid" with a single term as "is one of"
|
||||
// - filter "tid_2" with a single term as "is one of"
|
||||
$view = View::load('test_filter_taxonomy_index_tid');
|
||||
$display =& $view->getDisplay('default');
|
||||
$display['display_options']['filters']['tid']['value'] = [];
|
||||
$display['display_options']['filters']['tid']['value'][0] = $this->terms[1][0]->id();
|
||||
$display['display_options']['filters']['tid']['operator'] = 'or';
|
||||
$display['display_options']['filters']['tid']['group'] = 2;
|
||||
$display['display_options']['filters']['tid_2'] = $display['display_options']['filters']['tid'];
|
||||
$display['display_options']['filters']['tid_2']['id'] = 'tid_2';
|
||||
$display['display_options']['filters']['tid_2']['value'][0] = $this->terms[2][0]->id();
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// We expect all the tagged nodes to be shown but not the untagged node.
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_1_0->label());
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_terms_1_0_and_1_1->label());
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_2_0->label());
|
||||
$this->assertSession()->pageTextNotContains($node_no_term->label());
|
||||
|
||||
// Different fields/taxonomies filters/values.
|
||||
// Case 5: OR
|
||||
// - filter "tid" with terms from tags as "is one of"
|
||||
// - filter "taxonomy_other_tags_target_id" with term from other tags
|
||||
// as "is one of".
|
||||
$view = View::load('test_filter_taxonomy_index_tid');
|
||||
$display = &$view->getDisplay('default');
|
||||
$display['display_options']['filters']['tid']['value'][0] = $this->terms[1][0]->id();
|
||||
$display['display_options']['filters']['tid']['value'][1] = $this->terms[1][1]->id();
|
||||
$display['display_options']['filters']['tid']['operator'] = 'or';
|
||||
$display['display_options']['filters']['tid']['group'] = 2;
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id'] = $display['display_options']['filters']['tid'];
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id']['id'] = 'taxonomy_other_tags_target_id';
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id']['value'][0] = $this->terms[3][0]->id();
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id']['operator'] = 'or';
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id']['group'] = 2;
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id']['table'] = 'node__taxonomy_other_tags';
|
||||
$display['display_options']['filters']['taxonomy_other_tags_target_id']['field'] = 'taxonomy_other_tags_target_id';
|
||||
unset($display['display_options']['filters']['tid_2']);
|
||||
$display['display_options']['filter_groups'] = [
|
||||
'operator' => 'AND',
|
||||
'groups' => [
|
||||
1 => 'AND',
|
||||
2 => 'OR',
|
||||
],
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet('test-filter-taxonomy-index-tid');
|
||||
// We expect no nodes tagged with term 1.0 or 1.1. The node tagged with
|
||||
// term 3.0 and the untagged node will be shown.
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_1_0->label());
|
||||
// The view does not have DISTINCT query enabled, the node tagged with
|
||||
// both 1.0 and 1.1 will appear twice.
|
||||
$this->assertSession()->pageTextMatchesCount(2, "/{$node_with_terms_1_0_and_1_1->label()}/");
|
||||
$this->assertSession()->pageTextContainsOnce($node_with_term_3_0->label());
|
||||
$this->assertSession()->pageTextNotContains($node_with_term_2_0->label());
|
||||
$this->assertSession()->pageTextNotContains($node_no_term->label());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Tests\views_ui\Functional\UITestBase;
|
||||
|
||||
/**
|
||||
* Tests views taxonomy parent plugin UI.
|
||||
*
|
||||
* @group taxonomy
|
||||
* @see Drupal\taxonomy\Plugin\views\access\Role
|
||||
*/
|
||||
class TaxonomyParentUITest extends UITestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_taxonomy_parent'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'taxonomy_test_views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = ['taxonomy_test_views']): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the taxonomy parent plugin UI.
|
||||
*/
|
||||
public function testTaxonomyParentUI(): void {
|
||||
$this->drupalGet('admin/structure/views/nojs/handler/test_taxonomy_parent/default/relationship/parent');
|
||||
$this->assertSession()->pageTextNotContains('The handler for this item is broken or missing.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests taxonomy relationships with parent term and node.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyRelationshipTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* Stores the terms used in the tests.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface[]
|
||||
*/
|
||||
protected $terms = [];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_taxonomy_term_relationship'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
// Make term2 parent of term1.
|
||||
$this->term1->set('parent', $this->term2->id());
|
||||
$this->term1->save();
|
||||
// Store terms in an array for testing.
|
||||
$this->terms[] = $this->term1;
|
||||
$this->terms[] = $this->term2;
|
||||
// Only set term1 on node1 and term2 on node2 for testing.
|
||||
unset($this->nodes[0]->field_views_testing_tags[1]);
|
||||
$this->nodes[0]->save();
|
||||
unset($this->nodes[1]->field_views_testing_tags[0]);
|
||||
$this->nodes[1]->save();
|
||||
|
||||
Views::viewsData()->clear();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the taxonomy parent plugin UI.
|
||||
*/
|
||||
public function testTaxonomyRelationships(): void {
|
||||
|
||||
// Check the generated views data of taxonomy_index.
|
||||
$views_data = Views::viewsData()->get('taxonomy_index');
|
||||
// Check the table join data.
|
||||
$this->assertEquals('tid', $views_data['table']['join']['taxonomy_term_field_data']['left_field']);
|
||||
$this->assertEquals('tid', $views_data['table']['join']['taxonomy_term_field_data']['field']);
|
||||
$this->assertEquals('nid', $views_data['table']['join']['node_field_data']['left_field']);
|
||||
$this->assertEquals('nid', $views_data['table']['join']['node_field_data']['field']);
|
||||
$this->assertEquals('entity_id', $views_data['table']['join']['taxonomy_term__parent']['left_field']);
|
||||
$this->assertEquals('tid', $views_data['table']['join']['taxonomy_term__parent']['field']);
|
||||
|
||||
// Check the generated views data of taxonomy_term__parent.
|
||||
$views_data = Views::viewsData()->get('taxonomy_term__parent');
|
||||
// Check the table join data.
|
||||
$this->assertEquals('entity_id', $views_data['table']['join']['taxonomy_term__parent']['left_field']);
|
||||
$this->assertEquals('parent_target_id', $views_data['table']['join']['taxonomy_term__parent']['field']);
|
||||
$this->assertEquals('tid', $views_data['table']['join']['taxonomy_term_field_data']['left_field']);
|
||||
$this->assertEquals('entity_id', $views_data['table']['join']['taxonomy_term_field_data']['field']);
|
||||
// Check the parent relationship data.
|
||||
$this->assertEquals('taxonomy_term_field_data', $views_data['parent_target_id']['relationship']['base']);
|
||||
$this->assertEquals('tid', $views_data['parent_target_id']['relationship']['base field']);
|
||||
$this->assertEquals('Parent', $views_data['parent_target_id']['relationship']['label']);
|
||||
$this->assertEquals('standard', $views_data['parent_target_id']['relationship']['id']);
|
||||
// Check the parent filter and argument data.
|
||||
$this->assertEquals('numeric', $views_data['parent_target_id']['filter']['id']);
|
||||
$this->assertEquals('taxonomy', $views_data['parent_target_id']['argument']['id']);
|
||||
|
||||
// Check an actual test view.
|
||||
$view = Views::getView('test_taxonomy_term_relationship');
|
||||
$this->executeView($view);
|
||||
/** @var \Drupal\views\ResultRow $row */
|
||||
foreach ($view->result as $index => $row) {
|
||||
// Check that the actual ID of the entity is the expected one.
|
||||
$this->assertEquals($this->terms[$index]->id(), $row->tid);
|
||||
|
||||
// Also check that we have the correct result entity.
|
||||
$this->assertEquals($this->terms[$index]->id(), $row->_entity->id());
|
||||
$this->assertInstanceOf(TermInterface::class, $row->_entity);
|
||||
|
||||
if (!$index) {
|
||||
$this->assertInstanceOf(TermInterface::class, $row->_relationship_entities['parent']);
|
||||
$this->assertEquals($this->term2->id(), $row->_relationship_entities['parent']->id());
|
||||
$this->assertEquals($this->term2->id(), $row->taxonomy_term_field_data_taxonomy_term__parent_tid);
|
||||
}
|
||||
$this->assertInstanceOf(NodeInterface::class, $row->_relationship_entities['nid']);
|
||||
$this->assertEquals($this->nodes[$index]->id(), $row->_relationship_entities['nid']->id());
|
||||
}
|
||||
|
||||
// Test node fields are available through relationship.
|
||||
\Drupal::service('module_installer')->install(['views_ui']);
|
||||
$this->drupalLogin($this->createUser(['administer views']));
|
||||
$this->drupalGet('admin/structure/views/view/test_taxonomy_term_relationship');
|
||||
$this->click('#views-add-field');
|
||||
$this->assertSession()->pageTextContains('Body');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term with depth argument.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyTermArgumentDepthTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'taxonomy',
|
||||
'taxonomy_test_views',
|
||||
'views',
|
||||
'node',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_argument_taxonomy_index_tid_depth'];
|
||||
|
||||
/**
|
||||
* @var \Drupal\taxonomy\TermInterface[]
|
||||
*/
|
||||
protected $terms = [];
|
||||
|
||||
/**
|
||||
* @var \Drupal\views\ViewExecutable
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
// Create a term with markup in the label.
|
||||
$first = $this->createTerm(['name' => '<em>First</em>']);
|
||||
|
||||
// Create a node w/o any terms.
|
||||
$settings = ['type' => 'article'];
|
||||
|
||||
// Create a node with linked to the term.
|
||||
$settings['field_views_testing_tags'][0]['target_id'] = $first->id();
|
||||
$this->nodes[] = $this->drupalCreateNode($settings);
|
||||
|
||||
$this->terms[0] = $first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests title escaping.
|
||||
*/
|
||||
public function testTermWithDepthArgumentTitleEscaping(): void {
|
||||
$this->drupalGet('test_argument_taxonomy_index_tid_depth/' . $this->terms[0]->id());
|
||||
$this->assertSession()->assertEscaped($this->terms[0]->label());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term view page and its translation.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyTermViewTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* A user with permissions to administer taxonomy.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* Name of the taxonomy term reference field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName1;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
// Create an administrative user.
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'bypass node access',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Create a vocabulary and add two term reference fields to article nodes.
|
||||
|
||||
$this->fieldName1 = $this->randomMachineName();
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $this->fieldName1, '', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($this->fieldName1, [
|
||||
'type' => 'options_select',
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($this->fieldName1, [
|
||||
'type' => 'entity_reference_label',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the taxonomy term view is working properly.
|
||||
*/
|
||||
public function testTaxonomyTermView(): void {
|
||||
// Create terms in the vocabulary.
|
||||
$term = $this->createTerm();
|
||||
|
||||
// Post an article.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $original_title = $this->randomMachineName();
|
||||
$edit['body[0][value]'] = $this->randomMachineName();
|
||||
$edit["{$this->fieldName1}[]"] = $term->id();
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->pageTextContains($term->label());
|
||||
$this->assertSession()->pageTextContains($node->label());
|
||||
|
||||
\Drupal::service('module_installer')->install(['language', 'content_translation']);
|
||||
ConfigurableLanguage::createFromLangcode('ur')->save();
|
||||
// Enable translation for the article content type and ensure the change is
|
||||
// picked up.
|
||||
\Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE);
|
||||
$roles = $this->adminUser->getRoles(TRUE);
|
||||
Role::load(reset($roles))
|
||||
->grantPermission('create content translations')
|
||||
->grantPermission('translate any entity')
|
||||
->save();
|
||||
|
||||
$edit['title[0][value]'] = $translated_title = $this->randomMachineName();
|
||||
|
||||
$this->drupalGet('node/' . $node->id() . '/translations/add/en/ur');
|
||||
$this->submitForm($edit, 'Save (this translation)');
|
||||
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->pageTextContains($term->label());
|
||||
$this->assertSession()->pageTextContains($original_title);
|
||||
$this->assertSession()->pageTextNotContains($translated_title);
|
||||
|
||||
$this->drupalGet('ur/taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->pageTextContains($term->label());
|
||||
$this->assertSession()->pageTextNotContains($original_title);
|
||||
$this->assertSession()->pageTextContains($translated_title);
|
||||
|
||||
// Uninstall language module and ensure that the language is not part of the
|
||||
// query anymore.
|
||||
// @see \Drupal\views\Plugin\views\filter\LanguageFilter::query()
|
||||
$node->delete();
|
||||
|
||||
// We also have to remove the nodes created by the parent ::setUp() method
|
||||
// if we want to be able to uninstall the Content Translation module.
|
||||
foreach (Node::loadMultiple() as $node) {
|
||||
$node->delete();
|
||||
}
|
||||
\Drupal::service('module_installer')->uninstall(['content_translation', 'language']);
|
||||
|
||||
$view = Views::getView('taxonomy_term');
|
||||
$view->initDisplay();
|
||||
$view->setArguments([$term->id()]);
|
||||
$view->build();
|
||||
/** @var \Drupal\Core\Database\Query\Select $query */
|
||||
$query = $view->build_info['query'];
|
||||
$tables = $query->getTables();
|
||||
|
||||
// Ensure that the join to node_field_data is not added by default.
|
||||
$this->assertEquals(['node_field_data', 'taxonomy_index'], array_keys($tables));
|
||||
// Ensure that the filter to the language column is not there by default.
|
||||
$condition = $query->conditions();
|
||||
// We only want to check the no. of conditions in the query.
|
||||
unset($condition['#conjunction']);
|
||||
$this->assertCount(1, $condition);
|
||||
|
||||
// Clear permissions for anonymous users to check access for default views.
|
||||
Role::load(RoleInterface::ANONYMOUS_ID)->revokePermission('access content')->save();
|
||||
|
||||
// Test the default views disclose no data by default.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('taxonomy/term/' . $term->id());
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/feed');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Base class for all taxonomy tests.
|
||||
*/
|
||||
abstract class TaxonomyTestBase extends ViewTestBase {
|
||||
|
||||
use EntityReferenceFieldCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'taxonomy_test_views'];
|
||||
|
||||
/**
|
||||
* Stores the nodes used for the different tests.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface[]
|
||||
*/
|
||||
protected $nodes = [];
|
||||
|
||||
/**
|
||||
* The vocabulary used for creating terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* Stores the first term used in the different tests.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface
|
||||
*/
|
||||
protected $term1;
|
||||
|
||||
/**
|
||||
* Stores the second term used in the different tests.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface
|
||||
*/
|
||||
protected $term2;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
// Important: taxonomy_test_views module must not be in the $modules to
|
||||
// avoid an issue that particular view is already exists.
|
||||
parent::setUp($import_test_views, $modules);
|
||||
$this->mockStandardInstall();
|
||||
|
||||
// This needs to be done again after ::mockStandardInstall() to make
|
||||
// test vocabularies available.
|
||||
// Explicitly add taxonomy_test_views to $modules now, so required views are
|
||||
// being created.
|
||||
$modules[] = 'taxonomy_test_views';
|
||||
if ($import_test_views) {
|
||||
ViewTestData::createTestViews(static::class, $modules);
|
||||
}
|
||||
|
||||
$this->term1 = $this->createTerm();
|
||||
$this->term2 = $this->createTerm();
|
||||
|
||||
$node = [];
|
||||
$node['type'] = 'article';
|
||||
$node['field_views_testing_tags'][]['target_id'] = $this->term1->id();
|
||||
$node['field_views_testing_tags'][]['target_id'] = $this->term2->id();
|
||||
$this->nodes[] = $this->drupalCreateNode($node);
|
||||
$this->nodes[] = $this->drupalCreateNode($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a workaround for the inability to use the standard profile.
|
||||
*
|
||||
* @see https://www.drupal.org/node/1708692
|
||||
*/
|
||||
protected function mockStandardInstall() {
|
||||
$this->drupalCreateContentType([
|
||||
'type' => 'article',
|
||||
]);
|
||||
// Create the vocabulary for the tag field.
|
||||
$this->vocabulary = Vocabulary::create([
|
||||
'name' => 'Views testing tags',
|
||||
'vid' => 'views_testing_tags',
|
||||
]);
|
||||
$this->vocabulary->save();
|
||||
$field_name = 'field_' . $this->vocabulary->id();
|
||||
|
||||
$handler_settings = [
|
||||
'target_bundles' => [
|
||||
$this->vocabulary->id() => $this->vocabulary->id(),
|
||||
],
|
||||
'auto_create' => TRUE,
|
||||
];
|
||||
$this->createEntityReferenceField('node', 'article', $field_name, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = \Drupal::service('entity_display.repository');
|
||||
$display_repository->getFormDisplay('node', 'article')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'entity_reference_autocomplete_tags',
|
||||
'weight' => -4,
|
||||
])
|
||||
->save();
|
||||
|
||||
$display_repository->getViewDisplay('node', 'article')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'entity_reference_label',
|
||||
'weight' => 10,
|
||||
])
|
||||
->save();
|
||||
$display_repository->getViewDisplay('node', 'article', 'teaser')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'entity_reference_label',
|
||||
'weight' => 10,
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a taxonomy term.
|
||||
*
|
||||
* @param array $settings
|
||||
* (optional) An array of values to override the following default
|
||||
* properties of the term:
|
||||
* - name: A random string.
|
||||
* - description: A random string.
|
||||
* - format: First available text format.
|
||||
* - vid: Vocabulary ID of self::$vocabulary object.
|
||||
* - langcode: LANGCODE_NOT_SPECIFIED.
|
||||
* Defaults to an empty array.
|
||||
*
|
||||
* @return \Drupal\taxonomy\Entity\Term
|
||||
* The created taxonomy term.
|
||||
*/
|
||||
protected function createTerm(array $settings = []) {
|
||||
$filter_formats = filter_formats();
|
||||
$format = array_pop($filter_formats);
|
||||
$settings += [
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
// Use the first available text format.
|
||||
'format' => $format->id(),
|
||||
'vid' => $this->vocabulary->id(),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
];
|
||||
$term = Term::create($settings);
|
||||
$term->save();
|
||||
return $term;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the vocabulary argument.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyVocabularyArgumentTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'taxonomy_test_views', 'views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_argument_taxonomy_vocabulary'];
|
||||
|
||||
/**
|
||||
* @var \Drupal\taxonomy\TermInterface[]
|
||||
*/
|
||||
protected $terms = [];
|
||||
|
||||
/**
|
||||
* Vocabularies used for creating terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface[]
|
||||
*/
|
||||
protected $vocabularies;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
// Add default vocabulary to list of vocabularies.
|
||||
$this->vocabularies[] = $this->vocabulary;
|
||||
// Create additional vocabulary.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Views testing category',
|
||||
'vid' => 'views_testing_category',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
$this->vocabularies[] = $vocabulary;
|
||||
|
||||
// Create some terms.
|
||||
$this->terms[0] = $this->createTerm([
|
||||
'name' => 'First',
|
||||
'vid' => $this->vocabularies[0]->id(),
|
||||
]);
|
||||
$this->terms[1] = $this->createTerm([
|
||||
'name' => 'Second',
|
||||
'vid' => $this->vocabularies[1]->id(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the vocabulary argument handler.
|
||||
*
|
||||
* @see Drupal\taxonomy\Plugin\views\argument\VocabularyVid
|
||||
*/
|
||||
public function testTermWithVocabularyArgument(): void {
|
||||
$this->drupalGet('test_argument_taxonomy_vocabulary/' . $this->vocabularies[0]->id());
|
||||
// First term should be present.
|
||||
$this->assertSession()->pageTextContains($this->terms[0]->label());
|
||||
// Second term should not be present.
|
||||
$this->assertSession()->pageTextNotContains($this->terms[1]->label());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
/**
|
||||
* Tests making taxonomy term base fields' displays configurable.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermDisplayConfigurableTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_term_show_entity'];
|
||||
|
||||
/**
|
||||
* Sets base fields to configurable display and check settings are respected.
|
||||
*/
|
||||
public function testDisplayConfigurable(): void {
|
||||
$user = $this->drupalCreateUser(['administer nodes']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$assert = $this->assertSession();
|
||||
|
||||
// Check the taxonomy_term with default non-configurable display.
|
||||
$this->drupalGet('test_term_show_entity');
|
||||
// Name should be linked to entity and description should be displayed.
|
||||
$assert->pageTextContains($this->term1->getName());
|
||||
$assert->linkByHrefExists($this->term1->toUrl()->toString());
|
||||
$assert->pageTextContains($this->term1->getDescription());
|
||||
$assert->pageTextContains($this->term2->getName());
|
||||
$assert->linkByHrefExists($this->term2->toUrl()->toString());
|
||||
$assert->pageTextContains($this->term2->getDescription());
|
||||
// The field labels should not be present.
|
||||
$assert->pageTextNotContains('Name');
|
||||
$assert->pageTextNotContains('Description');
|
||||
|
||||
// Enable helper module to make base fields' displays configurable.
|
||||
\Drupal::service('module_installer')->install(['taxonomy_term_display_configurable_test']);
|
||||
|
||||
// Configure display.
|
||||
$display = \Drupal::service('entity_display.repository')->getViewDisplay('taxonomy_term', $this->vocabulary->id(), 'default');
|
||||
$display->setComponent('name', [
|
||||
'type' => 'text_default',
|
||||
'label' => 'above',
|
||||
])->save();
|
||||
|
||||
// Recheck the taxonomy_term with configurable display.
|
||||
$this->drupalGet('test_term_show_entity');
|
||||
// The description should be the first field in each row, with no label.
|
||||
// Name field should be the second field in view row. Value should be
|
||||
// displayed after the label. It should not be linked to the term.
|
||||
$assert->pageTextContains('Name');
|
||||
$assert->pageTextNotContains('Description');
|
||||
$assert->pageTextContains($this->term1->getName());
|
||||
$assert->linkByHrefNotExists($this->term1->toUrl()->toString());
|
||||
$assert->pageTextContains($this->term1->getDescription());
|
||||
$assert->elementTextContains('xpath', '//*[@class="views-row"][1]/div/div[1]//p', $this->term1->getDescription());
|
||||
$assert->elementTextContains('xpath', '//*[@class="views-row"][1]/div/div[2]/div[1]', 'Name');
|
||||
$assert->elementTextContains('xpath', '//*[@class="views-row"][1]/div/div[2]/div[2]', $this->term1->getName());
|
||||
$assert->pageTextContains($this->term2->getName());
|
||||
$assert->linkByHrefNotExists($this->term2->toUrl()->toString());
|
||||
$assert->pageTextContains($this->term2->getDescription());
|
||||
$assert->elementTextContains('xpath', '//*[@class="views-row"][2]/div/div[1]//p', $this->term2->getDescription());
|
||||
$assert->elementTextContains('xpath', '//*[@class="views-row"][2]/div/div[2]/div[1]', 'Name');
|
||||
$assert->elementTextContains('xpath', '//*[@class="views-row"][2]/div/div[2]/div[2]', $this->term2->getName());
|
||||
|
||||
// Remove 'name' field from display.
|
||||
$display->removeComponent('name')->save();
|
||||
|
||||
// Recheck the taxonomy_term with 'name' field removed from display.
|
||||
// There should just be an unlabelled description. Nothing should be
|
||||
// linked to the terms.
|
||||
$this->drupalGet('test_term_show_entity');
|
||||
$assert->pageTextNotContains('Name');
|
||||
$assert->pageTextNotContains('Description');
|
||||
$assert->pageTextNotContains($this->term1->getName());
|
||||
$assert->linkByHrefNotExists($this->term1->toUrl()->toString());
|
||||
$assert->pageTextContains($this->term1->getDescription());
|
||||
$assert->pageTextNotContains($this->term2->getName());
|
||||
$assert->linkByHrefNotExists($this->term2->toUrl()->toString());
|
||||
$assert->pageTextContains($this->term2->getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the term_name field handler.
|
||||
*
|
||||
* @group taxonomy
|
||||
*
|
||||
* @see \Drupal\taxonomy\Plugin\views\field\TermName
|
||||
*/
|
||||
class TermNameFieldTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_taxonomy_term_name'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests term name field plugin functionality.
|
||||
*/
|
||||
public function testTermNameField(): void {
|
||||
$this->term1->name->value = $this->randomMachineName() . ' ' . $this->randomMachineName();
|
||||
$this->term1->save();
|
||||
|
||||
$user = $this->drupalCreateUser(['access content']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$view = Views::getView('test_taxonomy_term_name');
|
||||
$view->initDisplay();
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEquals($this->term1->getName(), $view->getStyle()->getField(0, 'name'));
|
||||
$this->assertEquals($this->term2->getName(), $view->getStyle()->getField(1, 'name'));
|
||||
|
||||
$view = Views::getView('test_taxonomy_term_name');
|
||||
$display =& $view->storage->getDisplay('default');
|
||||
$display['display_options']['fields']['name']['convert_spaces'] = TRUE;
|
||||
$view->storage->invalidateCaches();
|
||||
$this->executeView($view);
|
||||
|
||||
$this->assertEquals(str_replace(' ', '-', $this->term1->getName()), $view->getStyle()->getField(0, 'name'));
|
||||
$this->assertEquals($this->term2->getName(), $view->getStyle()->getField(1, 'name'));
|
||||
|
||||
// Enable link_to_entity option and ensure that title is displayed properly.
|
||||
$view = Views::getView('test_taxonomy_term_name');
|
||||
$display =& $view->storage->getDisplay('default');
|
||||
$display['display_options']['fields']['name']['convert_spaces'] = TRUE;
|
||||
$display['display_options']['fields']['name']['settings']['link_to_entity'] = TRUE;
|
||||
$view->storage->invalidateCaches();
|
||||
$this->executeView($view);
|
||||
|
||||
$expected_link1 = Link::fromTextAndUrl(str_replace(' ', '-', $this->term1->getName()), $this->term1->toUrl());
|
||||
$expected_link2 = Link::fromTextAndUrl($this->term2->getName(), $this->term2->toUrl());
|
||||
$this->assertEquals($expected_link1->toString(), $view->getStyle()->getField(0, 'name'));
|
||||
$this->assertEquals($expected_link2->toString(), $view->getStyle()->getField(1, 'name'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Views;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\taxonomy\Functional\TaxonomyTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* Tests for views translation.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTranslationViewsTest extends TaxonomyTestBase {
|
||||
|
||||
use TaxonomyTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* Term to translated term mapping.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $termTranslationMap = [
|
||||
'one' => 'translatedOne',
|
||||
'two' => 'translatedTwo',
|
||||
'three' => 'translatedThree',
|
||||
];
|
||||
|
||||
/**
|
||||
* Created terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Term[]
|
||||
*/
|
||||
protected $terms = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'language', 'content_translation', 'views'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['taxonomy_translated_term_name_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Language object.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageInterface|null
|
||||
*/
|
||||
protected $translationLanguage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = []): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
$this->setupLanguages();
|
||||
$this->enableTranslation();
|
||||
$this->setUpTerms();
|
||||
$this->translationLanguage = \Drupal::languageManager()->getLanguage($this->translateToLangcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that proper translation is returned when contextual filter.
|
||||
*
|
||||
* Taxonomy term: Term ID & Content: Has taxonomy term ID (with depth)
|
||||
* contextual filters are enabled for two separate view modes.
|
||||
*/
|
||||
public function testTermsTranslationWithContextualFilter(): void {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
foreach ($this->terms as $term) {
|
||||
// Test with "Content: Has taxonomy term ID (with depth)" contextual
|
||||
// filter. Generate base language url and send request.
|
||||
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_1', ['arg_0' => $term->id()])->toString();
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains($term->label());
|
||||
|
||||
// Generate translation URL and send request.
|
||||
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_1', ['arg_0' => $term->id()], ['language' => $this->translationLanguage])->toString();
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains($this->termTranslationMap[$term->label()]);
|
||||
|
||||
// Test with "Taxonomy term: Term ID" contextual filter.
|
||||
// Generate base language url and send request.
|
||||
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_2', ['arg_0' => $term->id()])->toString();
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains($term->label());
|
||||
|
||||
// Generate translation URL and send request.
|
||||
$url = Url::fromRoute('view.taxonomy_translated_term_name_test.page_2', ['arg_0' => $term->id()], ['language' => $this->translationLanguage])->toString();
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->pageTextContains($this->termTranslationMap[$term->label()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup translated terms in a hierarchy.
|
||||
*/
|
||||
protected function setUpTerms(): void {
|
||||
$parent_vid = 0;
|
||||
foreach ($this->termTranslationMap as $name => $translation) {
|
||||
|
||||
$term = $this->createTerm([
|
||||
'name' => $name,
|
||||
'langcode' => $this->baseLangcode,
|
||||
'parent' => $parent_vid,
|
||||
'vid' => $this->vocabulary->id(),
|
||||
]);
|
||||
|
||||
$term->addTranslation($this->translateToLangcode, [
|
||||
'name' => $translation,
|
||||
]);
|
||||
$term->save();
|
||||
|
||||
// Each term is nested under the last.
|
||||
$parent_vid = $term->id();
|
||||
|
||||
$this->terms[] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
|
||||
/**
|
||||
* Tests the language functionality for vocabularies.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyLanguageTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create an administrative user.
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
|
||||
|
||||
// Add some custom languages.
|
||||
ConfigurableLanguage::create([
|
||||
'id' => 'aa',
|
||||
'label' => $this->randomMachineName(),
|
||||
])->save();
|
||||
|
||||
ConfigurableLanguage::create([
|
||||
'id' => 'bb',
|
||||
'label' => $this->randomMachineName(),
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language settings for vocabularies.
|
||||
*/
|
||||
public function testVocabularyLanguage(): void {
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
|
||||
// Check that we have the language selector available.
|
||||
$this->assertSession()->fieldExists('edit-langcode');
|
||||
|
||||
// Create the vocabulary.
|
||||
$vid = $this->randomMachineName();
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['description'] = $this->randomMachineName();
|
||||
$edit['langcode'] = 'aa';
|
||||
$edit['vid'] = $vid;
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check the language on the edit page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vid);
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode', $edit['langcode'])->isSelected());
|
||||
|
||||
// Change the language and save again.
|
||||
$edit['langcode'] = 'bb';
|
||||
unset($edit['vid']);
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check again the language on the edit page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vid);
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-langcode', $edit['langcode'])->isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests term language settings for vocabulary terms are saved and updated.
|
||||
*/
|
||||
public function testVocabularyDefaultLanguageForTerms(): void {
|
||||
// Add a new vocabulary and check that the default language settings are for
|
||||
// the terms are saved.
|
||||
$edit = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $this->randomMachineName(),
|
||||
'default_language[langcode]' => 'bb',
|
||||
'default_language[language_alterable]' => TRUE,
|
||||
];
|
||||
$vid = $edit['vid'];
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that the vocabulary was actually created.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $edit['vid']);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
// Check that the language settings were saved.
|
||||
$language_settings = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', $edit['vid']);
|
||||
$this->assertEquals('bb', $language_settings->getDefaultLangcode(), 'The langcode was saved.');
|
||||
$this->assertTrue($language_settings->isLanguageAlterable(), 'The visibility setting was saved.');
|
||||
|
||||
// Check that the correct options are selected in the interface.
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-default-language-langcode', 'bb')->isSelected());
|
||||
$this->assertSession()->checkboxChecked('edit-default-language-language-alterable');
|
||||
|
||||
// Edit the vocabulary and check that the new settings are updated.
|
||||
$edit = [
|
||||
'default_language[langcode]' => 'aa',
|
||||
'default_language[language_alterable]' => FALSE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vid);
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// And check again the settings and also the interface.
|
||||
$language_settings = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', $vid);
|
||||
$this->assertEquals('aa', $language_settings->getDefaultLangcode(), 'The langcode was saved.');
|
||||
$this->assertFalse($language_settings->isLanguageAlterable(), 'The visibility setting was saved.');
|
||||
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vid);
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-default-language-langcode', 'aa')->isSelected());
|
||||
$this->assertSession()->checkboxNotChecked('edit-default-language-language-alterable');
|
||||
|
||||
// Check that language settings are changed after editing vocabulary.
|
||||
$edit = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'default_language[langcode]' => 'authors_default',
|
||||
'default_language[language_alterable]' => FALSE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vid);
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check that we have the new settings.
|
||||
$new_settings = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', $vid);
|
||||
$this->assertEquals('authors_default', $new_settings->getDefaultLangcode(), 'The langcode was saved.');
|
||||
$this->assertFalse($new_settings->isLanguageAlterable(), 'The new visibility setting was saved.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy vocabulary permissions.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyPermissionsTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['help'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
$this->drupalPlaceBlock('local_actions_block');
|
||||
$this->drupalPlaceBlock('help_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, edit and delete a vocabulary via the user interface.
|
||||
*/
|
||||
public function testVocabularyPermissionsVocabulary(): void {
|
||||
// VocabularyTest.php already tests for user with "administer taxonomy"
|
||||
// permission.
|
||||
|
||||
// Test as user without proper permissions.
|
||||
$authenticated_user = $this->drupalCreateUser([]);
|
||||
$this->drupalLogin($authenticated_user);
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
// Visit the main taxonomy administration page.
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
|
||||
// Test as user with "access taxonomy overview" permissions.
|
||||
$proper_user = $this->drupalCreateUser(['access taxonomy overview']);
|
||||
$this->drupalLogin($proper_user);
|
||||
|
||||
// Visit the main taxonomy administration page.
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('Vocabulary name');
|
||||
$assert_session->linkNotExists('Add vocabulary');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the vocabulary overview permission.
|
||||
*/
|
||||
public function testTaxonomyVocabularyOverviewPermissions(): void {
|
||||
// Create two vocabularies, one with two terms, the other without any term.
|
||||
/** @var \Drupal\taxonomy\Entity\Vocabulary $vocabulary1 , $vocabulary2 */
|
||||
$vocabulary1 = $this->createVocabulary();
|
||||
$vocabulary2 = $this->createVocabulary();
|
||||
$vocabulary1_id = $vocabulary1->id();
|
||||
$vocabulary2_id = $vocabulary2->id();
|
||||
$this->createTerm($vocabulary1);
|
||||
$this->createTerm($vocabulary1);
|
||||
|
||||
// Assert expected help texts on first vocabulary.
|
||||
$vocabulary1_label = Unicode::ucfirst($vocabulary1->label());
|
||||
$edit_help_text = "You can reorganize the terms in $vocabulary1_label using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.";
|
||||
$no_edit_help_text = "$vocabulary1_label contains the following terms.";
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
// Logged in as admin user with 'administer taxonomy' permission.
|
||||
$admin_user = $this->drupalCreateUser(['administer taxonomy']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->linkExists('Edit');
|
||||
$assert_session->linkExists('Delete');
|
||||
$assert_session->linkExists('Add term');
|
||||
$assert_session->buttonExists('Save');
|
||||
$assert_session->pageTextContains('Weight');
|
||||
$assert_session->fieldExists('Weight');
|
||||
$assert_session->pageTextContains($edit_help_text);
|
||||
|
||||
$this->submitForm([], 'Reset to alphabetical');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
|
||||
// Visit vocabulary overview without terms. 'Add term' should be shown.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('No terms available');
|
||||
$assert_session->linkExists('Add term');
|
||||
|
||||
// Login as a user without any of the required permissions.
|
||||
$no_permission_user = $this->drupalCreateUser();
|
||||
$this->drupalLogin($no_permission_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
|
||||
// Log in as a user with only the overview permission, neither edit nor
|
||||
// delete operations must be available and no Save button.
|
||||
$overview_only_user = $this->drupalCreateUser(['access taxonomy overview']);
|
||||
$this->drupalLogin($overview_only_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->linkNotExists('Edit');
|
||||
$assert_session->linkNotExists('Delete');
|
||||
$assert_session->buttonNotExists('Save');
|
||||
$assert_session->buttonNotExists('Reset to alphabetical');
|
||||
$assert_session->pageTextContains('Weight');
|
||||
$assert_session->fieldNotExists('Weight');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
$assert_session->pageTextContains($no_edit_help_text);
|
||||
|
||||
// Visit vocabulary overview without terms. 'Add term' should not be shown.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('No terms available');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
|
||||
// Login as a user with permission to edit terms, only edit link should be
|
||||
// visible.
|
||||
$edit_user = $this->createUser([
|
||||
'access taxonomy overview',
|
||||
'edit terms in ' . $vocabulary1_id,
|
||||
'edit terms in ' . $vocabulary2_id,
|
||||
]);
|
||||
$this->drupalLogin($edit_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->linkExists('Edit');
|
||||
$assert_session->linkNotExists('Delete');
|
||||
$assert_session->buttonExists('Save');
|
||||
$assert_session->pageTextContains('Weight');
|
||||
$assert_session->fieldExists('Weight');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
$assert_session->pageTextContains($edit_help_text);
|
||||
|
||||
$this->submitForm([], 'Reset to alphabetical');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
|
||||
// Visit vocabulary overview without terms. 'Add term' should not be shown.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('No terms available');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
|
||||
// Login as a user with permission only to delete terms.
|
||||
$edit_delete_user = $this->createUser([
|
||||
'access taxonomy overview',
|
||||
'delete terms in ' . $vocabulary1_id,
|
||||
'delete terms in ' . $vocabulary2_id,
|
||||
]);
|
||||
$this->drupalLogin($edit_delete_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->linkNotExists('Edit');
|
||||
$assert_session->linkExists('Delete');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
$assert_session->buttonNotExists('Save');
|
||||
$assert_session->buttonNotExists('Reset to alphabetical');
|
||||
$assert_session->pageTextContains('Weight');
|
||||
$assert_session->fieldNotExists('Weight');
|
||||
$assert_session->pageTextContains($no_edit_help_text);
|
||||
|
||||
// Visit vocabulary overview without terms. 'Add term' should not be shown.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('No terms available');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
|
||||
// Login as a user with permission to edit and delete terms.
|
||||
$edit_delete_user = $this->createUser([
|
||||
'access taxonomy overview',
|
||||
'edit terms in ' . $vocabulary1_id,
|
||||
'delete terms in ' . $vocabulary1_id,
|
||||
'edit terms in ' . $vocabulary2_id,
|
||||
'delete terms in ' . $vocabulary2_id,
|
||||
]);
|
||||
$this->drupalLogin($edit_delete_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->linkExists('Edit');
|
||||
$assert_session->linkExists('Delete');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
$assert_session->buttonExists('Save');
|
||||
$assert_session->pageTextContains('Weight');
|
||||
$assert_session->fieldExists('Weight');
|
||||
$assert_session->pageTextContains($edit_help_text);
|
||||
$this->submitForm([], 'Reset to alphabetical');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
|
||||
// Visit vocabulary overview without terms. 'Add term' should not be shown.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('No terms available');
|
||||
$assert_session->linkNotExists('Add term');
|
||||
|
||||
// Login as a user with permission to create new terms, only add new term
|
||||
// link should be visible.
|
||||
$edit_user = $this->createUser([
|
||||
'access taxonomy overview',
|
||||
'create terms in ' . $vocabulary1_id,
|
||||
'create terms in ' . $vocabulary2_id,
|
||||
]);
|
||||
$this->drupalLogin($edit_user);
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary1_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->linkNotExists('Edit');
|
||||
$assert_session->linkNotExists('Delete');
|
||||
$assert_session->linkExists('Add term');
|
||||
$assert_session->buttonNotExists('Save');
|
||||
$assert_session->buttonNotExists('Reset to alphabetical');
|
||||
$assert_session->pageTextContains('Weight');
|
||||
$assert_session->fieldNotExists('Weight');
|
||||
$assert_session->pageTextContains($no_edit_help_text);
|
||||
|
||||
// Visit vocabulary overview without terms. 'Add term' should not be shown.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary2_id . '/overview');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->pageTextContains('No terms available');
|
||||
$assert_session->linkExists('Add term');
|
||||
|
||||
// Ensure the dynamic vocabulary permissions have the correct dependencies.
|
||||
$permissions = \Drupal::service('user.permissions')->getPermissions();
|
||||
$this->assertTrue(isset($permissions['create terms in ' . $vocabulary1_id]));
|
||||
$this->assertEquals(['config' => [$vocabulary1->getConfigDependencyName()]], $permissions['create terms in ' . $vocabulary1_id]['dependencies']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, edit and delete a taxonomy term via the user interface.
|
||||
*/
|
||||
public function testVocabularyPermissionsTaxonomyTerm(): void {
|
||||
// Vocabulary used for creating, removing and editing terms.
|
||||
$vocabulary = $this->createVocabulary();
|
||||
|
||||
// Test as admin user.
|
||||
$user = $this->drupalCreateUser(['administer taxonomy']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Visit the main taxonomy administration page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->fieldExists('edit-name-0-value');
|
||||
|
||||
// Submit the term.
|
||||
$edit = [];
|
||||
$edit['name[0][value]'] = $this->randomMachineName();
|
||||
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Created new term ' . $edit['name[0][value]'] . '.');
|
||||
|
||||
// Verify that the creation message contains a link to a term.
|
||||
$this->assertSession()->elementExists('xpath', '//div[@data-drupal-messages]//a[contains(@href, "term/")]');
|
||||
|
||||
$terms = \Drupal::entityTypeManager()
|
||||
->getStorage('taxonomy_term')
|
||||
->loadByProperties(['name' => $edit['name[0][value]']]);
|
||||
$term = reset($terms);
|
||||
|
||||
// Edit the term.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains($edit['name[0][value]']);
|
||||
|
||||
$edit['name[0][value]'] = $this->randomMachineName();
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]'] . '.');
|
||||
|
||||
// Delete the vocabulary.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/delete');
|
||||
$this->assertSession()->pageTextContains("Are you sure you want to delete the taxonomy term {$edit['name[0][value]']}?");
|
||||
|
||||
// Confirm deletion.
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertSession()->pageTextContains("Deleted term {$edit['name[0][value]']}.");
|
||||
|
||||
// Test as user with "create" permissions.
|
||||
$user = $this->drupalCreateUser(["create terms in {$vocabulary->id()}"]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
// Create a new term.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
$assert_session->fieldExists('name[0][value]');
|
||||
|
||||
// Submit the term.
|
||||
$edit = [];
|
||||
$edit['name[0][value]'] = $this->randomMachineName();
|
||||
|
||||
$this->submitForm($edit, 'Save');
|
||||
$assert_session->pageTextContains("Created new term {$edit['name[0][value]']}.");
|
||||
|
||||
$terms = \Drupal::entityTypeManager()
|
||||
->getStorage('taxonomy_term')
|
||||
->loadByProperties(['name' => $edit['name[0][value]']]);
|
||||
$term = reset($terms);
|
||||
|
||||
// Ensure that edit and delete access is denied.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/delete');
|
||||
$assert_session->statusCodeEquals(403);
|
||||
|
||||
// Test as user with "edit" permissions.
|
||||
$user = $this->drupalCreateUser(["edit terms in {$vocabulary->id()}"]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Ensure the taxonomy term add form is denied.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a test term.
|
||||
$term = $this->createTerm($vocabulary);
|
||||
|
||||
// Edit the term.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains($term->getName());
|
||||
|
||||
$edit['name[0][value]'] = $this->randomMachineName();
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]'] . '.');
|
||||
|
||||
// Verify that the update message contains a link to a term.
|
||||
$this->assertSession()->elementExists('xpath', '//div[@data-drupal-messages]//a[contains(@href, "term/")]');
|
||||
|
||||
// Ensure the term cannot be deleted.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/delete');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Test as user with "delete" permissions.
|
||||
$user = $this->drupalCreateUser(["delete terms in {$vocabulary->id()}"]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Ensure the taxonomy term add form is denied.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a test term.
|
||||
$term = $this->createTerm($vocabulary);
|
||||
|
||||
// Ensure that the term cannot be edited.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Delete the vocabulary.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/delete');
|
||||
$this->assertSession()->pageTextContains("Are you sure you want to delete the taxonomy term {$term->getName()}?");
|
||||
|
||||
// Confirm deletion.
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertSession()->pageTextContains("Deleted term {$term->getName()}.");
|
||||
|
||||
// Test as user without proper permissions.
|
||||
$user = $this->drupalCreateUser();
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Ensure the taxonomy term add form is denied.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a test term.
|
||||
$term = $this->createTerm($vocabulary);
|
||||
|
||||
// Ensure that the term cannot be edited.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/edit');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Ensure the term cannot be deleted.
|
||||
$this->drupalGet('taxonomy/term/' . $term->id() . '/delete');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests content translation for vocabularies.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyTranslationTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'config_translation',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Languages to enable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $additionalLangcodes = ['es'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create an administrative user.
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer taxonomy',
|
||||
'administer content translation',
|
||||
'translate configuration',
|
||||
]));
|
||||
|
||||
// Add languages.
|
||||
foreach ($this->additionalLangcodes as $langcode) {
|
||||
ConfigurableLanguage::createFromLangcode($langcode)->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language settings for vocabularies.
|
||||
*/
|
||||
public function testVocabularyLanguage(): void {
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
|
||||
// Check that the field to enable content translation is available.
|
||||
$this->assertSession()->fieldExists('edit-default-language-content-translation');
|
||||
|
||||
// Create the vocabulary.
|
||||
$vid = $this->randomMachineName();
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['description'] = $this->randomMachineName();
|
||||
$edit['langcode'] = 'en';
|
||||
$edit['vid'] = $vid;
|
||||
$edit['default_language[content_translation]'] = TRUE;
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Check if content translation is enabled on the edit page.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vid);
|
||||
$this->assertSession()->checkboxChecked('edit-default-language-content-translation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests vocabulary name translation for the overview and reset pages.
|
||||
*/
|
||||
public function testVocabularyTitleLabelTranslation(): void {
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
|
||||
// Create the vocabulary.
|
||||
$vid = $this->randomMachineName();
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['description'] = $this->randomMachineName();
|
||||
$edit['langcode'] = 'en';
|
||||
$edit['vid'] = $vid;
|
||||
$edit['default_language[content_translation]'] = TRUE;
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
$langcode = $this->additionalLangcodes[0];
|
||||
$vid_name = $edit['name'];
|
||||
$translated_vid_name = "Translated $vid_name";
|
||||
|
||||
$this->assertSession()->pageTextContains($vid_name);
|
||||
|
||||
// Assert that the name label is displayed on the translation form with the
|
||||
// right value.
|
||||
$this->drupalGet("admin/structure/taxonomy/manage/$vid/translate/$langcode/add");
|
||||
|
||||
// Translate the name label.
|
||||
$this->submitForm(["translation[config_names][taxonomy.vocabulary.$vid][name]" => $translated_vid_name], 'Save translation');
|
||||
|
||||
// Assert that the right name label is displayed on the taxonomy term
|
||||
// overview page.
|
||||
$this->drupalGet("admin/structure/taxonomy/manage/$vid/overview");
|
||||
$this->assertSession()->pageTextContains($vid_name);
|
||||
$this->drupalGet("$langcode/admin/structure/taxonomy/manage/$vid/overview");
|
||||
$this->assertSession()->pageTextContains($translated_vid_name);
|
||||
|
||||
// Assert that the right name label is displayed on the taxonomy reset page.
|
||||
$this->drupalGet("admin/structure/taxonomy/manage/$vid/reset");
|
||||
$this->assertSession()->pageTextContains($vid_name);
|
||||
$this->drupalGet("$langcode/admin/structure/taxonomy/manage/$vid/reset");
|
||||
$this->assertSession()->pageTextContains($translated_vid_name);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy vocabulary interface.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyUiTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* The vocabulary used for creating terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
|
||||
$this->vocabulary = $this->createVocabulary();
|
||||
$this->drupalPlaceBlock('local_actions_block');
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, edit and delete a vocabulary via the user interface.
|
||||
*/
|
||||
public function testVocabularyInterface(): void {
|
||||
// Visit the main taxonomy administration page.
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
|
||||
// Create a new vocabulary.
|
||||
$this->clickLink('Add vocabulary');
|
||||
$edit = [];
|
||||
$vid = $this->randomMachineName();
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['description'] = $this->randomMachineName();
|
||||
$edit['vid'] = $vid;
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains("Created new vocabulary {$edit['name']}.");
|
||||
|
||||
// Edit the vocabulary.
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
$this->assertSession()->pageTextContains($edit['name']);
|
||||
$this->assertSession()->pageTextContains($edit['description']);
|
||||
$this->assertSession()->linkByHrefExists(Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $edit['vid']])->toString());
|
||||
$this->clickLink('Edit vocabulary');
|
||||
$edit = [];
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['description'] = $this->randomMachineName();
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
$this->assertSession()->pageTextContains($edit['name']);
|
||||
$this->assertSession()->pageTextContains($edit['description']);
|
||||
|
||||
// Try to submit a vocabulary with a duplicate machine name.
|
||||
$edit['vid'] = $vid;
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.');
|
||||
|
||||
// Try to submit an invalid machine name.
|
||||
$edit['vid'] = '!&^%';
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('The machine-readable name must contain only lowercase letters, numbers, and underscores.');
|
||||
|
||||
// Ensure that vocabulary titles are escaped properly.
|
||||
$edit = [];
|
||||
$edit['name'] = 'Don\'t Panic';
|
||||
$edit['description'] = $this->randomMachineName();
|
||||
$edit['vid'] = 'don_t_panic';
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
$site_name = $this->config('system.site')->get('name');
|
||||
$this->assertSession()->titleEquals("Don't Panic | $site_name");
|
||||
|
||||
// Delete the vocabulary.
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
$href = Url::fromRoute('entity.taxonomy_vocabulary.delete_form', ['taxonomy_vocabulary' => $edit['vid']])->toString();
|
||||
$xpath = $this->assertSession()->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
|
||||
$link = $this->assertSession()->elementExists('xpath', $xpath);
|
||||
$this->assertEquals('Delete vocabulary', $link->getText());
|
||||
$link->click();
|
||||
|
||||
// Confirm deletion.
|
||||
$name = Html::escape($edit['name']);
|
||||
$this->assertSession()->responseContains("Are you sure you want to delete the vocabulary <em class=\"placeholder\">$name</em>?");
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertSession()->responseContains("Deleted vocabulary <em class=\"placeholder\">$name</em>.");
|
||||
$this->container->get('entity_type.manager')->getStorage('taxonomy_vocabulary')->resetCache();
|
||||
$this->assertNull(Vocabulary::load($edit['vid']), 'Vocabulary not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Changing weights on the vocabulary overview with two or more vocabularies.
|
||||
*/
|
||||
public function testTaxonomyAdminChangingWeights(): void {
|
||||
// Create some vocabularies.
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$this->createVocabulary();
|
||||
}
|
||||
// Get all vocabularies and change their weights.
|
||||
$vocabularies = Vocabulary::loadMultiple();
|
||||
$edit = [];
|
||||
foreach ($vocabularies as $key => $vocabulary) {
|
||||
$weight = -$vocabulary->get('weight');
|
||||
$vocabularies[$key]->set('weight', $weight);
|
||||
$edit['vocabularies[' . $key . '][weight]'] = $weight;
|
||||
}
|
||||
// Saving the new weights via the interface.
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
$this->submitForm($edit, 'Save');
|
||||
|
||||
// Load the vocabularies from the database.
|
||||
$this->container->get('entity_type.manager')->getStorage('taxonomy_vocabulary')->resetCache();
|
||||
$new_vocabularies = Vocabulary::loadMultiple();
|
||||
|
||||
// Check that the weights are saved in the database correctly.
|
||||
foreach ($vocabularies as $key => $vocabulary) {
|
||||
$this->assertEquals($new_vocabularies[$key]->get('weight'), $vocabularies[$key]->get('weight'), 'The vocabulary weight was changed.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the vocabulary overview with no vocabularies.
|
||||
*/
|
||||
public function testTaxonomyAdminNoVocabularies(): void {
|
||||
// Delete all vocabularies.
|
||||
$vocabularies = Vocabulary::loadMultiple();
|
||||
foreach ($vocabularies as $vocabulary) {
|
||||
$vocabulary->delete();
|
||||
}
|
||||
// Confirm that no vocabularies are found in the database.
|
||||
$this->assertEmpty(Vocabulary::loadMultiple(), 'No vocabularies found.');
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
// Check the default message for no vocabularies.
|
||||
$this->assertSession()->pageTextContains('No vocabularies available.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deleting a vocabulary.
|
||||
*/
|
||||
public function testTaxonomyAdminDeletingVocabulary(): void {
|
||||
// Create a vocabulary.
|
||||
$vid = $this->randomMachineName();
|
||||
$edit = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vid,
|
||||
];
|
||||
$this->drupalGet('admin/structure/taxonomy/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Created new vocabulary');
|
||||
|
||||
// Check the created vocabulary.
|
||||
$this->container->get('entity_type.manager')->getStorage('taxonomy_vocabulary')->resetCache();
|
||||
$vocabulary = Vocabulary::load($vid);
|
||||
$this->assertNotEmpty($vocabulary, 'Vocabulary found.');
|
||||
|
||||
// Delete the vocabulary.
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id());
|
||||
$this->clickLink('Delete');
|
||||
$this->assertSession()->pageTextContains("Are you sure you want to delete the vocabulary {$vocabulary->label()}?");
|
||||
$this->assertSession()->pageTextContains('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.');
|
||||
|
||||
// Confirm deletion.
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertSession()->pageTextContains("Deleted vocabulary {$vocabulary->label()}.");
|
||||
$this->container->get('entity_type.manager')->getStorage('taxonomy_vocabulary')->resetCache();
|
||||
$this->assertNull(Vocabulary::load($vid), 'Vocabulary not found.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\ContextProvider;
|
||||
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\taxonomy\ContextProvider\TermRouteContext;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\taxonomy\ContextProvider\TermRouteContext
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermContextTest extends KernelTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['filter', 'taxonomy', 'text', 'user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installConfig(['filter']);
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAvailableContexts
|
||||
*/
|
||||
public function testGetAvailableContexts(): void {
|
||||
$context_repository = $this->container->get('context.repository');
|
||||
|
||||
// Test taxonomy_term.taxonomy_term_route_context:taxonomy_term exists.
|
||||
$contexts = $context_repository->getAvailableContexts();
|
||||
$this->assertArrayHasKey('@taxonomy_term.taxonomy_term_route_context:taxonomy_term', $contexts);
|
||||
$this->assertSame('entity:taxonomy_term', $contexts['@taxonomy_term.taxonomy_term_route_context:taxonomy_term']->getContextDefinition()
|
||||
->getDataType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getRuntimeContexts
|
||||
*/
|
||||
public function testGetRuntimeContexts(): void {
|
||||
// Create term.
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$term = $this->createTerm($vocabulary);
|
||||
|
||||
// Create RouteMatch from term entity.
|
||||
$url = $term->toUrl();
|
||||
$route_provider = \Drupal::service('router.route_provider');
|
||||
$route = $route_provider->getRouteByName($url->getRouteName());
|
||||
$route_match = new RouteMatch($url->getRouteName(), $route, [
|
||||
'taxonomy_term' => $term,
|
||||
]);
|
||||
|
||||
// Initiate TermRouteContext with RouteMatch.
|
||||
$provider = new TermRouteContext($route_match);
|
||||
|
||||
$runtime_contexts = $provider->getRuntimeContexts([]);
|
||||
$this->assertArrayHasKey('taxonomy_term', $runtime_contexts);
|
||||
$this->assertTrue($runtime_contexts['taxonomy_term']->hasContextValue());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the loading of multiple taxonomy terms at once.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class LoadMultipleTest extends KernelTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'system',
|
||||
'taxonomy',
|
||||
'user',
|
||||
'text',
|
||||
'filter',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests loading multiple taxonomy terms by term ID and vocabulary.
|
||||
*/
|
||||
public function testTaxonomyTermMultipleLoad(): void {
|
||||
// Create a vocabulary.
|
||||
$vocabulary = $this->createVocabulary();
|
||||
|
||||
// Create five terms in the vocabulary.
|
||||
$i = 0;
|
||||
while ($i < 5) {
|
||||
$i++;
|
||||
$this->createTerm($vocabulary);
|
||||
}
|
||||
// Load the terms from the vocabulary.
|
||||
$term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
|
||||
$terms = $term_storage->loadByProperties(['vid' => $vocabulary->id()]);
|
||||
$count = count($terms);
|
||||
$this->assertEquals(5, $count, "Correct number of terms were loaded. $count terms.");
|
||||
|
||||
// Load the same terms again by tid.
|
||||
$terms2 = Term::loadMultiple(array_keys($terms));
|
||||
$this->assertEquals($terms, $terms2, 'Both arrays contain the same terms.');
|
||||
|
||||
// Remove one term from the array, then delete it.
|
||||
$deleted = array_shift($terms2);
|
||||
$deleted->delete();
|
||||
$deleted_term = Term::load($deleted->id());
|
||||
$this->assertNull($deleted_term);
|
||||
|
||||
// Load terms from the vocabulary by vid.
|
||||
$terms3 = $term_storage->loadByProperties(['vid' => $vocabulary->id()]);
|
||||
$this->assertCount(4, $terms3, 'Correct number of terms were loaded.');
|
||||
$this->assertFalse(isset($terms3[$deleted->id()]));
|
||||
|
||||
// Create a single term and load it by name.
|
||||
$term = $this->createTerm($vocabulary);
|
||||
$loaded_terms = $term_storage->loadByProperties(['name' => $term->getName()]);
|
||||
$this->assertCount(1, $loaded_terms, 'One term was loaded.');
|
||||
$loaded_term = reset($loaded_terms);
|
||||
$this->assertEquals($term->id(), $loaded_term->id(), 'Term loaded by name successfully.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate;
|
||||
|
||||
use Drupal\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade variables to taxonomy.settings.yml.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTaxonomyConfigsTest extends MigrateDrupal6TestBase {
|
||||
|
||||
use SchemaCheckTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->executeMigration('taxonomy_settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of taxonomy variables to taxonomy.settings.yml.
|
||||
*/
|
||||
public function testTaxonomySettings(): void {
|
||||
$config = $this->config('taxonomy.settings');
|
||||
$this->assertSame(100, $config->get('terms_per_page_admin'));
|
||||
$this->assertFalse($config->get('override_selector'));
|
||||
$this->assertTrue($config->get('maintain_index_table'));
|
||||
$this->assertConfigSchema(\Drupal::service('config.typed'), 'taxonomy.settings', $config->get());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase;
|
||||
use Drupal\migrate_drupal\Tests\StubTestTrait;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Test stub creation for taxonomy terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class MigrateTaxonomyTermStubTest extends MigrateDrupalTestBase {
|
||||
|
||||
use StubTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'text', 'taxonomy_term_stub_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creation of taxonomy term stubs.
|
||||
*/
|
||||
public function testStub(): void {
|
||||
Vocabulary::create([
|
||||
'vid' => 'test_vocabulary',
|
||||
'name' => 'Test vocabulary',
|
||||
])->save();
|
||||
$this->performStubTest('taxonomy_term');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creation of stubs when weight is mapped.
|
||||
*/
|
||||
public function testStubWithWeightMapping(): void {
|
||||
// Create a vocabulary via migration for the terms to reference.
|
||||
$vocabulary_data_rows = [
|
||||
['id' => '1', 'name' => 'tags'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$definition = [
|
||||
'migration_tags' => ['Stub test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $vocabulary_data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'vid' => 'id',
|
||||
'name' => 'name',
|
||||
],
|
||||
'destination' => ['plugin' => 'entity:taxonomy_vocabulary'],
|
||||
];
|
||||
$vocabulary_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
$vocabulary_executable = new MigrateExecutable($vocabulary_migration, $this);
|
||||
$vocabulary_executable->import();
|
||||
|
||||
// We have a term referencing an unmigrated parent, forcing a stub to be
|
||||
// created.
|
||||
$migration = $this->getMigration('taxonomy_term_stub_test');
|
||||
$term_executable = new MigrateExecutable($migration, $this);
|
||||
$term_executable->import();
|
||||
$this->assertNotEmpty($migration->getIdMap()->getRowBySource(['2']), 'Stub row exists in the ID map table');
|
||||
|
||||
// Load the referenced term, which should exist as a stub.
|
||||
/** @var \Drupal\Core\Entity\ContentEntityBase $stub_entity */
|
||||
$stub_entity = Term::load(2);
|
||||
$this->assertNotEmpty($stub_entity, 'Stub successfully created');
|
||||
if ($stub_entity) {
|
||||
$this->assertCount(0, $stub_entity->validate(), 'Stub is a valid entity');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
// cspell:ignore vocabfixed vocablocalized vocabtranslate
|
||||
|
||||
/**
|
||||
* Tests d7 taxonomy term deriver.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class TaxonomyTermDeriverTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'text'];
|
||||
|
||||
/**
|
||||
* Tests fields exist in process pipeline for term migrations.
|
||||
*/
|
||||
public function testBuilder(): void {
|
||||
// Test a field on the vocabfixed term.
|
||||
$process = $this->getMigration('d7_taxonomy_term:vocabfixed')->getProcess();
|
||||
$this->assertSame('field_training', $process['field_training'][0]['source']);
|
||||
|
||||
// Test a field on the vocablocalized term.
|
||||
$process = $this->getMigration('d7_taxonomy_term:vocablocalized')->getProcess();
|
||||
$this->assertSame('field_sector', $process['field_sector'][0]['source']);
|
||||
|
||||
// Test a field on the vocabtranslate term.
|
||||
$process = $this->getMigration('d7_taxonomy_term:vocabtranslate')->getProcess();
|
||||
$this->assertSame('field_chancellor', $process['field_chancellor'][0]['source']);
|
||||
|
||||
// Test a field on the test_vocabulary term.
|
||||
$process = $this->getMigration('d7_taxonomy_term:test_vocabulary')->getProcess();
|
||||
$this->assertSame('field_integer', $process['field_integer'][0]['source']);
|
||||
$this->assertSame('field_term_reference', $process['field_term_reference'][0]['source']);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade taxonomy terms.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTaxonomyTermTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['comment', 'taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations(['d6_taxonomy_vocabulary', 'd6_taxonomy_term']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 taxonomy term to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyTerms(): void {
|
||||
$expected_results = [
|
||||
'1' => [
|
||||
'source_vid' => 1,
|
||||
'vid' => 'vocabulary_1_i_0_',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'zu',
|
||||
],
|
||||
'2' => [
|
||||
'source_vid' => 2,
|
||||
'vid' => 'vocabulary_2_i_1_',
|
||||
'weight' => 3,
|
||||
'parent' => [0],
|
||||
'language' => 'fr',
|
||||
],
|
||||
'3' => [
|
||||
'source_vid' => 2,
|
||||
'vid' => 'vocabulary_2_i_1_',
|
||||
'weight' => 4,
|
||||
'parent' => [2],
|
||||
'language' => 'fr',
|
||||
],
|
||||
'4' => [
|
||||
'source_vid' => 3,
|
||||
'vid' => 'vocabulary_3_i_2_',
|
||||
'weight' => 6,
|
||||
'parent' => [0],
|
||||
],
|
||||
'5' => [
|
||||
'source_vid' => 3,
|
||||
'vid' => 'vocabulary_3_i_2_',
|
||||
'weight' => 7,
|
||||
'parent' => [4],
|
||||
],
|
||||
'6' => [
|
||||
'source_vid' => 3,
|
||||
'vid' => 'vocabulary_3_i_2_',
|
||||
'weight' => 8,
|
||||
'parent' => [4, 5],
|
||||
],
|
||||
];
|
||||
$terms = Term::loadMultiple(array_keys($expected_results));
|
||||
|
||||
// Find each term in the tree.
|
||||
$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
|
||||
$vids = array_unique(array_column($expected_results, 'vid'));
|
||||
$tree_terms = [];
|
||||
foreach ($vids as $vid) {
|
||||
foreach ($storage->loadTree($vid) as $term) {
|
||||
$tree_terms[$term->tid] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($expected_results as $tid => $values) {
|
||||
/** @var \Drupal\taxonomy\Entity\Term $term */
|
||||
$term = $terms[$tid];
|
||||
$language = isset($values['language']) ? $values['language'] . ' - ' : '';
|
||||
$this->assertSame("{$language}term {$tid} of vocabulary {$values['source_vid']}", $term->name->value);
|
||||
$this->assertSame("{$language}description of term {$tid} of vocabulary {$values['source_vid']}", $term->description->value);
|
||||
$this->assertSame($values['vid'], $term->vid->target_id);
|
||||
$this->assertSame((string) $values['weight'], $term->weight->value);
|
||||
if ($values['parent'] === [0]) {
|
||||
$this->assertSame(0, (int) $term->parent->target_id);
|
||||
}
|
||||
else {
|
||||
$parents = [];
|
||||
foreach (\Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadParents($tid) as $parent) {
|
||||
$parents[] = (int) $parent->id();
|
||||
}
|
||||
$this->assertSame($parents, $values['parent']);
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($tid, $tree_terms, "Term $tid exists in vocabulary tree");
|
||||
$tree_term = $tree_terms[$tid];
|
||||
|
||||
// PostgreSQL, MySQL and SQLite may not return the parent terms in the
|
||||
// same order so sort before testing.
|
||||
$expected_parents = $values['parent'];
|
||||
sort($expected_parents);
|
||||
$actual_parents = $tree_term->parents;
|
||||
sort($actual_parents);
|
||||
$this->assertEquals($expected_parents, $actual_parents, "Term $tid has correct parents in vocabulary tree");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Migrate taxonomy vocabularies to taxonomy.vocabulary.*.yml.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTaxonomyVocabularyTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->executeMigration('d6_taxonomy_vocabulary');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 taxonomy vocabularies to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyVocabulary(): void {
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$j = $i + 1;
|
||||
$vocabulary = Vocabulary::load("vocabulary_{$j}_i_{$i}_");
|
||||
$this->assertSame($this->getMigration('d6_taxonomy_vocabulary')->getIdMap()->lookupDestinationIds([$j]), [[$vocabulary->id()]]);
|
||||
$this->assertSame("vocabulary $j (i=$i)", $vocabulary->label());
|
||||
$this->assertSame("description of vocabulary $j (i=$i)", $vocabulary->getDescription());
|
||||
$this->assertSame(4 + $i, $vocabulary->get('weight'));
|
||||
}
|
||||
$vocabulary = Vocabulary::load('vocabulary_name_much_longer_th');
|
||||
$this->assertSame('vocabulary name much longer than thirty two characters', $vocabulary->label());
|
||||
$this->assertSame('description of vocabulary name much longer than thirty two characters', $vocabulary->getDescription());
|
||||
$this->assertSame(7, $vocabulary->get('weight'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Migrate taxonomy vocabularies to taxonomy.vocabulary.*.yml.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTaxonomyVocabularyTranslationTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'config_translation',
|
||||
'language',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_taxonomy_vocabulary_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 i18n taxonomy vocabularies to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyVocabularyTranslation(): void {
|
||||
$language_manager = \Drupal::service('language_manager');
|
||||
$config = $language_manager->getLanguageConfigOverride('zu', 'taxonomy.vocabulary.vocabulary_1_i_0_');
|
||||
$this->assertSame('zu - vocabulary 1 (i=0)', $config->get('name'));
|
||||
$config = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabulary_1_i_0_');
|
||||
$this->assertSame('fr - vocabulary 1 (i=0)', $config->get('name'));
|
||||
$config = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabulary_2_i_1_');
|
||||
$this->assertSame('fr - vocabulary 2 (i=1)', $config->get('name'));
|
||||
$config = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabulary_3_i_2_');
|
||||
$this->assertSame('fr - vocabulary 3 (i=2)', $config->get('name'));
|
||||
$config = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabulary_name_much_longer_th');
|
||||
$this->assertSame('Nom de vocabulaire beaucoup plus long que trente-deux caractères', $config->get('name'));
|
||||
$config = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.tags');
|
||||
$this->assertSame('fr - Tags', $config->get('name'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
|
||||
/**
|
||||
* Tests migration of localized translated taxonomy terms.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTermLocalizedTranslationTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'menu_ui',
|
||||
'node',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* The cached taxonomy tree items, keyed by vid and tid.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $treeData = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installConfig(static::$modules);
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_node_type',
|
||||
'd6_field',
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_field_instance',
|
||||
'd6_taxonomy_term',
|
||||
'd6_taxonomy_term_localized_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a migrated term contains the expected values.
|
||||
*
|
||||
* @param int $id
|
||||
* Entity ID to load and check.
|
||||
* @param string $expected_language
|
||||
* The language code for this term.
|
||||
* @param string $expected_label
|
||||
* The label the migrated entity should have.
|
||||
* @param string $expected_vid
|
||||
* The parent vocabulary the migrated entity should have.
|
||||
* @param string|null $expected_description
|
||||
* The description the migrated entity should have.
|
||||
* @param string|null $expected_format
|
||||
* The format the migrated entity should have.
|
||||
* @param int $expected_weight
|
||||
* The weight the migrated entity should have.
|
||||
* @param array $expected_parents
|
||||
* The parent terms the migrated entity should have.
|
||||
* @param int $expected_field_integer_value
|
||||
* The value the migrated entity field should have.
|
||||
* @param int $expected_term_reference_tid
|
||||
* The term reference ID the migrated entity field should have.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertEntity(int $id, string $expected_language, string $expected_label, string $expected_vid, ?string $expected_description = '', ?string $expected_format = NULL, int $expected_weight = 0, array $expected_parents = [], ?int $expected_field_integer_value = NULL, ?int $expected_term_reference_tid = NULL): void {
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load($id);
|
||||
$this->assertInstanceOf(TermInterface::class, $entity);
|
||||
$this->assertSame($expected_language, $entity->language()->getId());
|
||||
$this->assertSame($expected_label, $entity->label());
|
||||
$this->assertSame($expected_vid, $entity->bundle());
|
||||
$this->assertSame($expected_description, $entity->getDescription());
|
||||
$this->assertSame($expected_format, $entity->getFormat());
|
||||
$this->assertSame($expected_weight, $entity->getWeight());
|
||||
$this->assertHierarchy($expected_vid, $id, $expected_parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a term is present in the tree storage, with the right parents.
|
||||
*
|
||||
* @param string $vid
|
||||
* Vocabulary ID.
|
||||
* @param int $tid
|
||||
* ID of the term to check.
|
||||
* @param array $parent_ids
|
||||
* The expected parent term IDs.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertHierarchy(string $vid, int $tid, array $parent_ids): void {
|
||||
if (!isset($this->treeData[$vid])) {
|
||||
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vid);
|
||||
$this->treeData[$vid] = [];
|
||||
foreach ($tree as $item) {
|
||||
$this->treeData[$vid][$item->tid] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
|
||||
$term = $this->treeData[$vid][$tid];
|
||||
$this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 i18n localized taxonomy term to Drupal 8 migration.
|
||||
*/
|
||||
public function testTranslatedLocalizedTaxonomyTerms(): void {
|
||||
$this->assertEntity(14, 'en', 'Talos IV', 'vocabulary_name_much_longer_th', 'The home of Captain Christopher Pike.', NULL, 0, []);
|
||||
$this->assertEntity(15, 'en', 'Vulcan', 'vocabulary_name_much_longer_th', NULL, NULL, 0, []);
|
||||
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load(14);
|
||||
$this->assertTrue($entity->hasTranslation('fr'));
|
||||
$translation = $entity->getTranslation('fr');
|
||||
$this->assertSame('fr - Talos IV', $translation->label());
|
||||
$this->assertSame('fr - The home of Captain Christopher Pike.', $translation->getDescription());
|
||||
|
||||
$this->assertTrue($entity->hasTranslation('zu'));
|
||||
$translation = $entity->getTranslation('zu');
|
||||
$this->assertSame('Talos IV', $translation->label());
|
||||
$this->assertSame('zu - The home of Captain Christopher Pike.', $translation->getDescription());
|
||||
|
||||
$entity = Term::load(15);
|
||||
$this->assertFalse($entity->hasTranslation('fr'));
|
||||
$this->assertTrue($entity->hasTranslation('zu'));
|
||||
$translation = $entity->getTranslation('zu');
|
||||
$this->assertSame('zu - Vulcan', $translation->label());
|
||||
$this->assertSame('', $translation->getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\migrate_drupal\NodeMigrateType;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Upgrade taxonomy term node associations.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTermNodeCompleteTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'menu_ui',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Remove the classic node table made in setup.
|
||||
$this->removeNodeMigrateMapTable(NodeMigrateType::NODE_MIGRATE_TYPE_CLASSIC, '6');
|
||||
|
||||
$this->installSchema('node', ['node_access']);
|
||||
$this->installEntitySchema('node');
|
||||
|
||||
$this->executeMigration('language');
|
||||
$this->migrateUsers(FALSE);
|
||||
$this->migrateFields();
|
||||
$this->executeMigrations(['d6_node_settings', 'd6_node_complete']);
|
||||
$this->migrateTaxonomy();
|
||||
// This is a base plugin ID and we want to run all derivatives.
|
||||
$this->executeMigrations(['d6_term_node']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 term-node association to Drupal 8 migration.
|
||||
*/
|
||||
public function testTermNode(): void {
|
||||
$this->container->get('entity_type.manager')
|
||||
->getStorage('node')
|
||||
->resetCache([1, 2]);
|
||||
|
||||
$nodes = Node::loadMultiple([1, 2]);
|
||||
$node = $nodes[1];
|
||||
$this->assertCount(1, $node->field_vocabulary_1_i_0_);
|
||||
$this->assertSame('1', $node->field_vocabulary_1_i_0_[0]->target_id);
|
||||
$node = $nodes[2];
|
||||
$this->assertCount(2, $node->field_vocabulary_2_i_1_);
|
||||
$this->assertSame('2', $node->field_vocabulary_2_i_1_[0]->target_id);
|
||||
$this->assertSame('3', $node->field_vocabulary_2_i_1_[1]->target_id);
|
||||
|
||||
// Tests the Drupal 6 term-node association to Drupal 8 node revisions.
|
||||
$this->executeMigrations(['d6_term_node_revision']);
|
||||
|
||||
$node = \Drupal::entityTypeManager()->getStorage('node')->loadRevision(2001);
|
||||
$this->assertCount(2, $node->field_vocabulary_3_i_2_);
|
||||
$this->assertSame('4', $node->field_vocabulary_3_i_2_[0]->target_id);
|
||||
$this->assertSame('5', $node->field_vocabulary_3_i_2_[1]->target_id);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Upgrade taxonomy term node associations.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTermNodeRevisionTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installSchema('node', ['node_access']);
|
||||
$this->migrateContent(['revisions']);
|
||||
$this->migrateTaxonomy();
|
||||
$this->executeMigrations(['d6_term_node', 'd6_term_node_revision']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 term-node revision association to Drupal 8 migration.
|
||||
*/
|
||||
public function testTermRevisionNode(): void {
|
||||
$node = \Drupal::entityTypeManager()->getStorage('node')->loadRevision(2001);
|
||||
$this->assertCount(2, $node->field_vocabulary_3_i_2_);
|
||||
$this->assertSame('4', $node->field_vocabulary_3_i_2_[0]->target_id);
|
||||
$this->assertSame('5', $node->field_vocabulary_3_i_2_[1]->target_id);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Upgrade taxonomy term node associations.
|
||||
*
|
||||
* @group #slow
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTermNodeTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installSchema('node', ['node_access']);
|
||||
$this->migrateContent();
|
||||
$this->migrateTaxonomy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 term-node association to Drupal 8 migration.
|
||||
*/
|
||||
public function testTermNode(): void {
|
||||
// This is a base plugin id and we want to run all derivatives.
|
||||
$this->executeMigrations(['d6_term_node']);
|
||||
|
||||
$this->container->get('entity_type.manager')
|
||||
->getStorage('node')
|
||||
->resetCache([1, 2]);
|
||||
|
||||
$nodes = Node::loadMultiple([1, 2]);
|
||||
$node = $nodes[1];
|
||||
$this->assertCount(1, $node->field_vocabulary_1_i_0_);
|
||||
$this->assertSame('1', $node->field_vocabulary_1_i_0_[0]->target_id);
|
||||
$node = $nodes[2];
|
||||
$this->assertCount(2, $node->field_vocabulary_2_i_1_);
|
||||
$this->assertSame('2', $node->field_vocabulary_2_i_1_[0]->target_id);
|
||||
$this->assertSame('3', $node->field_vocabulary_2_i_1_[1]->target_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that term relationships are ignored for un-migrated nodes.
|
||||
*/
|
||||
public function testSkipNonExistentNode(): void {
|
||||
// Node 2 is migrated by d6_node__story, but we need to pretend that it
|
||||
// failed, so record that in the map table.
|
||||
$this->mockFailure('d6_node:story', ['nid' => 2, 'language' => 'en']);
|
||||
|
||||
// d6_term_node__2 should skip over node 2 (a.k.a. revision 3) because,
|
||||
// according to the map table, it failed.
|
||||
$migration = $this->getMigration('d6_term_node:2');
|
||||
$this->executeMigration($migration);
|
||||
$this->assertNull($migration->getIdMap()->lookupDestinationIds(['vid' => 3])[0][0]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Upgrade taxonomy term node associations.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
* @group #slow
|
||||
*/
|
||||
class MigrateTermNodeTranslationTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'config_translation',
|
||||
'content_translation',
|
||||
'language',
|
||||
'locale',
|
||||
'menu_ui',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig(['node']);
|
||||
$this->installSchema('node', ['node_access']);
|
||||
|
||||
$this->executeMigration('language');
|
||||
$this->executeMigration('d6_node_settings');
|
||||
$this->migrateUsers(FALSE);
|
||||
$this->migrateFields();
|
||||
$this->migrateTaxonomy();
|
||||
$this->migrateContent(['translations']);
|
||||
|
||||
// This is a base plugin id and we want to run all derivatives.
|
||||
$this->executeMigrations([
|
||||
'd6_term_node',
|
||||
'd6_term_node_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 term-node association to Drupal 8 migration.
|
||||
*/
|
||||
public function testTermNode(): void {
|
||||
$this->container->get('entity_type.manager')
|
||||
->getStorage('node')
|
||||
->resetCache([18, 21]);
|
||||
|
||||
// Test with translated content type employee. Vocabulary
|
||||
// field_vocabulary_name_much_longe is a localized vocabulary and
|
||||
// field_vocabulary_3_i_2_ is a per language vocabulary.
|
||||
// An untranslated node.
|
||||
$node = Node::load(18);
|
||||
// A localized vocabulary.
|
||||
$this->assertSame('15', $node->field_vocabulary_name_much_longe[0]->target_id);
|
||||
// Per language vocabulary.
|
||||
$this->assertSame('5', $node->field_vocabulary_3_i_2_[0]->target_id);
|
||||
|
||||
// A translated node.
|
||||
// The English node.
|
||||
$node = Node::load(21);
|
||||
$this->assertSame('15', $node->field_vocabulary_name_much_longe[0]->target_id);
|
||||
$this->assertSame('4', $node->field_vocabulary_3_i_2_[0]->target_id);
|
||||
// The French translation of the English node.
|
||||
$translation = $node->getTranslation('fr');
|
||||
$this->assertSame('14', $translation->field_vocabulary_name_much_longe[0]->target_id);
|
||||
$this->assertSame('9', $translation->field_vocabulary_3_i_2_[0]->target_id);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Vocabulary entity display migration.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateVocabularyEntityDisplayTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['field', 'taxonomy', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Execute Dependency Migrations.
|
||||
$this->migrateContentTypes();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations([
|
||||
'd6_node_type',
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_vocabulary_field',
|
||||
'd6_vocabulary_field_instance',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 vocabulary-node type association to Drupal 8 migration.
|
||||
*/
|
||||
public function testVocabularyEntityDisplay(): void {
|
||||
$this->executeMigration('d6_vocabulary_entity_display');
|
||||
|
||||
// Test that the field exists.
|
||||
$component = EntityViewDisplay::load('node.page.default')->getComponent('field_tags');
|
||||
$this->assertSame('entity_reference_label', $component['type']);
|
||||
$this->assertSame(20, $component['weight']);
|
||||
// Test the Id map.
|
||||
$this->assertSame(
|
||||
[['node', 'article', 'default', 'field_tags']],
|
||||
$this->getMigration('d6_vocabulary_entity_display')->getIdMap()->lookupDestinationIds([4, 'article'])
|
||||
);
|
||||
|
||||
// Tests that a vocabulary named like a D8 base field will be migrated and
|
||||
// prefixed with 'field_' to avoid conflicts.
|
||||
$field_type = EntityViewDisplay::load('node.sponsor.default')->getComponent('field_type');
|
||||
$this->assertIsArray($field_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that vocabulary displays are ignored appropriately.
|
||||
*
|
||||
* Vocabulary displays should be ignored when they belong to node types which
|
||||
* were not migrated.
|
||||
*/
|
||||
public function testSkipNonExistentNodeType(): void {
|
||||
// The "story" node type is migrated by d6_node_type but we need to pretend
|
||||
// that it didn't occur, so record that in the map table.
|
||||
$this->mockFailure('d6_node_type', ['type' => 'story']);
|
||||
|
||||
// d6_vocabulary_entity_display should skip over the "story" node type
|
||||
// config because, according to the map table, it didn't occur.
|
||||
$migration = $this->getMigration('d6_vocabulary_entity_display');
|
||||
|
||||
$this->executeMigration($migration);
|
||||
$this->assertNull($migration->getIdMap()->lookupDestinationIds(['type' => 'story'])[0][0]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Vocabulary entity form display migration.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateVocabularyEntityFormDisplayTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Execute Dependency Migrations.
|
||||
$this->migrateContentTypes();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations([
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_vocabulary_field',
|
||||
'd6_vocabulary_field_instance',
|
||||
'd6_vocabulary_entity_display',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 vocabulary-node type association to Drupal 8 migration.
|
||||
*/
|
||||
public function testVocabularyEntityFormDisplay(): void {
|
||||
$this->executeMigration('d6_vocabulary_entity_form_display');
|
||||
|
||||
// Test that the field exists.
|
||||
$component = EntityFormDisplay::load('node.page.default')->getComponent('field_tags');
|
||||
$this->assertSame('options_select', $component['type']);
|
||||
$this->assertSame(20, $component['weight']);
|
||||
// Test the Id map.
|
||||
$this->assertSame([
|
||||
[
|
||||
'node',
|
||||
'article',
|
||||
'default',
|
||||
'field_tags',
|
||||
],
|
||||
],
|
||||
$this->getMigration('d6_vocabulary_entity_form_display')
|
||||
->getIdMap()
|
||||
->lookupDestinationIds([4, 'article'])
|
||||
);
|
||||
|
||||
// Test the term widget tags setting.
|
||||
$entity_form_display = EntityFormDisplay::load('node.story.default');
|
||||
$this->assertSame($entity_form_display->getComponent('field_vocabulary_1_i_0_')['type'], 'options_select');
|
||||
$this->assertSame($entity_form_display->getComponent('field_vocabulary_2_i_1_')['type'], 'entity_reference_autocomplete_tags');
|
||||
|
||||
// Tests that a vocabulary named like a D8 base field will be migrated and
|
||||
// prefixed with 'field_' to avoid conflicts.
|
||||
$field_type = EntityFormDisplay::load('node.sponsor.default')->getComponent('field_type');
|
||||
$this->assertIsArray($field_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that vocabulary displays are ignored appropriately.
|
||||
*
|
||||
* Vocabulary displays should be ignored when they belong to node types which
|
||||
* were not migrated.
|
||||
*/
|
||||
public function testSkipNonExistentNodeType(): void {
|
||||
// The "story" node type is migrated by d6_node_type but we need to pretend
|
||||
// that it didn't occur, so record that in the map table.
|
||||
$this->mockFailure('d6_node_type', ['type' => 'story']);
|
||||
|
||||
// d6_vocabulary_entity_form_display should skip over the "story" node type
|
||||
// config because, according to the map table, it didn't occur.
|
||||
$migration = $this->getMigration('d6_vocabulary_entity_form_display');
|
||||
|
||||
$this->executeMigration($migration);
|
||||
$this->assertNull($migration->getIdMap()->lookupDestinationIds(['type' => 'story'])[0][0]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Vocabulary field instance migration.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateVocabularyFieldInstanceTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Execute Dependency Migrations.
|
||||
$this->migrateContentTypes();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->executeMigrations([
|
||||
'd6_node_type',
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_vocabulary_field',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 vocabulary-node type association to Drupal 8 migration.
|
||||
*/
|
||||
public function testVocabularyFieldInstance(): void {
|
||||
$this->executeMigration('d6_vocabulary_field_instance');
|
||||
|
||||
// Test that the field exists. Tags has a multilingual option of 'None'.
|
||||
$field_id = 'node.article.field_tags';
|
||||
$field = FieldConfig::load($field_id);
|
||||
$this->assertSame($field_id, $field->id(), 'Field instance exists on article bundle.');
|
||||
$this->assertSame('Tags', $field->label());
|
||||
$this->assertTrue($field->isRequired(), 'Field is required');
|
||||
$this->assertFalse($field->isTranslatable());
|
||||
$this->assertTargetBundles($field_id, ['tags' => 'tags']);
|
||||
|
||||
// Test the page bundle as well. Tags has a multilingual option of 'None'.
|
||||
$field_id = 'node.page.field_tags';
|
||||
$field = FieldConfig::load($field_id);
|
||||
$this->assertSame($field_id, $field->id(), 'Field instance exists on page bundle.');
|
||||
$this->assertSame('Tags', $field->label());
|
||||
$this->assertTrue($field->isRequired(), 'Field is required');
|
||||
$this->assertFalse($field->isTranslatable());
|
||||
|
||||
$settings = $field->getSettings();
|
||||
$this->assertSame('default:taxonomy_term', $settings['handler'], 'The handler plugin ID is correct.');
|
||||
$this->assertTargetBundles($field_id, ['tags' => 'tags']);
|
||||
$this->assertTrue($settings['handler_settings']['auto_create'], 'The "auto_create" setting is correct.');
|
||||
|
||||
$this->assertSame(
|
||||
[['node', 'article', 'field_tags']],
|
||||
$this->getMigration('d6_vocabulary_field_instance')->getIdMap()->lookupDestinationIds([4, 'article'])
|
||||
);
|
||||
|
||||
// Test the field vocabulary_1_i_0_ with multilingual option,
|
||||
// 'per language terms'.
|
||||
$field_id = 'node.story.field_vocabulary_1_i_0_';
|
||||
$field = FieldConfig::load($field_id);
|
||||
$this->assertFalse($field->isRequired(), 'Field is not required');
|
||||
$this->assertTrue($field->isTranslatable());
|
||||
$this->assertTargetBundles($field_id, ['vocabulary_1_i_0_' => 'vocabulary_1_i_0_']);
|
||||
|
||||
// Test the field vocabulary_2_i_0_ with multilingual option,
|
||||
// 'Set language to vocabulary'.
|
||||
$field_id = 'node.story.field_vocabulary_2_i_1_';
|
||||
$field = FieldConfig::load($field_id);
|
||||
$this->assertFalse($field->isRequired(), 'Field is not required');
|
||||
$this->assertFalse($field->isTranslatable());
|
||||
$this->assertTargetBundles($field_id, ['vocabulary_2_i_1_' => 'vocabulary_2_i_1_']);
|
||||
|
||||
// Test the field vocabulary_3_i_0_ with multilingual option,
|
||||
// 'Localize terms'.
|
||||
$field_id = 'node.story.field_vocabulary_3_i_2_';
|
||||
$field = FieldConfig::load($field_id);
|
||||
$this->assertFalse($field->isRequired(), 'Field is not required');
|
||||
$this->assertTrue($field->isTranslatable());
|
||||
$this->assertTargetBundles($field_id, ['vocabulary_3_i_2_' => 'vocabulary_3_i_2_']);
|
||||
|
||||
// Tests that a vocabulary named like a D8 base field will be migrated and
|
||||
// prefixed with 'field_' to avoid conflicts.
|
||||
$field_type = FieldConfig::load('node.sponsor.field_type');
|
||||
$this->assertInstanceOf(FieldConfig::class, $field_type);
|
||||
$this->assertTrue($field->isTranslatable());
|
||||
$this->assertTargetBundles($field_id, ['vocabulary_3_i_2_' => 'vocabulary_3_i_2_']);
|
||||
|
||||
$this->assertTargetBundles('node.employee.field_vocabulary_3_i_2_', ['vocabulary_3_i_2_' => 'vocabulary_3_i_2_']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the settings of an entity reference field config entity.
|
||||
*
|
||||
* @param string $id
|
||||
* The entity ID in the form ENTITY_TYPE.BUNDLE.FIELD_NAME.
|
||||
* @param string[] $target_bundles
|
||||
* An array of expected target bundles.
|
||||
*/
|
||||
protected function assertTargetBundles($id, array $target_bundles): void {
|
||||
$field = FieldConfig::load($id);
|
||||
$handler_settings = $field->getSetting('handler_settings');
|
||||
$this->assertArrayHasKey('target_bundles', $handler_settings);
|
||||
$this->assertSame($handler_settings['target_bundles'], $target_bundles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that vocabulary field instances are ignored appropriately.
|
||||
*
|
||||
* Vocabulary field instances should be ignored when they belong to node
|
||||
* types which were not migrated.
|
||||
*/
|
||||
public function testSkipNonExistentNodeType(): void {
|
||||
// The "story" node type is migrated by d6_node_type but we need to pretend
|
||||
// that it didn't occur, so record that in the map table.
|
||||
$this->mockFailure('d6_node_type', ['type' => 'story']);
|
||||
|
||||
// d6_vocabulary_field_instance should skip over the "story" node type
|
||||
// config because, according to the map table, it didn't occur.
|
||||
$migration = $this->getMigration('d6_vocabulary_field_instance');
|
||||
|
||||
$this->executeMigration($migration);
|
||||
$this->assertNull($migration->getIdMap()->lookupDestinationIds(['type' => 'story'])[0][0]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
* Vocabulary field migration.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateVocabularyFieldTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->migrateTaxonomy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 vocabulary-node type association to Drupal 8 migration.
|
||||
*/
|
||||
public function testVocabularyField(): void {
|
||||
// Test that the field exists.
|
||||
$field_storage_id = 'node.field_tags';
|
||||
/** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
|
||||
$field_storage = FieldStorageConfig::load($field_storage_id);
|
||||
$this->assertSame($field_storage_id, $field_storage->id());
|
||||
|
||||
$settings = $field_storage->getSettings();
|
||||
$this->assertSame('taxonomy_term', $settings['target_type'], "Target type is correct.");
|
||||
$this->assertSame(1, $field_storage->getCardinality(), "Field cardinality in 1.");
|
||||
|
||||
$this->assertSame([['node', 'field_tags']], $this->getMigration('d6_vocabulary_field')->getIdMap()->lookupDestinationIds([4]), "Test IdMap");
|
||||
|
||||
// Tests that a vocabulary named like a D8 base field will be migrated and
|
||||
// prefixed with 'field_' to avoid conflicts.
|
||||
$field_type = FieldStorageConfig::load('node.field_type');
|
||||
$this->assertInstanceOf(FieldStorageConfig::class, $field_type);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* @group taxonomy
|
||||
*/
|
||||
class MigrateNodeTaxonomyTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'comment',
|
||||
'datetime',
|
||||
'datetime_range',
|
||||
'image',
|
||||
'link',
|
||||
'menu_ui',
|
||||
'node',
|
||||
'taxonomy',
|
||||
'telephone',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('file');
|
||||
|
||||
$this->migrateTaxonomyTerms();
|
||||
$this->migrateUsers(FALSE);
|
||||
$this->executeMigration('d7_node:article');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests node migration from Drupal 7 to 8.
|
||||
*/
|
||||
public function testMigration(): void {
|
||||
$node = Node::load(2);
|
||||
$this->assertInstanceOf(NodeInterface::class, $node);
|
||||
$this->assertEquals(9, $node->field_tags[0]->target_id);
|
||||
$this->assertEquals(14, $node->field_tags[1]->target_id);
|
||||
$this->assertEquals(17, $node->field_tags[2]->target_id);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
|
||||
/**
|
||||
* Upgrade taxonomy terms.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'comment',
|
||||
'content_translation',
|
||||
'datetime',
|
||||
'datetime_range',
|
||||
'image',
|
||||
'language',
|
||||
'link',
|
||||
'menu_ui',
|
||||
'node',
|
||||
'taxonomy',
|
||||
'telephone',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* The cached taxonomy tree items, keyed by vid and tid.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $treeData = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('comment');
|
||||
$this->installEntitySchema('file');
|
||||
|
||||
$this->migrateTaxonomyTerms();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_user_role',
|
||||
'd7_user',
|
||||
'd7_entity_translation_settings',
|
||||
'd7_taxonomy_term_entity_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a migrated term contains the expected values.
|
||||
*
|
||||
* @param int $id
|
||||
* Entity ID to load and check.
|
||||
* @param string $expected_language
|
||||
* The language code for this term.
|
||||
* @param string $expected_label
|
||||
* The label the migrated entity should have.
|
||||
* @param string $expected_vid
|
||||
* The parent vocabulary the migrated entity should have.
|
||||
* @param string|null $expected_description
|
||||
* The description the migrated entity should have.
|
||||
* @param string|null $expected_format
|
||||
* The format the migrated entity should have.
|
||||
* @param int $expected_weight
|
||||
* The weight the migrated entity should have.
|
||||
* @param array $expected_parents
|
||||
* The parent terms the migrated entity should have.
|
||||
* @param int $expected_field_integer_value
|
||||
* The value the migrated entity field should have.
|
||||
* @param int $expected_term_reference_tid
|
||||
* The term reference id the migrated entity field should have.
|
||||
* @param int|null $expected_container_flag
|
||||
* The term should be a container entity.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertEntity(int $id, string $expected_language, string $expected_label, string $expected_vid, ?string $expected_description = '', ?string $expected_format = NULL, int $expected_weight = 0, array $expected_parents = [], ?int $expected_field_integer_value = NULL, ?int $expected_term_reference_tid = NULL, int|NULL $expected_container_flag = NULL): void {
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load($id);
|
||||
$this->assertInstanceOf(TermInterface::class, $entity);
|
||||
$this->assertSame($expected_language, $entity->language()->getId());
|
||||
$this->assertEquals($expected_label, $entity->label());
|
||||
$this->assertEquals($expected_vid, $entity->bundle());
|
||||
$this->assertEquals($expected_description, $entity->getDescription());
|
||||
$this->assertEquals($expected_format, $entity->getFormat());
|
||||
$this->assertEquals($expected_weight, $entity->getWeight());
|
||||
$this->assertEquals($expected_parents, $this->getParentIDs($id));
|
||||
$this->assertHierarchy($expected_vid, $id, $expected_parents);
|
||||
if (!is_null($expected_field_integer_value)) {
|
||||
$this->assertTrue($entity->hasField('field_integer'));
|
||||
$this->assertEquals($expected_field_integer_value, $entity->field_integer->value);
|
||||
}
|
||||
if (!is_null($expected_term_reference_tid)) {
|
||||
$this->assertTrue($entity->hasField('field_integer'));
|
||||
$this->assertEquals($expected_term_reference_tid, $entity->field_term_reference->target_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 7 taxonomy term to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyTerms(): void {
|
||||
$this->assertEntity(1, 'en', 'General discussion', 'sujet_de_discussion', '', NULL, 2);
|
||||
|
||||
// Tests that terms that used the Drupal 7 Title module and that have their
|
||||
// name and description replaced by real fields are correctly migrated.
|
||||
$this->assertEntity(2, 'en', 'Term1 (This is a real field!)', 'test_vocabulary', 'The first term. (This is a real field!)', 'filtered_html', 0, [], NULL, 3);
|
||||
|
||||
$this->assertEntity(3, 'en', 'Term2', 'test_vocabulary', 'The second term.', 'filtered_html');
|
||||
$this->assertEntity(4, 'en', 'Term3 in plain old English', 'test_vocabulary', 'The third term in plain old English.', 'full_html', 0, [3], 6);
|
||||
$this->assertEntity(5, 'en', 'Custom Forum', 'sujet_de_discussion', 'Where the cool kids are.', NULL, 3, [], NULL, NULL, 0);
|
||||
$this->assertEntity(6, 'en', 'Games', 'sujet_de_discussion', NULL, '', 4, [], NULL, NULL, 1);
|
||||
$this->assertEntity(7, 'en', 'Minecraft', 'sujet_de_discussion', '', NULL, 1, [6], NULL, NULL, 0);
|
||||
$this->assertEntity(8, 'en', 'Half Life 3', 'sujet_de_discussion', '', NULL, 0, [6], NULL, NULL, 0);
|
||||
|
||||
// Test taxonomy term language translations.
|
||||
$this->assertEntity(19, 'en', 'Jupiter Station', 'vocablocalized', 'Holographic research.', 'filtered_html', 0, [], NULL, NULL);
|
||||
$this->assertEntity(20, 'en', 'DS9', 'vocablocalized', 'Terok Nor', 'filtered_html', 0, [], NULL, NULL);
|
||||
$this->assertEntity(21, 'en', 'High council', 'vocabtranslate', NULL, NULL, 0, [], NULL, NULL);
|
||||
$this->assertEntity(22, 'fr', 'fr - High council', 'vocabtranslate', NULL, NULL, 0, [], NULL, NULL);
|
||||
$this->assertEntity(23, 'is', 'is - High council', 'vocabtranslate', NULL, NULL, 0, [], NULL, NULL);
|
||||
$this->assertEntity(24, 'fr', 'FR - Crewman', 'vocabfixed', NULL, NULL, 0, [], NULL, NULL);
|
||||
|
||||
// Localized.
|
||||
$this->assertEntity(19, 'en', 'Jupiter Station', 'vocablocalized', 'Holographic research.', 'filtered_html', 0, []);
|
||||
$this->assertEntity(20, 'en', 'DS9', 'vocablocalized', 'Terok Nor', 'filtered_html', 0, []);
|
||||
$this->assertEntity(25, 'en', 'Emissary', 'vocablocalized2', 'Pilot episode', 'filtered_html', 0, []);
|
||||
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load(20);
|
||||
$this->assertSame('Bajor', $entity->field_sector->value);
|
||||
|
||||
// Translate.
|
||||
$this->assertEntity(21, 'en', 'High council', 'vocabtranslate', NULL, NULL, 0, []);
|
||||
$entity = Term::load(21);
|
||||
$this->assertSame("K'mpec", $entity->field_chancellor->value);
|
||||
$this->assertEntity(22, 'fr', 'fr - High council', 'vocabtranslate', NULL, NULL, 0, []);
|
||||
$this->assertEntity(23, 'is', 'is - High council', 'vocabtranslate', NULL, NULL, 0, []);
|
||||
|
||||
// Fixed.
|
||||
$this->assertEntity(24, 'fr', 'FR - Crewman', 'vocabfixed', NULL, NULL, 0, []);
|
||||
|
||||
// Tests the migration of taxonomy term entity translations.
|
||||
$manager = $this->container->get('content_translation.manager');
|
||||
|
||||
// Get the term and its translations.
|
||||
$term = Term::load(4);
|
||||
$term_fr = $term->getTranslation('fr');
|
||||
$term_is = $term->getTranslation('is');
|
||||
|
||||
// Test that fields translated with Entity Translation are migrated.
|
||||
$this->assertSame('Term3 in plain old English', $term->getName());
|
||||
$this->assertSame('Term3 en français s\'il vous plaît', $term_fr->getName());
|
||||
$this->assertSame('Term3 á íslensku', $term_is->getName());
|
||||
$this->assertSame('The third term in plain old English.', $term->getDescription());
|
||||
$this->assertSame('The third term en français s\'il vous plaît.', $term_fr->getDescription());
|
||||
$this->assertSame('The third term á íslensku.', $term_is->getDescription());
|
||||
$this->assertSame('full_html', $term->getFormat());
|
||||
$this->assertSame('filtered_html', $term_fr->getFormat());
|
||||
$this->assertSame('plain_text', $term_is->getFormat());
|
||||
$this->assertSame('6', $term->field_integer->value);
|
||||
$this->assertSame('5', $term_fr->field_integer->value);
|
||||
$this->assertSame('4', $term_is->field_integer->value);
|
||||
|
||||
// Test that the French translation metadata is correctly migrated.
|
||||
$metadata_fr = $manager->getTranslationMetadata($term_fr);
|
||||
$this->assertTrue($metadata_fr->isPublished());
|
||||
$this->assertSame('en', $metadata_fr->getSource());
|
||||
$this->assertSame('2', $metadata_fr->getAuthor()->uid->value);
|
||||
$this->assertSame('1531922267', $metadata_fr->getCreatedTime());
|
||||
$this->assertSame(1531922268, $metadata_fr->getChangedTime());
|
||||
$this->assertTrue($metadata_fr->isOutdated());
|
||||
|
||||
// Test that the Icelandic translation metadata is correctly migrated.
|
||||
$metadata_is = $manager->getTranslationMetadata($term_is);
|
||||
$this->assertFalse($metadata_is->isPublished());
|
||||
$this->assertSame('en', $metadata_is->getSource());
|
||||
$this->assertSame('1', $metadata_is->getAuthor()->uid->value);
|
||||
$this->assertSame('1531922278', $metadata_is->getCreatedTime());
|
||||
$this->assertSame(1531922279, $metadata_is->getChangedTime());
|
||||
$this->assertFalse($metadata_is->isOutdated());
|
||||
|
||||
// Test that untranslatable properties are the same as the source language.
|
||||
$this->assertSame($term->bundle(), $term_fr->bundle());
|
||||
$this->assertSame($term->bundle(), $term_is->bundle());
|
||||
$this->assertSame($term->getWeight(), $term_fr->getWeight());
|
||||
$this->assertSame($term->getWeight(), $term_is->getWeight());
|
||||
$this->assertSame($term->parent->terget_id, $term_fr->parent->terget_id);
|
||||
$this->assertSame($term->parent->terget_id, $term_is->parent->terget_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the parent term IDs for a given term.
|
||||
*
|
||||
* @param int $tid
|
||||
* ID of the term to check.
|
||||
*
|
||||
* @return array
|
||||
* List of parent term IDs.
|
||||
*/
|
||||
protected function getParentIDs($tid): array {
|
||||
return array_keys(\Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadParents($tid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a term is present in the tree storage, with the right parents.
|
||||
*
|
||||
* @param string $vid
|
||||
* Vocabulary ID.
|
||||
* @param int $tid
|
||||
* ID of the term to check.
|
||||
* @param array $parent_ids
|
||||
* The expected parent term IDs.
|
||||
*/
|
||||
protected function assertHierarchy(string $vid, int $tid, array $parent_ids): void {
|
||||
if (!isset($this->treeData[$vid])) {
|
||||
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vid);
|
||||
$this->treeData[$vid] = [];
|
||||
foreach ($tree as $item) {
|
||||
$this->treeData[$vid][$item->tid] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
|
||||
$term = $this->treeData[$vid][$tid];
|
||||
$this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
|
||||
/**
|
||||
* Test migration of translated taxonomy terms.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
* @group #slow
|
||||
*/
|
||||
class MigrateTaxonomyTermTranslationTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'comment',
|
||||
'content_translation',
|
||||
'datetime',
|
||||
'datetime_range',
|
||||
'image',
|
||||
'language',
|
||||
'link',
|
||||
'menu_ui',
|
||||
'node',
|
||||
'taxonomy',
|
||||
'telephone',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* The cached taxonomy tree items, keyed by vid and tid.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $treeData = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('comment');
|
||||
$this->installEntitySchema('file');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->migrateFields();
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_language_content_taxonomy_vocabulary_settings',
|
||||
'd7_taxonomy_vocabulary',
|
||||
'd7_taxonomy_term',
|
||||
'd7_entity_translation_settings',
|
||||
'd7_taxonomy_term_entity_translation',
|
||||
'd7_taxonomy_term_localized_translation',
|
||||
'd7_taxonomy_term_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a migrated term contains the expected values.
|
||||
*
|
||||
* @param int $id
|
||||
* Entity ID to load and check.
|
||||
* @param string $expected_language
|
||||
* The language code for this term.
|
||||
* @param string $expected_label
|
||||
* The label the migrated entity should have.
|
||||
* @param string $expected_vid
|
||||
* The parent vocabulary the migrated entity should have.
|
||||
* @param string|null $expected_description
|
||||
* The description the migrated entity should have.
|
||||
* @param string|null $expected_format
|
||||
* The format the migrated entity should have.
|
||||
* @param int $expected_weight
|
||||
* The weight the migrated entity should have.
|
||||
* @param array $expected_parents
|
||||
* The parent terms the migrated entity should have.
|
||||
* @param int $expected_field_integer_value
|
||||
* The value the migrated entity field should have.
|
||||
* @param int $expected_term_reference_tid
|
||||
* The term reference ID the migrated entity field should have.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertEntity(int $id, string $expected_language, string $expected_label, string $expected_vid, ?string $expected_description = '', ?string $expected_format = NULL, int $expected_weight = 0, array $expected_parents = [], ?int $expected_field_integer_value = NULL, ?int $expected_term_reference_tid = NULL): void {
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load($id);
|
||||
$this->assertInstanceOf(TermInterface::class, $entity);
|
||||
$this->assertSame($expected_language, $entity->language()->getId());
|
||||
$this->assertSame($expected_label, $entity->label());
|
||||
$this->assertSame($expected_vid, $entity->bundle());
|
||||
$this->assertSame($expected_description, $entity->getDescription());
|
||||
$this->assertSame($expected_format, $entity->getFormat());
|
||||
$this->assertSame($expected_weight, $entity->getWeight());
|
||||
$this->assertHierarchy($expected_vid, $id, $expected_parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a term is present in the tree storage, with the right parents.
|
||||
*
|
||||
* @param string $vid
|
||||
* Vocabulary ID.
|
||||
* @param int $tid
|
||||
* ID of the term to check.
|
||||
* @param array $parent_ids
|
||||
* The expected parent term IDs.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertHierarchy(string $vid, int $tid, array $parent_ids): void {
|
||||
if (!isset($this->treeData[$vid])) {
|
||||
$tree = \Drupal::entityTypeManager()
|
||||
->getStorage('taxonomy_term')
|
||||
->loadTree($vid);
|
||||
$this->treeData[$vid] = [];
|
||||
foreach ($tree as $item) {
|
||||
$this->treeData[$vid][$item->tid] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
|
||||
$term = $this->treeData[$vid][$tid];
|
||||
$this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal i18n taxonomy term to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyTermTranslation(): void {
|
||||
// Forums vocabulary, no multilingual option.
|
||||
$this->assertEntity(1, 'en', 'General discussion', 'sujet_de_discussion', NULL, NULL, 2, []);
|
||||
$this->assertEntity(5, 'en', 'Custom Forum', 'sujet_de_discussion', 'Where the cool kids are.', NULL, 3, []);
|
||||
$this->assertEntity(6, 'en', 'Games', 'sujet_de_discussion', NULL, NULL, 4, []);
|
||||
$this->assertEntity(7, 'en', 'Minecraft', 'sujet_de_discussion', NULL, NULL, 1, ['6']);
|
||||
$this->assertEntity(8, 'en', 'Half Life 3', 'sujet_de_discussion', NULL, NULL, 0, ['6']);
|
||||
|
||||
// Test vocabulary, field translation.
|
||||
$this->assertEntity(2, 'en', 'Term1 (This is a real field!)', 'test_vocabulary', 'The first term. (This is a real field!)', 'filtered_html', 0, []);
|
||||
$this->assertEntity(3, 'en', 'Term2', 'test_vocabulary', 'The second term.', 'filtered_html', 0, []);
|
||||
$this->assertEntity(4, 'en', 'Term3 in plain old English', 'test_vocabulary', 'The third term in plain old English.', 'full_html', 0, ['3']);
|
||||
|
||||
// Tags vocabulary, no multilingual option.
|
||||
$this->assertEntity(9, 'en', 'Benjamin Sisko', 'tags', 'Portrayed by Avery Brooks', 'filtered_html', 0, []);
|
||||
$this->assertEntity(10, 'en', 'Kira Nerys', 'tags', 'Portrayed by Nana Visitor', 'filtered_html', 0, []);
|
||||
$this->assertEntity(11, 'en', 'Dax', 'tags', 'Portrayed by Terry Farrell', 'filtered_html', 0, []);
|
||||
$this->assertEntity(12, 'en', 'Jake Sisko', 'tags', 'Portrayed by Cirroc Lofton', 'filtered_html', 0, []);
|
||||
$this->assertEntity(13, 'en', 'Gul Dukat', 'tags', 'Portrayed by Marc Alaimo', 'filtered_html', 0, []);
|
||||
$this->assertEntity(14, 'en', 'Odo', 'tags', 'Portrayed by Rene Auberjonois', 'filtered_html', 0, []);
|
||||
$this->assertEntity(15, 'en', 'Worf', 'tags', 'Portrayed by Michael Dorn', 'filtered_html', 0, []);
|
||||
$this->assertEntity(16, 'en', "Miles O'Brien", 'tags', 'Portrayed by Colm Meaney', 'filtered_html', 0, []);
|
||||
$this->assertEntity(17, 'en', 'Quark', 'tags', 'Portrayed by Armin Shimerman', 'filtered_html', 0, []);
|
||||
$this->assertEntity(18, 'en', 'Elim Garak', 'tags', 'Portrayed by Andrew Robinson', 'filtered_html', 0, []);
|
||||
|
||||
// Localized.
|
||||
$this->assertEntity(19, 'en', 'Jupiter Station', 'vocablocalized', 'Holographic research.', 'filtered_html', 0, []);
|
||||
$this->assertEntity(20, 'en', 'DS9', 'vocablocalized', 'Terok Nor', 'filtered_html', 0, []);
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load(20);
|
||||
$this->assertSame('Bajor', $entity->field_sector->value);
|
||||
|
||||
// Translate.
|
||||
$this->assertEntity(21, 'en', 'High council', 'vocabtranslate', NULL, NULL, 0, []);
|
||||
$entity = Term::load(21);
|
||||
$this->assertSame("K'mpec", $entity->field_chancellor->value);
|
||||
|
||||
$this->assertEntity(22, 'fr', 'fr - High council', 'vocabtranslate', NULL, NULL, 0, []);
|
||||
$entity = Term::load(22);
|
||||
$this->assertSame("fr - K'mpec", $entity->field_chancellor->value);
|
||||
$this->assertEntity(23, 'is', 'is - High council', 'vocabtranslate', NULL, NULL, 0, []);
|
||||
|
||||
// Fixed.
|
||||
$this->assertEntity(24, 'fr', 'FR - Crewman', 'vocabfixed', NULL, NULL, 0, []);
|
||||
$entity = Term::load(24);
|
||||
$this->assertSame('fr - specialist', $entity->field_training->value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\taxonomy\VocabularyInterface;
|
||||
|
||||
/**
|
||||
* Migrate taxonomy vocabularies to taxonomy.vocabulary.*.yml.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class MigrateTaxonomyVocabularyTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'text'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->executeMigration('d7_taxonomy_vocabulary');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a migrated vocabulary contains the expected values.
|
||||
*
|
||||
* @param string $id
|
||||
* Entity ID to load and check.
|
||||
* @param string $expected_label
|
||||
* The label the migrated entity should have.
|
||||
* @param string $expected_description
|
||||
* The description the migrated entity should have.
|
||||
* @param string $expected_weight
|
||||
* The weight the migrated entity should have.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertEntity(string $id, string $expected_label, string $expected_description, int $expected_weight): void {
|
||||
/** @var \Drupal\taxonomy\VocabularyInterface $entity */
|
||||
$entity = Vocabulary::load($id);
|
||||
$this->assertInstanceOf(VocabularyInterface::class, $entity);
|
||||
$this->assertSame($expected_label, $entity->label());
|
||||
$this->assertSame($expected_description, $entity->getDescription());
|
||||
$this->assertSame($expected_weight, (int) $entity->get('weight'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 7 taxonomy vocabularies to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyVocabulary(): void {
|
||||
$this->assertEntity('tags', 'Tags', 'Use tags to group articles on similar topics into categories.', 0);
|
||||
$this->assertEntity('sujet_de_discussion', 'Sujet de discussion', 'Forum navigation vocabulary', -10);
|
||||
$this->assertEntity('test_vocabulary', 'Test Vocabulary', 'This is the vocabulary description', 0);
|
||||
$this->assertEntity('vocabulary_name_much_longer_th', 'vocabulary name clearly different than machine name and much longer than thirty two characters', 'description of vocabulary name much longer than thirty two characters', 0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Migrate taxonomy vocabularies to taxonomy.vocabulary.*.yml.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateTaxonomyVocabularyTranslationTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'config_translation',
|
||||
'language',
|
||||
'taxonomy',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_taxonomy_vocabulary',
|
||||
'd7_taxonomy_vocabulary_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 7 i18n taxonomy vocabularies to Drupal 8 migration.
|
||||
*/
|
||||
public function testTaxonomyVocabularyTranslation(): void {
|
||||
/** @var \Drupal\language\ConfigurableLanguageManagerInterface $language_manager */
|
||||
$language_manager = \Drupal::service('language_manager');
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.sujet_de_discussion');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.tags');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.test_vocabulary');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.test_vocabulary');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.vocabulary_name_clearly_diffe');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabulary_name_clearly_diffe');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabfixed');
|
||||
$this->assertSame('fr - VocabFixed', $config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocablocalized');
|
||||
$this->assertSame('fr - VocabLocalized', $config_translation->get('name'));
|
||||
$this->assertSame('fr - Vocabulary localize option', $config_translation->get('description'));
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.vocablocalized');
|
||||
$this->assertSame('is - VocabLocalized', $config_translation->get('name'));
|
||||
$this->assertSame('is - Vocabulary localize option', $config_translation->get('description'));
|
||||
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabtranslate');
|
||||
$this->assertNull($config_translation->get('name'));
|
||||
$this->assertNull($config_translation->get('description'));
|
||||
$config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.vocabtranslate');
|
||||
$this->assertSame('is - VocabTranslate', $config_translation->get('name'));
|
||||
$this->assertSame('is - Vocabulary translate option', $config_translation->get('description'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
|
||||
/**
|
||||
* Tests migration of localized translated taxonomy terms.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateTermLocalizedTranslationTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'taxonomy',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* The cached taxonomy tree items, keyed by vid and tid.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $treeData = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installConfig(static::$modules);
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_taxonomy_vocabulary',
|
||||
'd7_taxonomy_term',
|
||||
'd7_taxonomy_term_localized_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a migrated term contains the expected values.
|
||||
*
|
||||
* @param int $id
|
||||
* Entity ID to load and check.
|
||||
* @param string $expected_language
|
||||
* The language code for this term.
|
||||
* @param string $expected_label
|
||||
* The label the migrated entity should have.
|
||||
* @param string $expected_vid
|
||||
* The parent vocabulary the migrated entity should have.
|
||||
* @param string $expected_description
|
||||
* The description the migrated entity should have.
|
||||
* @param string $expected_format
|
||||
* The format the migrated entity should have.
|
||||
* @param int $expected_weight
|
||||
* The weight the migrated entity should have.
|
||||
* @param array $expected_parents
|
||||
* The parent terms the migrated entity should have.
|
||||
* @param int $expected_field_integer_value
|
||||
* The value the migrated entity field should have.
|
||||
* @param int $expected_term_reference_tid
|
||||
* The term reference ID the migrated entity field should have.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertEntity(int $id, string $expected_language, string $expected_label, string $expected_vid, string $expected_description = '', ?string $expected_format = NULL, int $expected_weight = 0, array $expected_parents = [], ?int $expected_field_integer_value = NULL, ?int $expected_term_reference_tid = NULL): void {
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load($id);
|
||||
$this->assertInstanceOf(TermInterface::class, $entity);
|
||||
$this->assertSame($expected_language, $entity->language()->getId());
|
||||
$this->assertSame($expected_label, $entity->label());
|
||||
$this->assertSame($expected_vid, $entity->bundle());
|
||||
$this->assertSame($expected_description, $entity->getDescription());
|
||||
$this->assertSame($expected_format, $entity->getFormat());
|
||||
$this->assertSame($expected_weight, $entity->getWeight());
|
||||
$this->assertHierarchy($expected_vid, $id, $expected_parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a term is present in the tree storage, with the right parents.
|
||||
*
|
||||
* @param string $vid
|
||||
* Vocabulary ID.
|
||||
* @param int $tid
|
||||
* ID of the term to check.
|
||||
* @param array $parent_ids
|
||||
* The expected parent term IDs.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertHierarchy(string $vid, int $tid, array $parent_ids): void {
|
||||
if (!isset($this->treeData[$vid])) {
|
||||
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vid);
|
||||
$this->treeData[$vid] = [];
|
||||
foreach ($tree as $item) {
|
||||
$this->treeData[$vid][$item->tid] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
|
||||
$term = $this->treeData[$vid][$tid];
|
||||
$this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 i18n localized taxonomy term to Drupal 8 migration.
|
||||
*/
|
||||
public function testTranslatedLocalizedTaxonomyTerms(): void {
|
||||
$this->assertEntity(19, 'en', 'Jupiter Station', 'vocablocalized', 'Holographic research.', 'filtered_html', 0, []);
|
||||
$this->assertEntity(20, 'en', 'DS9', 'vocablocalized', 'Terok Nor', 'filtered_html', 0, []);
|
||||
$this->assertEntity(25, 'en', 'Emissary', 'vocablocalized2', 'Pilot episode', 'filtered_html', 0, []);
|
||||
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load(19);
|
||||
$this->assertFalse($entity->hasTranslation('fr'));
|
||||
$this->assertTrue($entity->hasTranslation('is'));
|
||||
$translation = $entity->getTranslation('is');
|
||||
$this->assertSame('Jupiter Station', $translation->label());
|
||||
$this->assertSame('is - Holographic research. (localized)', $translation->getDescription());
|
||||
|
||||
$entity = Term::load(20);
|
||||
$this->assertFalse($entity->hasTranslation('is'));
|
||||
$this->assertTrue($entity->hasTranslation('fr'));
|
||||
$translation = $entity->getTranslation('fr');
|
||||
$this->assertSame('fr - DS9 (localized)', $translation->label());
|
||||
$this->assertSame('fr - Terok Nor (localized)', $translation->getDescription());
|
||||
$this->assertFALSE($entity->hasTranslation('is'));
|
||||
|
||||
$entity = Term::load(25);
|
||||
$this->assertFalse($entity->hasTranslation('is'));
|
||||
$this->assertTrue($entity->hasTranslation('fr'));
|
||||
$translation = $entity->getTranslation('fr');
|
||||
$this->assertSame('fr - Emissary', $translation->label());
|
||||
$this->assertSame('fr - Pilot episode', $translation->getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Kernel tests for taxonomy pending revisions.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class PendingRevisionTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'taxonomy',
|
||||
'node',
|
||||
'user',
|
||||
'text',
|
||||
'field',
|
||||
'system',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['taxonomy']);
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installSchema('node', 'node_access');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the taxonomy index work correctly with pending revisions.
|
||||
*/
|
||||
public function testTaxonomyIndexWithPendingRevision(): void {
|
||||
\Drupal::configFactory()->getEditable('taxonomy.settings')->set('maintain_index_table', TRUE)->save();
|
||||
|
||||
Vocabulary::create([
|
||||
'name' => 'test',
|
||||
'vid' => 'test',
|
||||
])->save();
|
||||
$term = Term::create([
|
||||
'name' => 'term1',
|
||||
'vid' => 'test',
|
||||
]);
|
||||
$term->save();
|
||||
$term2 = Term::create([
|
||||
'name' => 'term2',
|
||||
'vid' => 'test',
|
||||
]);
|
||||
$term2->save();
|
||||
|
||||
NodeType::create([
|
||||
'type' => 'page',
|
||||
'name' => 'Page',
|
||||
])->save();
|
||||
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'field_tags',
|
||||
'type' => 'entity_reference',
|
||||
'settings' => [
|
||||
'target_type' => 'taxonomy_term',
|
||||
],
|
||||
])->save();
|
||||
|
||||
FieldConfig::create([
|
||||
'field_name' => 'field_tags',
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
])->save();
|
||||
$node = Node::create([
|
||||
'type' => 'page',
|
||||
'title' => 'test_title',
|
||||
'field_tags' => [$term->id()],
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
$taxonomy_index = $this->getTaxonomyIndex();
|
||||
$this->assertEquals($term->id(), $taxonomy_index[$node->id()]->tid);
|
||||
|
||||
// Normal new revision.
|
||||
$node->setNewRevision(TRUE);
|
||||
$node->isDefaultRevision(TRUE);
|
||||
$node->field_tags->target_id = $term2->id();
|
||||
$node->save();
|
||||
|
||||
$taxonomy_index = $this->getTaxonomyIndex();
|
||||
$this->assertEquals($term2->id(), $taxonomy_index[$node->id()]->tid);
|
||||
|
||||
// Check that saving a pending revision does not affect the taxonomy index.
|
||||
$node->setNewRevision(TRUE);
|
||||
$node->isDefaultRevision(FALSE);
|
||||
$node->field_tags->target_id = $term->id();
|
||||
$node->save();
|
||||
|
||||
$taxonomy_index = $this->getTaxonomyIndex();
|
||||
$this->assertEquals($term2->id(), $taxonomy_index[$node->id()]->tid);
|
||||
|
||||
// Check that making the previously created pending revision the default
|
||||
// revision updates the taxonomy index correctly.
|
||||
$node->isDefaultRevision(TRUE);
|
||||
$node->save();
|
||||
|
||||
$taxonomy_index = $this->getTaxonomyIndex();
|
||||
$this->assertEquals($term->id(), $taxonomy_index[$node->id()]->tid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the taxonomy index from the database.
|
||||
*/
|
||||
protected function getTaxonomyIndex() {
|
||||
return \Drupal::database()->select('taxonomy_index')
|
||||
->fields('taxonomy_index')
|
||||
->execute()
|
||||
->fetchAllAssoc('nid');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
// cspell:ignore objectid objectindex plid
|
||||
|
||||
/**
|
||||
* Tests D6 i18n term localized source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\TermLocalizedTranslation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermLocalizedTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'language' => NULL,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'parent' => 1,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['i18n_strings'] = [
|
||||
[
|
||||
'lid' => 6,
|
||||
'objectid' => 1,
|
||||
'type' => 'term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '1',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 7,
|
||||
'objectid' => 1,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '1',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 8,
|
||||
'objectid' => 3,
|
||||
'type' => 'term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '3',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 9,
|
||||
'objectid' => 4,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '4',
|
||||
'format' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['locales_target'] = [
|
||||
[
|
||||
'lid' => 6,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - name value 1 translation',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 7,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - description value 1 translation',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 8,
|
||||
'language' => 'zu',
|
||||
'translation' => 'zu - description value 2 translation',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'property' => 'name',
|
||||
'language' => 'fr',
|
||||
'name_translated' => 'fr - name value 1 translation',
|
||||
'description_translated' => 'fr - description value 1 translation',
|
||||
],
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'property' => 'description',
|
||||
'language' => 'fr',
|
||||
'name_translated' => 'fr - name value 1 translation',
|
||||
'description_translated' => 'fr - description value 1 translation',
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'property' => 'name',
|
||||
'language' => 'zu',
|
||||
'name_translated' => 'zu - description value 2 translation',
|
||||
'description_translated' => NULL,
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Empty configuration will return terms for all vocabularies.
|
||||
$tests[0]['configuration'] = [];
|
||||
|
||||
// Test that only i18n_strings of type 'term' are returned.
|
||||
$tests[1] = $tests[0];
|
||||
$tests[0]['source_data']['i18n_strings'] = [
|
||||
[
|
||||
'lid' => 6,
|
||||
'objectid' => 1,
|
||||
'type' => 'term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '1',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 7,
|
||||
'objectid' => 1,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '1',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 8,
|
||||
'objectid' => 3,
|
||||
'type' => 'not term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '3',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 9,
|
||||
'objectid' => 4,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '4',
|
||||
'format' => 0,
|
||||
],
|
||||
];
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'property' => 'name',
|
||||
'language' => 'fr',
|
||||
'name_translated' => 'fr - name value 1 translation',
|
||||
'description_translated' => 'fr - description value 1 translation',
|
||||
],
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'property' => 'description',
|
||||
'language' => 'fr',
|
||||
'name_translated' => 'fr - name value 1 translation',
|
||||
'description_translated' => 'fr - description value 1 translation',
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
// cspell:ignore tnid
|
||||
|
||||
/**
|
||||
* Tests d6_term_node source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\TermNode
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermNodeTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['term_node'] = [
|
||||
[
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'tid' => '1',
|
||||
],
|
||||
[
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'tid' => '4',
|
||||
],
|
||||
[
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'tid' => '5',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['node'] = [
|
||||
[
|
||||
'nid' => '1',
|
||||
'vid' => '1',
|
||||
'type' => 'story',
|
||||
'language' => '',
|
||||
'title' => 'Test title',
|
||||
'uid' => '1',
|
||||
'status' => '1',
|
||||
'created' => '1388271197',
|
||||
'changed' => '1420861423',
|
||||
'comment' => '0',
|
||||
'promote' => '0',
|
||||
'moderate' => '0',
|
||||
'sticky' => '0',
|
||||
'tnid' => '0',
|
||||
'translate' => '0',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['term_data'] = [
|
||||
[
|
||||
'tid' => '1',
|
||||
'vid' => '3',
|
||||
'name' => 'term 1 of vocabulary 3',
|
||||
'description' => 'description of term 1 of vocabulary 3',
|
||||
'weight' => '0',
|
||||
],
|
||||
[
|
||||
'tid' => '4',
|
||||
'vid' => '3',
|
||||
'name' => 'term 4 of vocabulary 3',
|
||||
'description' => 'description of term 4 of vocabulary 3',
|
||||
'weight' => '6',
|
||||
],
|
||||
[
|
||||
'tid' => '5',
|
||||
'vid' => '3',
|
||||
'name' => 'term 5 of vocabulary 3',
|
||||
'description' => 'description of term 5 of vocabulary 3',
|
||||
'weight' => '7',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'nid' => 1,
|
||||
'vid' => 1,
|
||||
'type' => 'story',
|
||||
'tid' => [1, 4, 5],
|
||||
],
|
||||
];
|
||||
|
||||
// Set default value for expected count.
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
|
||||
// Set plugin configuration.
|
||||
$tests[0]['configuration'] = [
|
||||
'vid' => 3,
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term source with vocabulary filter.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermSourceWithVocabularyFilterTest extends TermTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
// Get the source data from parent.
|
||||
$tests = parent::providerSource();
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
];
|
||||
|
||||
// We know there are two rows with vid == 5.
|
||||
$tests[0]['expected_count'] = 2;
|
||||
|
||||
// Set up source plugin configuration.
|
||||
$tests[0]['configuration'] = [
|
||||
'bundle' => [5],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests taxonomy term source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'parent' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 3,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'parent' => [2],
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
'parent' => [3, 2],
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Empty configuration will return terms for all vocabularies.
|
||||
$tests[0]['configuration'] = [];
|
||||
|
||||
// Change configuration to get one vocabulary, 5.
|
||||
$tests[1]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
];
|
||||
$tests[1]['expected_count'] = NULL;
|
||||
$tests[1]['configuration']['bundle'] = ['5'];
|
||||
|
||||
// Same as previous test, but with configuration vocabulary as a string
|
||||
// instead of an array.
|
||||
$tests[2]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[2]['expected_data'] = $tests[1]['expected_data'];
|
||||
$tests[2]['expected_count'] = NULL;
|
||||
$tests[2]['configuration']['bundle'] = '5';
|
||||
|
||||
// Change configuration to get two vocabularies, 5 and 6.
|
||||
$tests[3]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[3]['expected_data'] = $tests[0]['expected_data'];
|
||||
// Remove the last element because it is for vid 3.
|
||||
array_pop($tests[3]['expected_data']);
|
||||
$tests[3]['expected_count'] = NULL;
|
||||
$tests[3]['configuration']['bundle'] = ['5', '6'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
// cspell:ignore trid
|
||||
|
||||
/**
|
||||
* Tests taxonomy term source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 10,
|
||||
'vid' => 6,
|
||||
'name' => 'zu - name value 2',
|
||||
'description' => 'zu - description value 2',
|
||||
'weight' => 0,
|
||||
'language' => 'zu',
|
||||
'trid' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'parent' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 3,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 10,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 10,
|
||||
'vid' => 6,
|
||||
'name' => 'zu - name value 2',
|
||||
'description' => 'zu - description value 2',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'zu',
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'parent' => [2],
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
'parent' => [3, 2],
|
||||
'language' => NULL,
|
||||
'trid' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D6 vocabulary per type source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\VocabularyPerType
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyPerTypeTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 1,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['vocabulary_node_types'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'type' => 'page',
|
||||
],
|
||||
[
|
||||
'vid' => 1,
|
||||
'type' => 'article',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'type' => 'article',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'i18ntaxonomy_vocabulary',
|
||||
'value' => 'a:2:{i:1;s:1:"3";i:2;s:1:"2";}',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['page', 'article'],
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
'i18ntaxonomy_vocabulary' => '3',
|
||||
],
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['page', 'article'],
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
'i18ntaxonomy_vocabulary' => '3',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 1,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['article'],
|
||||
'cardinality' => 1,
|
||||
'i18ntaxonomy_vocabulary' => '2',
|
||||
],
|
||||
];
|
||||
|
||||
// The source data.
|
||||
$tests[1] = $tests[0];
|
||||
unset($tests[1]['source_data']['variable']);
|
||||
|
||||
// The expected results.
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['page', 'article'],
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
'i18ntaxonomy_vocabulary' => '',
|
||||
],
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['page', 'article'],
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
'i18ntaxonomy_vocabulary' => '',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 1,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['article'],
|
||||
'cardinality' => 1,
|
||||
'i18ntaxonomy_vocabulary' => '',
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D6 vocabulary source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\Vocabulary
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 1,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['vocabulary_node_types'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'type' => 'page',
|
||||
],
|
||||
[
|
||||
'vid' => 1,
|
||||
'type' => 'article',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'type' => 'article',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'help' => 1,
|
||||
'relations' => 0,
|
||||
'hierarchy' => 0,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['page', 'article'],
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 1,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'node_types' => ['article'],
|
||||
'cardinality' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
// cspell:ignore objectid objectindex plid
|
||||
|
||||
/**
|
||||
* Tests D6 i18n vocabulary source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d6\VocabularyTranslation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0][0]['i18n_strings'] = [
|
||||
[
|
||||
'lid' => 1,
|
||||
'objectid' => 1,
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectindex' => 1,
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 2,
|
||||
'objectid' => 2,
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectindex' => 2,
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 3,
|
||||
'objectid' => 3,
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectindex' => 3,
|
||||
'format' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0][0]['locales_target'] = [
|
||||
[
|
||||
'lid' => 1,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - vocabulary 1',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 2,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - vocabulary 2',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0][0]['vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'vocabulary 1',
|
||||
'description' => 'description of vocabulary 1',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 4,
|
||||
'language' => '',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'vocabulary 2',
|
||||
'description' => 'description of vocabulary 2',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 5,
|
||||
'language' => '',
|
||||
],
|
||||
[
|
||||
'vid' => 3,
|
||||
'name' => 'vocabulary 3',
|
||||
'description' => 'description of vocabulary 3',
|
||||
'help' => 1,
|
||||
'relations' => 1,
|
||||
'hierarchy' => 1,
|
||||
'multiple' => 0,
|
||||
'required' => 0,
|
||||
'tags' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 5,
|
||||
'language' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'vocabulary 1',
|
||||
'description' => 'description of vocabulary 1',
|
||||
'lid' => '1',
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectid' => '1',
|
||||
'lt_lid' => '1',
|
||||
'translation' => 'fr - vocabulary 1',
|
||||
'language' => 'fr',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'vocabulary 2',
|
||||
'description' => 'description of vocabulary 2',
|
||||
'lid' => '2',
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectid' => '2',
|
||||
'lt_lid' => '2',
|
||||
'translation' => 'fr - vocabulary 2',
|
||||
'language' => 'fr',
|
||||
],
|
||||
];
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests taxonomy term entity translation source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\TermEntityTranslation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermEntityTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['entity_translation'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'en',
|
||||
'source' => '',
|
||||
'uid' => 1,
|
||||
'status' => 1,
|
||||
'translate' => 0,
|
||||
'created' => 1531343498,
|
||||
'changed' => 1531343498,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'fr',
|
||||
'source' => 'en',
|
||||
'uid' => 2,
|
||||
'status' => 1,
|
||||
'translate' => 1,
|
||||
'created' => 1531343508,
|
||||
'changed' => 1531343508,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'es',
|
||||
'source' => 'en',
|
||||
'uid' => 1,
|
||||
'status' => 0,
|
||||
'translate' => 0,
|
||||
'created' => 1531343528,
|
||||
'changed' => 1531343528,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config'] = [
|
||||
[
|
||||
'id' => 1,
|
||||
'field_name' => 'field_test',
|
||||
'type' => 'text',
|
||||
'module' => 'text',
|
||||
'active' => 1,
|
||||
'storage_type' => 'field_sql_storage',
|
||||
'storage_module' => 'field_sql_storage',
|
||||
'storage_active' => 1,
|
||||
'locked' => 1,
|
||||
'data' => 'a:0:{}',
|
||||
'cardinality' => 1,
|
||||
'translatable' => 1,
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'field_name' => 'name_field',
|
||||
'type' => 'text',
|
||||
'module' => 'text',
|
||||
'active' => 1,
|
||||
'storage_type' => 'field_sql_storage',
|
||||
'storage_module' => 'field_sql_storage',
|
||||
'storage_active' => 1,
|
||||
'locked' => 1,
|
||||
'data' => 'a:0:{}',
|
||||
'cardinality' => 1,
|
||||
'translatable' => 1,
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => 3,
|
||||
'field_name' => 'description_field',
|
||||
'type' => 'text',
|
||||
'module' => 'text',
|
||||
'active' => 1,
|
||||
'storage_type' => 'field_sql_storage',
|
||||
'storage_module' => 'field_sql_storage',
|
||||
'storage_active' => 1,
|
||||
'locked' => 1,
|
||||
'data' => 'a:0:{}',
|
||||
'cardinality' => 1,
|
||||
'translatable' => 1,
|
||||
'deleted' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config_instance'] = [
|
||||
[
|
||||
'id' => '1',
|
||||
'field_id' => 1,
|
||||
'field_name' => 'field_test',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'field_id' => 2,
|
||||
'field_name' => 'name_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => 3,
|
||||
'field_id' => 3,
|
||||
'field_name' => 'description_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_field_test'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'en',
|
||||
'delta' => 0,
|
||||
'field_test_value' => 'English field',
|
||||
'field_test_format' => 'filtered_html',
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'fr',
|
||||
'delta' => 0,
|
||||
'field_test_value' => 'French field',
|
||||
'field_test_format' => 'filtered_html',
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'es',
|
||||
'delta' => 0,
|
||||
'field_test_value' => 'Spanish field',
|
||||
'field_test_format' => 'filtered_html',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_name_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'en',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'Term Name EN',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'fr',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'Term Name FR',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'es',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'Term Name ES',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_description_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'en',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'Term Description EN',
|
||||
'description_field_format' => 'full_html',
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'fr',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'Term Description FR',
|
||||
'description_field_format' => 'full_html',
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'es',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'Term Description ES',
|
||||
'description_field_format' => 'full_html',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['system'] = [
|
||||
[
|
||||
'name' => 'title',
|
||||
'type' => 'module',
|
||||
'status' => 1,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 1,
|
||||
'name' => 'Term Name',
|
||||
'description' => 'Term Description',
|
||||
'format' => 'filtered_html',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'machine_name' => 'tags',
|
||||
'description' => '',
|
||||
'hierarchy' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'fr',
|
||||
'source' => 'en',
|
||||
'uid' => 2,
|
||||
'status' => 1,
|
||||
'translate' => 1,
|
||||
'created' => 1531343508,
|
||||
'changed' => 1531343508,
|
||||
'name' => 'Term Name FR',
|
||||
'description' => 'Term Description FR',
|
||||
'format' => 'full_html',
|
||||
'machine_name' => 'tags',
|
||||
'field_test' => [
|
||||
[
|
||||
'value' => 'French field',
|
||||
'format' => 'filtered_html',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'es',
|
||||
'source' => 'en',
|
||||
'uid' => 1,
|
||||
'status' => 0,
|
||||
'translate' => 0,
|
||||
'created' => 1531343528,
|
||||
'changed' => 1531343528,
|
||||
'name' => 'Term Name ES',
|
||||
'description' => 'Term Description ES',
|
||||
'format' => 'full_html',
|
||||
'machine_name' => 'tags',
|
||||
'field_test' => [
|
||||
[
|
||||
'value' => 'Spanish field',
|
||||
'format' => 'filtered_html',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
// cspell:ignore ltlanguage objectid objectindex plid tdlanguage tsid
|
||||
|
||||
/**
|
||||
* Tests D7 i18n term localized source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\TermLocalizedTranslation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermLocalizedTranslationTest extends TermTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = parent::providerSource();
|
||||
|
||||
for ($i = 1; $i < 4; $i++) {
|
||||
unset($tests[$i]);
|
||||
}
|
||||
|
||||
foreach ($tests[0]['source_data']['taxonomy_term_data'] as $key => $value) {
|
||||
$tests[0]['source_data']['taxonomy_term_data'][$key]['language'] = 'und';
|
||||
$tests[0]['source_data']['taxonomy_term_data'][$key]['i18n_tsid'] = 0;
|
||||
}
|
||||
// The source data.
|
||||
$tests[0]['source_data']['i18n_string'] = [
|
||||
[
|
||||
'lid' => 6,
|
||||
'objectid' => 1,
|
||||
'type' => 'term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '1',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 7,
|
||||
'objectid' => 1,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '1',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 8,
|
||||
'objectid' => 3,
|
||||
'type' => 'term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '3',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 9,
|
||||
'objectid' => 4,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '4',
|
||||
'format' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['locales_target'] = [
|
||||
[
|
||||
'lid' => 6,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - name value 1',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 7,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - description value 1',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 8,
|
||||
'language' => 'zu',
|
||||
'translation' => 'zu - name value 3',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1 (name_field)',
|
||||
'description' => 'description value 1 (description_field)',
|
||||
'weight' => 0,
|
||||
'language' => 'fr',
|
||||
'i18n_tsid' => '0',
|
||||
'machine_name' => 'tags',
|
||||
'tdlanguage' => 'und',
|
||||
'lid' => '6',
|
||||
'property' => 'name',
|
||||
'ltlanguage' => 'fr',
|
||||
'translation' => 'fr - name value 1',
|
||||
'name_translated' => 'fr - name value 1',
|
||||
'description_translated' => 'fr - description value 1',
|
||||
],
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1 (name_field)',
|
||||
'description' => 'description value 1 (description_field)',
|
||||
'weight' => 0,
|
||||
'language' => 'fr',
|
||||
'i18n_tsid' => '0',
|
||||
'machine_name' => 'tags',
|
||||
'tdlanguage' => 'und',
|
||||
'lid' => '7',
|
||||
'property' => 'description',
|
||||
'ltlanguage' => 'fr',
|
||||
'translation' => 'fr - description value 1',
|
||||
'name_translated' => 'fr - name value 1',
|
||||
'description_translated' => 'fr - description value 1',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Get translations for the tags bundle.
|
||||
$tests[0]['configuration']['bundle'] = ['tags'];
|
||||
|
||||
// The source data.
|
||||
$tests[1] = $tests[0];
|
||||
array_push($tests[1]['source_data']['i18n_string'],
|
||||
[
|
||||
'lid' => 10,
|
||||
'objectid' => 5,
|
||||
'type' => 'term',
|
||||
'property' => 'name',
|
||||
'objectindex' => '5',
|
||||
'format' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 11,
|
||||
'objectid' => 5,
|
||||
'type' => 'term',
|
||||
'property' => 'description',
|
||||
'objectindex' => '5',
|
||||
'format' => 0,
|
||||
]);
|
||||
array_push($tests[1]['source_data']['locales_target'],
|
||||
[
|
||||
'lid' => 10,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - name value 5',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 11,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - description value 5',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
]);
|
||||
|
||||
// The expected results.
|
||||
array_push($tests[1]['expected_data'],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'language' => 'zu',
|
||||
'i18n_tsid' => '0',
|
||||
'machine_name' => 'categories',
|
||||
'tdlanguage' => 'und',
|
||||
'lid' => '8',
|
||||
'property' => 'name',
|
||||
'ltlanguage' => 'zu',
|
||||
'translation' => 'zu - name value 3',
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'language' => 'fr',
|
||||
'i18n_tsid' => '0',
|
||||
'machine_name' => 'categories',
|
||||
'tdlanguage' => 'und',
|
||||
'lid' => '10',
|
||||
'property' => 'name',
|
||||
'ltlanguage' => 'fr',
|
||||
'translation' => 'fr - name value 5',
|
||||
'name_translated' => 'fr - name value 5',
|
||||
'description_translated' => 'fr - description value 5',
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'language' => 'fr',
|
||||
'i18n_tsid' => '0',
|
||||
'machine_name' => 'categories',
|
||||
'tdlanguage' => 'und',
|
||||
'lid' => '11',
|
||||
'property' => 'description',
|
||||
'ltlanguage' => 'fr',
|
||||
'translation' => 'fr - description value 5',
|
||||
'name_translated' => 'fr - name value 5',
|
||||
'description_translated' => 'fr - description value 5',
|
||||
]);
|
||||
|
||||
$tests[1]['expected_count'] = NULL;
|
||||
// Empty configuration will return terms for all vocabularies.
|
||||
$tests[1]['configuration'] = [];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
/**
|
||||
* Tests the taxonomy term source with vocabulary filter.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermSourceWithVocabularyFilterTest extends TermTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
// Get the source data from parent.
|
||||
$tests = parent::providerSource();
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1 (name_field)',
|
||||
'description' => 'description value 1 (description_field)',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4 (name_field)',
|
||||
'description' => 'description value 4 (description_field)',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
],
|
||||
];
|
||||
|
||||
// We know there are two rows with machine_name == 'tags'.
|
||||
$tests[0]['expected_count'] = 2;
|
||||
|
||||
// Set up source plugin configuration.
|
||||
$tests[0]['configuration'] = [
|
||||
'bundle' => ['tags'],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests taxonomy term source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\Term
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['taxonomy_term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1',
|
||||
'description' => 'description value 1',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4',
|
||||
'description' => 'description value 4',
|
||||
'weight' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'parent' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 3,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_vocabulary'] = [
|
||||
[
|
||||
'vid' => 5,
|
||||
'machine_name' => 'tags',
|
||||
],
|
||||
[
|
||||
'vid' => 6,
|
||||
'machine_name' => 'categories',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config'] = [
|
||||
[
|
||||
'id' => '3',
|
||||
'translatable' => '0',
|
||||
],
|
||||
[
|
||||
'id' => '4',
|
||||
'translatable' => '1',
|
||||
],
|
||||
[
|
||||
'id' => '5',
|
||||
'translatable' => '1',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config_instance'] = [
|
||||
[
|
||||
'id' => '2',
|
||||
'field_id' => 3,
|
||||
'field_name' => 'field_term_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => '3',
|
||||
'field_id' => 3,
|
||||
'field_name' => 'field_term_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'categories',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => '4',
|
||||
'field_id' => '4',
|
||||
'field_name' => 'name_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => '0',
|
||||
],
|
||||
[
|
||||
'id' => '5',
|
||||
'field_id' => '5',
|
||||
'field_name' => 'description_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => '0',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_field_term_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'delta' => 0,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'categories',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'delta' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_name_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'name value 1 (name_field)',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '4',
|
||||
'revision_id' => '4',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'name value 4 (name_field)',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_description_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'description value 1 (description_field)',
|
||||
'description_field_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '4',
|
||||
'revision_id' => '4',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'description value 4 (description_field)',
|
||||
'description_field_format' => NULL,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['system'] = [
|
||||
[
|
||||
'name' => 'title',
|
||||
'type' => 'module',
|
||||
'status' => 1,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'forum_containers',
|
||||
'value' => 'a:3:{i:0;s:1:"5";i:1;s:1:"6";i:2;s:1:"7";}',
|
||||
],
|
||||
[
|
||||
'name' => 'language_default',
|
||||
'value' => 'O:8:"stdClass":1:{s:8:"language";s:2:"en";}',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1 (name_field)',
|
||||
'description' => 'description value 1 (description_field)',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 2',
|
||||
'description' => 'description value 2',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 3',
|
||||
'description' => 'description value 3',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4 (name_field)',
|
||||
'description' => 'description value 4 (description_field)',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 5',
|
||||
'description' => 'description value 5',
|
||||
'weight' => 1,
|
||||
'parent' => [2],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name value 6',
|
||||
'description' => 'description value 6',
|
||||
'weight' => 0,
|
||||
'parent' => [3, 2],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 3,
|
||||
'name' => 'name value 7',
|
||||
'description' => 'description value 7',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'en',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Empty configuration will return terms for all vocabularies.
|
||||
$tests[0]['configuration'] = [];
|
||||
|
||||
// Change configuration to get one vocabulary, "tags".
|
||||
$tests[1]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 1 (name_field)',
|
||||
'description' => 'description value 1 (description_field)',
|
||||
'weight' => 0,
|
||||
'parent' => [0],
|
||||
'language' => 'en',
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'name value 4 (name_field)',
|
||||
'description' => 'description value 4 (description_field)',
|
||||
'weight' => 1,
|
||||
'parent' => [1],
|
||||
'language' => 'en',
|
||||
],
|
||||
];
|
||||
$tests[1]['expected_count'] = NULL;
|
||||
$tests[1]['configuration']['bundle'] = ['tags'];
|
||||
|
||||
// Same as previous test, but with configuration vocabulary as a string
|
||||
// instead of an array.
|
||||
$tests[2]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[2]['expected_data'] = $tests[1]['expected_data'];
|
||||
$tests[2]['expected_count'] = NULL;
|
||||
$tests[2]['configuration']['bundle'] = 'tags';
|
||||
|
||||
// Change configuration to get two vocabularies, "tags" and "categories".
|
||||
$tests[3]['source_data'] = $tests[0]['source_data'];
|
||||
$tests[3]['expected_data'] = $tests[0]['expected_data'];
|
||||
// Remove the last element because it is for vid 3.
|
||||
array_pop($tests[3]['expected_data']);
|
||||
$tests[3]['expected_count'] = NULL;
|
||||
$tests[3]['configuration']['bundle'] = ['tags', 'categories'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
// cspell:ignore tsid
|
||||
|
||||
/**
|
||||
* Tests D7 i18n term localized source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\TermTranslation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermTranslationTest extends TermTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// Ignore i18_modes 0 and 1, get i18n_mode 4.
|
||||
$tests[0]['source_data']['taxonomy_term_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'fr - name 1',
|
||||
'description' => 'desc 1',
|
||||
'weight' => 0,
|
||||
'language' => 'fr',
|
||||
'i18n_tsid' => '1',
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 5,
|
||||
'name' => 'name 2',
|
||||
'description' => 'desc 2',
|
||||
'weight' => 0,
|
||||
'language' => 'en',
|
||||
'i18n_tsid' => '1',
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'vid' => 6,
|
||||
'name' => 'name 3',
|
||||
'description' => 'desc 3',
|
||||
'weight' => 0,
|
||||
'language' => '',
|
||||
'i18n_tsid' => '',
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'is - name 4',
|
||||
'description' => 'desc 4',
|
||||
'weight' => 1,
|
||||
'language' => 'is',
|
||||
'i18n_tsid' => '1',
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'vid' => 6,
|
||||
'name' => 'name 5',
|
||||
'description' => 'desc 5',
|
||||
'weight' => 1,
|
||||
'language' => '',
|
||||
'i18n_tsid' => '',
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'vid' => 6,
|
||||
'name' => 'name 6',
|
||||
'description' => 'desc 6',
|
||||
'weight' => 0,
|
||||
'language' => '',
|
||||
'i18n_tsid' => '',
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'vid' => 7,
|
||||
'name' => 'is - captains',
|
||||
'description' => 'desc 7',
|
||||
'weight' => 0,
|
||||
'language' => 'is',
|
||||
'i18n_tsid' => '',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['taxonomy_term_hierarchy'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 3,
|
||||
'parent' => 0,
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'parent' => 1,
|
||||
],
|
||||
[
|
||||
'tid' => 5,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 3,
|
||||
],
|
||||
[
|
||||
'tid' => 6,
|
||||
'parent' => 2,
|
||||
],
|
||||
[
|
||||
'tid' => 7,
|
||||
'parent' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['source_data']['taxonomy_vocabulary'] = [
|
||||
[
|
||||
'vid' => 3,
|
||||
'machine_name' => 'foo',
|
||||
'language' => 'und',
|
||||
'i18n_mode' => '0',
|
||||
],
|
||||
[
|
||||
'vid' => 5,
|
||||
'machine_name' => 'tags',
|
||||
'language' => 'und',
|
||||
'i18n_mode' => '4',
|
||||
],
|
||||
[
|
||||
'vid' => 6,
|
||||
'machine_name' => 'categories',
|
||||
'language' => 'is',
|
||||
'i18n_mode' => '1',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['source_data']['field_config'] = [
|
||||
[
|
||||
'id' => '3',
|
||||
'translatable' => '0',
|
||||
],
|
||||
[
|
||||
'id' => '4',
|
||||
'translatable' => '1',
|
||||
],
|
||||
[
|
||||
'id' => '5',
|
||||
'translatable' => '1',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config_instance'] = [
|
||||
[
|
||||
'id' => '2',
|
||||
'field_id' => 3,
|
||||
'field_name' => 'field_term_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => '3',
|
||||
'field_id' => 3,
|
||||
'field_name' => 'field_term_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'categories',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
[
|
||||
'id' => '4',
|
||||
'field_id' => '4',
|
||||
'field_name' => 'name_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => '0',
|
||||
],
|
||||
[
|
||||
'id' => '5',
|
||||
'field_id' => '5',
|
||||
'field_name' => 'description_field',
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => '0',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_field_term_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'delta' => 0,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'categories',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'delta' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_name_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'fr - name 1',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '4',
|
||||
'revision_id' => '4',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'name_field_value' => 'is - name 4',
|
||||
'name_field_format' => NULL,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_description_field'] = [
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '1',
|
||||
'revision_id' => '1',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'desc 1',
|
||||
'description_field_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'bundle' => 'tags',
|
||||
'deleted' => '0',
|
||||
'entity_id' => '4',
|
||||
'revision_id' => '4',
|
||||
'language' => 'und',
|
||||
'delta' => '0',
|
||||
'description_field_value' => 'desc 4',
|
||||
'description_field_format' => NULL,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'tid' => 1,
|
||||
'vid' => 5,
|
||||
'name' => 'fr - name 1',
|
||||
'description' => 'desc 1',
|
||||
'weight' => 0,
|
||||
'language' => 'fr',
|
||||
'i18n_tsid' => '1',
|
||||
'machine_name' => 'tags',
|
||||
'i18n_mode' => '4',
|
||||
'td_language' => 'fr',
|
||||
'tv_i18n_mode' => '4',
|
||||
],
|
||||
[
|
||||
'tid' => 2,
|
||||
'vid' => 5,
|
||||
'name' => 'name 2',
|
||||
'description' => 'desc 2',
|
||||
'weight' => 0,
|
||||
'language' => 'en',
|
||||
'i18n_tsid' => '1',
|
||||
'machine_name' => 'tags',
|
||||
'i18n_mode' => '4',
|
||||
'td_language' => 'en',
|
||||
'tv_i18n_mode' => '4',
|
||||
],
|
||||
[
|
||||
'tid' => 4,
|
||||
'vid' => 5,
|
||||
'name' => 'is - name 4',
|
||||
'description' => 'desc 4',
|
||||
'weight' => 1,
|
||||
'language' => 'is',
|
||||
'i18n_tsid' => '1',
|
||||
'machine_name' => 'tags',
|
||||
'i18n_mode' => '4',
|
||||
'td_language' => 'is',
|
||||
'tv_i18n_mode' => '4',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_count'] = NULL;
|
||||
// Get translations for the tags bundle.
|
||||
$tests[0]['configuration']['bundle'] = ['tags'];
|
||||
|
||||
// Ignore i18_modes 0. get i18n_mode 2 and 4.
|
||||
$tests[1] = $tests[0];
|
||||
// Change a vocabulary to using fixed translation.
|
||||
$tests[1]['source_data']['taxonomy_vocabulary'][2] = [
|
||||
'vid' => 7,
|
||||
'machine_name' => 'categories',
|
||||
'language' => 'is',
|
||||
'i18n_mode' => '2',
|
||||
];
|
||||
|
||||
// Add the term with fixed translation.
|
||||
$tests[1]['expected_data'][] = [
|
||||
'tid' => 7,
|
||||
'vid' => 7,
|
||||
'name' => 'is - captains',
|
||||
'description' => 'desc 7',
|
||||
'weight' => 0,
|
||||
'language' => 'is',
|
||||
'i18n_tsid' => '',
|
||||
'machine_name' => 'categories',
|
||||
'i18n_mode' => '2',
|
||||
'td_language' => 'is',
|
||||
'tv_i18n_mode' => '2',
|
||||
];
|
||||
|
||||
$tests[1]['expected_count'] = NULL;
|
||||
$tests[1]['configuration']['bundle'] = NULL;
|
||||
|
||||
// No data returned when there is no i18n_mode column.
|
||||
$tests[2] = [];
|
||||
$tests[2]['source_data'] = $tests[0]['source_data'];
|
||||
foreach ($tests[2]['source_data']['taxonomy_vocabulary'] as &$table) {
|
||||
unset($table['i18n_mode']);
|
||||
}
|
||||
$tests[2]['expected_data'] = [0];
|
||||
$tests[2]['expected_count'] = 0;
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D7 vocabulary source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\Vocabulary
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['taxonomy_vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'Tags',
|
||||
'description' => 'Tags description.',
|
||||
'hierarchy' => 0,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'machine_name' => 'tags',
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'Categories',
|
||||
'description' => 'Categories description.',
|
||||
'hierarchy' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 0,
|
||||
'machine_name' => 'categories',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = $tests[0]['source_data']['taxonomy_vocabulary'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
// cspell:ignore objectid objectindex plid textgroup
|
||||
|
||||
/**
|
||||
* Tests D7 i18n vocabulary source plugin.
|
||||
*
|
||||
* @covers \Drupal\taxonomy\Plugin\migrate\source\d7\VocabularyTranslation
|
||||
* @group taxonomy
|
||||
*/
|
||||
class VocabularyTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['i18n_string'] = [
|
||||
[
|
||||
'lid' => '1',
|
||||
'textgroup' => 'taxonomy',
|
||||
'context' => 'vocabulary:1:name',
|
||||
'objectid' => '1',
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectindex' => '1',
|
||||
'format' => '',
|
||||
],
|
||||
[
|
||||
'lid' => '2',
|
||||
'textgroup' => 'taxonomy',
|
||||
'context' => 'vocabulary:1:description',
|
||||
'objectid' => '1',
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'description',
|
||||
'objectindex' => '1',
|
||||
'format' => '',
|
||||
],
|
||||
[
|
||||
'lid' => '764',
|
||||
'textgroup' => 'field',
|
||||
'context' => 'field_color:blog:label',
|
||||
'objectid' => 'blog',
|
||||
'type' => 'field_color',
|
||||
'property' => 'label',
|
||||
'objectindex' => '0',
|
||||
'format' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['source_data']['locales_target'] = [
|
||||
[
|
||||
'lid' => 1,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - vocabulary 1',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => 2,
|
||||
'language' => 'fr',
|
||||
'translation' => 'fr - description of vocabulary 1',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
[
|
||||
'lid' => '764',
|
||||
'translation' => 'Color',
|
||||
'language' => 'fr',
|
||||
'plid' => '0',
|
||||
'plural' => '0',
|
||||
'i18n_status' => '0',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['source_data']['taxonomy_vocabulary'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'vocabulary 1',
|
||||
'machine_name' => 'vocabulary_1',
|
||||
'description' => 'description of vocabulary 1',
|
||||
'hierarchy' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 4,
|
||||
'language' => 'und',
|
||||
'i18n_mode' => '4',
|
||||
|
||||
],
|
||||
[
|
||||
'vid' => 2,
|
||||
'name' => 'vocabulary 2',
|
||||
'machine_name' => 'vocabulary_1',
|
||||
'description' => 'description of vocabulary 2',
|
||||
'hierarchy' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 4,
|
||||
'language' => 'und',
|
||||
'i18n_mode' => '4',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'vocabulary 1',
|
||||
'machine_name' => 'vocabulary_1',
|
||||
'description' => 'description of vocabulary 1',
|
||||
'hierarchy' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 4,
|
||||
'i18n_mode' => '4',
|
||||
'lid' => '1',
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'name',
|
||||
'objectid' => '1',
|
||||
'lt_lid' => '1',
|
||||
'translation' => 'fr - vocabulary 1',
|
||||
'v_language' => 'und',
|
||||
'textgroup' => 'taxonomy',
|
||||
'context' => 'vocabulary:1:name',
|
||||
'objectindex' => '1',
|
||||
'format' => '',
|
||||
'language' => 'fr',
|
||||
'plid' => '0',
|
||||
'plural' => '0',
|
||||
'i18n_status' => '0',
|
||||
],
|
||||
[
|
||||
'vid' => 1,
|
||||
'name' => 'vocabulary 1',
|
||||
'machine_name' => 'vocabulary_1',
|
||||
'description' => 'description of vocabulary 1',
|
||||
'hierarchy' => 1,
|
||||
'module' => 'taxonomy',
|
||||
'weight' => 4,
|
||||
'i18n_mode' => '4',
|
||||
'lid' => '2',
|
||||
'type' => 'vocabulary',
|
||||
'property' => 'description',
|
||||
'objectid' => '1',
|
||||
'lt_lid' => '2',
|
||||
'translation' => 'fr - description of vocabulary 1',
|
||||
'v_language' => 'und',
|
||||
'textgroup' => 'taxonomy',
|
||||
'context' => 'vocabulary:1:description',
|
||||
'objectindex' => '1',
|
||||
'format' => '',
|
||||
'language' => 'fr',
|
||||
'plid' => '0',
|
||||
'plural' => '0',
|
||||
'i18n_status' => '0',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[1] = $tests[0];
|
||||
|
||||
// Test without the language and i18n_mode columns in taxonomy_vocabulary.
|
||||
foreach ($tests[1]['source_data']['taxonomy_vocabulary'] as &$data) {
|
||||
unset($data['language']);
|
||||
unset($data['i18n_mode']);
|
||||
}
|
||||
foreach ($tests[1]['expected_data'] as &$data) {
|
||||
unset($data['v_language']);
|
||||
unset($data['i18n_mode']);
|
||||
}
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Tests that appropriate query tags are added.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TaxonomyQueryAlterTest extends KernelTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'filter',
|
||||
'taxonomy',
|
||||
'taxonomy_test',
|
||||
'text',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests that appropriate tags are added when querying the database.
|
||||
*/
|
||||
public function testTaxonomyQueryAlter(): void {
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
|
||||
// Create a new vocabulary and add a few terms to it.
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$terms = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$terms[$i] = $this->createTerm($vocabulary);
|
||||
}
|
||||
|
||||
// Set up hierarchy. Term 2 is a child of 1.
|
||||
$terms[2]->parent = $terms[1]->id();
|
||||
$terms[2]->save();
|
||||
|
||||
/** @var \Drupal\taxonomy\TermStorageInterface $term_storage */
|
||||
$term_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$loaded_term = $term_storage->load($terms[0]->id());
|
||||
// First term was loaded.
|
||||
$this->assertEquals($terms[0]->id(), $loaded_term->id());
|
||||
// TermStorage::load().
|
||||
$this->assertQueryTagTestResult(1, 0);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$loaded_terms = $term_storage->loadTree($vocabulary->id());
|
||||
// All terms were loaded.
|
||||
$this->assertCount(5, $loaded_terms);
|
||||
// TermStorage::loadTree().
|
||||
$this->assertQueryTagTestResult(1, 1);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$loaded_terms = $term_storage->loadParents($terms[2]->id());
|
||||
// All parent terms were loaded.
|
||||
$this->assertCount(1, $loaded_terms);
|
||||
// TermStorage::loadParents().
|
||||
$this->assertQueryTagTestResult(3, 1);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$loaded_terms = $term_storage->loadChildren($terms[1]->id());
|
||||
// All child terms were loaded.
|
||||
$this->assertCount(1, $loaded_terms);
|
||||
// TermStorage::loadChildren().
|
||||
$this->assertQueryTagTestResult(3, 1);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$connection = Database::getConnection();
|
||||
$query = $connection->select('taxonomy_term_data', 't');
|
||||
$query->addField('t', 'tid');
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$tids = $query->execute()->fetchCol();
|
||||
// All term IDs were retrieved.
|
||||
$this->assertCount(5, $tids);
|
||||
// Database custom ::select() with 'taxonomy_term_access' tag (preferred).
|
||||
$this->assertQueryTagTestResult(1, 1);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$query = $connection->select('taxonomy_term_data', 't');
|
||||
$query->addField('t', 'tid');
|
||||
$query->addTag('term_access');
|
||||
$tids = $query->execute()->fetchCol();
|
||||
// All term IDs were retrieved.
|
||||
$this->assertCount(5, $tids);
|
||||
// Database custom ::select() with term_access tag (deprecated).
|
||||
$this->assertQueryTagTestResult(1, 1);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$query = \Drupal::entityQuery('taxonomy_term')->accessCheck(FALSE);
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$result = $query->execute();
|
||||
// All term IDs were retrieved.
|
||||
$this->assertCount(5, $result);
|
||||
// Custom entity query with taxonomy_term_access tag (preferred).
|
||||
$this->assertQueryTagTestResult(1, 1);
|
||||
|
||||
$this->setupQueryTagTestHooks();
|
||||
$query = \Drupal::entityQuery('taxonomy_term')->accessCheck(FALSE);
|
||||
$query->addTag('term_access');
|
||||
$result = $query->execute();
|
||||
// All term IDs were retrieved.
|
||||
$this->assertCount(5, $result);
|
||||
// Custom entity query with taxonomy_term_access tag (preferred).
|
||||
$this->assertQueryTagTestResult(1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the hooks in the test module.
|
||||
*/
|
||||
protected function setupQueryTagTestHooks(): void {
|
||||
$this->container->get('entity_type.manager')->getStorage('taxonomy_term')->resetCache();
|
||||
$state = $this->container->get('state');
|
||||
$state->set('taxonomy_test_query_alter', 0);
|
||||
$state->set('taxonomy_test_query_term_access_alter', 0);
|
||||
$state->set('taxonomy_test_query_taxonomy_term_access_alter', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies invocation of the hooks in the test module.
|
||||
*
|
||||
* @param int $expected_generic_invocations
|
||||
* The number of times the generic query_alter hook is expected to have
|
||||
* been invoked.
|
||||
* @param int $expected_specific_invocations
|
||||
* The number of times the tag-specific query_alter hooks are expected to
|
||||
* have been invoked.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertQueryTagTestResult(int $expected_generic_invocations, int $expected_specific_invocations): void {
|
||||
$state = $this->container->get('state');
|
||||
$this->assertEquals($expected_generic_invocations, $state->get('taxonomy_test_query_alter'));
|
||||
$this->assertEquals($expected_specific_invocations, $state->get('taxonomy_test_query_term_access_alter'));
|
||||
$this->assertEquals($expected_specific_invocations, $state->get('taxonomy_test_query_taxonomy_term_access_alter'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Verifies operation of a taxonomy-based Entity Query.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermEntityQueryTest extends KernelTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'field',
|
||||
'filter',
|
||||
'taxonomy',
|
||||
'text',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests that a basic taxonomy entity query works.
|
||||
*/
|
||||
public function testTermEntityQuery(): void {
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$vocabulary = $this->createVocabulary();
|
||||
|
||||
$terms = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$term = $this->createTerm($vocabulary);
|
||||
$terms[$term->id()] = $term;
|
||||
}
|
||||
$result = \Drupal::entityQuery('taxonomy_term')->accessCheck(FALSE)->execute();
|
||||
sort($result);
|
||||
$this->assertEquals(array_keys($terms), $result);
|
||||
$tid = reset($result);
|
||||
$ids = (object) [
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => $tid,
|
||||
'bundle' => $vocabulary->id(),
|
||||
];
|
||||
$term = _field_create_entity_from_ids($ids);
|
||||
$this->assertEquals($tid, $term->id());
|
||||
|
||||
// Create a second vocabulary and five more terms.
|
||||
$vocabulary2 = $this->createVocabulary();
|
||||
$terms2 = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$term = $this->createTerm($vocabulary2);
|
||||
$terms2[$term->id()] = $term;
|
||||
}
|
||||
|
||||
$result = \Drupal::entityQuery('taxonomy_term')
|
||||
->accessCheck(FALSE)
|
||||
->condition('vid', $vocabulary2->id())
|
||||
->execute();
|
||||
sort($result);
|
||||
$this->assertEquals(array_keys($terms2), $result);
|
||||
$tid = reset($result);
|
||||
$ids = (object) [
|
||||
'entity_type' => 'taxonomy_term',
|
||||
'entity_id' => $tid,
|
||||
'bundle' => $vocabulary2->id(),
|
||||
];
|
||||
$term = _field_create_entity_from_ids($ids);
|
||||
$this->assertEquals($tid, $term->id());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\entity_test\EntityTestHelper;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the settings of restricting term selection to a single vocabulary.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermEntityReferenceTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'entity_test',
|
||||
'field',
|
||||
'system',
|
||||
'taxonomy',
|
||||
'text',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installEntitySchema('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an entity reference field restricted to a single vocabulary.
|
||||
*
|
||||
* Creates two vocabularies with a term, then set up the entity reference
|
||||
* field to limit the target vocabulary to one of them, ensuring that
|
||||
* the restriction applies.
|
||||
*/
|
||||
public function testSelectionTestVocabularyRestriction(): void {
|
||||
// Create two vocabularies.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'test1',
|
||||
'vid' => 'test1',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
$vocabulary2 = Vocabulary::create([
|
||||
'name' => 'test2',
|
||||
'vid' => 'test2',
|
||||
]);
|
||||
$vocabulary2->save();
|
||||
|
||||
$term = Term::create([
|
||||
'name' => 'term1',
|
||||
'vid' => $vocabulary->id(),
|
||||
]);
|
||||
$term->save();
|
||||
$term2 = Term::create([
|
||||
'name' => 'term2',
|
||||
'vid' => $vocabulary2->id(),
|
||||
]);
|
||||
$term2->save();
|
||||
|
||||
// Create an entity reference field.
|
||||
$field_name = 'taxonomy_' . $vocabulary->id();
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'translatable' => FALSE,
|
||||
'settings' => [
|
||||
'target_type' => 'taxonomy_term',
|
||||
],
|
||||
'type' => 'entity_reference',
|
||||
'cardinality' => 1,
|
||||
]);
|
||||
$field_storage->save();
|
||||
|
||||
EntityTestHelper::createBundle('test_bundle');
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'test_bundle',
|
||||
'settings' => [
|
||||
'handler' => 'default',
|
||||
'handler_settings' => [
|
||||
// Restrict selection of terms to a single vocabulary.
|
||||
'target_bundles' => [
|
||||
$vocabulary->id() => $vocabulary->id(),
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$field->save();
|
||||
|
||||
$handler = $this->container->get('plugin.manager.entity_reference_selection')->getSelectionHandler($field);
|
||||
$result = $handler->getReferenceableEntities();
|
||||
|
||||
$expected_result = [
|
||||
$vocabulary->id() => [
|
||||
$term->id() => $term->getName(),
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected_result, $result, 'Terms selection restricted to a single vocabulary.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests handling of pending revisions.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\taxonomy\Plugin\Validation\Constraint\TaxonomyTermHierarchyConstraintValidator
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermHierarchyValidationTest extends EntityKernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the term hierarchy validation with re-parenting in pending revisions.
|
||||
*/
|
||||
public function testTermHierarchyValidation(): void {
|
||||
$vocabulary_id = $this->randomMachineName();
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => $vocabulary_id,
|
||||
'vid' => $vocabulary_id,
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
// Create a simple hierarchy in the vocabulary, a root term and three parent
|
||||
// terms.
|
||||
/** @var \Drupal\Core\Entity\RevisionableStorageInterface $term_storage */
|
||||
$term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
|
||||
$root = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
]);
|
||||
$root->save();
|
||||
$parent1 = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
'parent' => $root->id(),
|
||||
]);
|
||||
$parent1->save();
|
||||
$parent2 = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
'parent' => $root->id(),
|
||||
]);
|
||||
$parent2->save();
|
||||
$parent3 = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
'parent' => $root->id(),
|
||||
]);
|
||||
$parent3->save();
|
||||
|
||||
// Create a child term and assign one of the parents above.
|
||||
$child1 = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
'parent' => $parent1->id(),
|
||||
]);
|
||||
$violations = $child1->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$child1->save();
|
||||
|
||||
$validation_message = 'You can only change the hierarchy for the published version of this term.';
|
||||
|
||||
// Add a pending revision without changing the term parent.
|
||||
$pending_name = $this->randomMachineName();
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->name = $pending_name;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertEmpty($violations);
|
||||
|
||||
// Add a pending revision and change the parent.
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->parent = $parent2;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
|
||||
// Add a pending revision and add a new parent.
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->parent[0] = $parent1;
|
||||
$child_pending->parent[1] = $parent3;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
|
||||
// Add a pending revision and use the root term as a parent.
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->parent[0] = $root;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
|
||||
// Add a pending revision and remove the parent.
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->parent[0] = NULL;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
|
||||
// Add a pending revision and change the weight.
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->weight = 10;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('weight', $violations[0]->getPropertyPath());
|
||||
|
||||
// Add a pending revision and change both the parent and the weight.
|
||||
$child_pending = $term_storage->createRevision($child1, FALSE);
|
||||
$child_pending->parent = $parent2;
|
||||
$child_pending->weight = 10;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertCount(2, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals($validation_message, $violations[1]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
$this->assertEquals('weight', $violations[1]->getPropertyPath());
|
||||
|
||||
// Add a published revision and change the parent.
|
||||
$child_pending = $term_storage->createRevision($child1, TRUE);
|
||||
$child_pending->parent[0] = $parent2;
|
||||
$violations = $child_pending->validate();
|
||||
$this->assertEmpty($violations);
|
||||
|
||||
// Add a new term as a third-level child.
|
||||
// The taxonomy tree structure ends up as follows:
|
||||
// root
|
||||
// - parent1
|
||||
// - parent2
|
||||
// -- child1 <- this will be a term with a pending revision
|
||||
// --- child2
|
||||
// - parent3
|
||||
$child2 = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
'parent' => $child1->id(),
|
||||
]);
|
||||
$child2->save();
|
||||
|
||||
// Change 'child1' to be a pending revision.
|
||||
$child1 = $term_storage->createRevision($child1, FALSE);
|
||||
$child1->save();
|
||||
|
||||
// Check that a child of a pending term can not be re-parented.
|
||||
$child2_pending = $term_storage->createRevision($child2, FALSE);
|
||||
$child2_pending->parent = $parent3;
|
||||
$violations = $child2_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
|
||||
// Check that another term which has a pending revision can not moved under
|
||||
// another term which has pending revision.
|
||||
$parent3_pending = $term_storage->createRevision($parent3, FALSE);
|
||||
$parent3_pending->parent = $child1;
|
||||
$violations = $parent3_pending->validate();
|
||||
$this->assertCount(1, $violations);
|
||||
$this->assertEquals($validation_message, $violations[0]->getMessage());
|
||||
$this->assertEquals('parent', $violations[0]->getPropertyPath());
|
||||
|
||||
// Check that a new term can be created under a term that has a pending
|
||||
// revision.
|
||||
$child3 = $term_storage->create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'vid' => $vocabulary_id,
|
||||
'parent' => $child1->id(),
|
||||
]);
|
||||
$violations = $child3->validate();
|
||||
$this->assertEmpty($violations);
|
||||
}
|
||||
|
||||
}
|
||||
208
web/core/modules/taxonomy/tests/src/Kernel/TermKernelTest.php
Normal file
208
web/core/modules/taxonomy/tests/src/Kernel/TermKernelTest.php
Normal file
@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Kernel;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
use Drupal\Tests\user\Traits\UserCreationTrait;
|
||||
|
||||
/**
|
||||
* Kernel tests for taxonomy term functions.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class TermKernelTest extends KernelTestBase {
|
||||
|
||||
use TaxonomyTestTrait;
|
||||
use UserCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['filter', 'taxonomy', 'text', 'user', 'system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installConfig(['filter']);
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installEntitySchema('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a deleted term is no longer in the vocabulary.
|
||||
*/
|
||||
public function testTermDelete(): void {
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$valid_term = $this->createTerm($vocabulary);
|
||||
// Delete a valid term.
|
||||
$valid_term->delete();
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['vid' => $vocabulary->id()]);
|
||||
$this->assertEmpty($terms, 'Vocabulary is empty after deletion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deleting a parent of a term with multiple parents does not delete the term.
|
||||
*/
|
||||
public function testMultipleParentDelete(): void {
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$parent_term1 = $this->createTerm($vocabulary);
|
||||
$parent_term2 = $this->createTerm($vocabulary);
|
||||
$child_term = $this->createTerm($vocabulary);
|
||||
$child_term->parent = [$parent_term1->id(), $parent_term2->id()];
|
||||
$child_term->save();
|
||||
$child_term_id = $child_term->id();
|
||||
|
||||
$parent_term1->delete();
|
||||
$term_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||
$term_storage->resetCache([$child_term_id]);
|
||||
$child_term = Term::load($child_term_id);
|
||||
$this->assertNotEmpty($child_term, 'Child term is not deleted if only one of its parents is removed.');
|
||||
|
||||
$parent_term2->delete();
|
||||
$term_storage->resetCache([$child_term_id]);
|
||||
$child_term = Term::load($child_term_id);
|
||||
$this->assertEmpty($child_term, 'Child term is deleted if all of its parents are removed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a taxonomy with terms that have multiple parents of different depths.
|
||||
*/
|
||||
public function testTaxonomyVocabularyTree(): void {
|
||||
// Create a new vocabulary with 6 terms.
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$term = [];
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$term[$i] = $this->createTerm($vocabulary);
|
||||
}
|
||||
|
||||
// Get the taxonomy storage.
|
||||
$taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||
|
||||
// Set the weight on $term[1] so it appears before $term[5] when fetching
|
||||
// the parents for $term[2], in order to test for a regression on
|
||||
// \Drupal\taxonomy\TermStorageInterface::loadAllParents().
|
||||
$term[1]->weight = -1;
|
||||
$term[1]->save();
|
||||
|
||||
// $term[2] is a child of 1 and 5.
|
||||
$term[2]->parent = [$term[1]->id(), $term[5]->id()];
|
||||
$term[2]->save();
|
||||
// $term[3] is a child of 2.
|
||||
$term[3]->parent = [$term[2]->id()];
|
||||
$term[3]->save();
|
||||
// $term[5] is a child of 4.
|
||||
$term[5]->parent = [$term[4]->id()];
|
||||
$term[5]->save();
|
||||
|
||||
// Expected tree:
|
||||
// term[0] | depth: 0
|
||||
// term[1] | depth: 0
|
||||
// -- term[2] | depth: 1
|
||||
// ---- term[3] | depth: 2
|
||||
// term[4] | depth: 0
|
||||
// -- term[5] | depth: 1
|
||||
// ---- term[2] | depth: 2
|
||||
// ------ term[3] | depth: 3
|
||||
|
||||
// Count $term[1] parents with $max_depth = 1.
|
||||
$tree = $taxonomy_storage->loadTree($vocabulary->id(), $term[1]->id(), 1);
|
||||
$this->assertCount(1, $tree, 'We have one parent with depth 1.');
|
||||
|
||||
// Count all vocabulary tree elements.
|
||||
$tree = $taxonomy_storage->loadTree($vocabulary->id());
|
||||
$this->assertCount(8, $tree, 'We have all vocabulary tree elements.');
|
||||
|
||||
// Count elements in every tree depth.
|
||||
foreach ($tree as $element) {
|
||||
if (!isset($depth_count[$element->depth])) {
|
||||
$depth_count[$element->depth] = 0;
|
||||
}
|
||||
$depth_count[$element->depth]++;
|
||||
}
|
||||
$this->assertEquals(3, $depth_count[0], 'Three elements in taxonomy tree depth 0.');
|
||||
$this->assertEquals(2, $depth_count[1], 'Two elements in taxonomy tree depth 1.');
|
||||
$this->assertEquals(2, $depth_count[2], 'Two elements in taxonomy tree depth 2.');
|
||||
$this->assertEquals(1, $depth_count[3], 'One element in taxonomy tree depth 3.');
|
||||
|
||||
/** @var \Drupal\taxonomy\TermStorageInterface $storage */
|
||||
$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
|
||||
// Count parents of $term[2].
|
||||
$parents = $storage->loadParents($term[2]->id());
|
||||
$this->assertCount(2, $parents, 'The term has two parents.');
|
||||
|
||||
// Count parents of $term[3].
|
||||
$parents = $storage->loadParents($term[3]->id());
|
||||
$this->assertCount(1, $parents, 'The term has one parent.');
|
||||
|
||||
// Identify all ancestors of $term[2].
|
||||
$ancestors = $storage->loadAllParents($term[2]->id());
|
||||
$this->assertCount(4, $ancestors, 'The term has four ancestors including the term itself.');
|
||||
|
||||
// Identify all ancestors of $term[3].
|
||||
$ancestors = $storage->loadAllParents($term[3]->id());
|
||||
$this->assertCount(5, $ancestors, 'The term has five ancestors including the term itself.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a Term is renderable when unsaved (preview).
|
||||
*/
|
||||
public function testTermPreview(): void {
|
||||
$entity_manager = \Drupal::entityTypeManager();
|
||||
$vocabulary = $this->createVocabulary();
|
||||
|
||||
// Create a unsaved term.
|
||||
$term = $entity_manager->getStorage('taxonomy_term')->create([
|
||||
'vid' => $vocabulary->id(),
|
||||
'name' => 'Foo',
|
||||
]);
|
||||
|
||||
// Confirm we can get the view of unsaved term.
|
||||
$render_array = $entity_manager->getViewBuilder('taxonomy_term')
|
||||
->view($term);
|
||||
$this->assertNotEmpty($render_array, 'Term view builder is built.');
|
||||
|
||||
// Confirm we can render said view.
|
||||
$rendered = (string) \Drupal::service('renderer')->renderInIsolation($render_array);
|
||||
$this->assertNotEmpty(trim($rendered), 'Term is able to be rendered.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests revision log access.
|
||||
*/
|
||||
public function testRevisionLogAccess(): void {
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$entity = $this->createTerm($vocabulary, ['status' => TRUE]);
|
||||
$admin = $this->createUser([
|
||||
'administer taxonomy',
|
||||
'access content',
|
||||
]);
|
||||
$editor = $this->createUser([
|
||||
'edit terms in ' . $vocabulary->id(),
|
||||
'access content',
|
||||
]);
|
||||
$viewer = $this->createUser([
|
||||
'access content',
|
||||
]);
|
||||
|
||||
$this->assertTrue($entity->get('revision_log_message')->access('view', $admin));
|
||||
$this->assertTrue($entity->get('revision_log_message')->access('view', $editor));
|
||||
$this->assertFalse($entity->get('revision_log_message')->access('view', $viewer));
|
||||
}
|
||||
|
||||
/**
|
||||
* The "parent" field must restrict references to the same vocabulary.
|
||||
*/
|
||||
public function testParentHandlerSettings(): void {
|
||||
$vocabulary = $this->createVocabulary();
|
||||
$vocabulary_fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('taxonomy_term', $vocabulary->id());
|
||||
$parent_target_bundles = $vocabulary_fields['parent']->getSetting('handler_settings')['target_bundles'];
|
||||
$this->assertSame([$vocabulary->id() => $vocabulary->id()], $parent_target_bundles);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user