3a1a5a241d033153188b8afb6c2cb448abc59456
[yaffs-website] / web / core / modules / taxonomy / tests / src / Functional / Rest / TermResourceTestBase.php
1 <?php
2
3 namespace Drupal\Tests\taxonomy\Functional\Rest;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\taxonomy\Entity\Term;
7 use Drupal\taxonomy\Entity\Vocabulary;
8 use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
9 use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
10 use GuzzleHttp\RequestOptions;
11
12 abstract class TermResourceTestBase extends EntityResourceTestBase {
13
14   use BcTimestampNormalizerUnixTestTrait;
15
16   /**
17    * {@inheritdoc}
18    */
19   public static $modules = ['taxonomy', 'path'];
20
21   /**
22    * {@inheritdoc}
23    */
24   protected static $entityTypeId = 'taxonomy_term';
25
26   /**
27    * {@inheritdoc}
28    */
29   protected static $patchProtectedFieldNames = [
30     'changed' => NULL,
31   ];
32
33   /**
34    * @var \Drupal\taxonomy\TermInterface
35    */
36   protected $entity;
37
38   /**
39    * {@inheritdoc}
40    */
41   protected function setUpAuthorization($method) {
42     switch ($method) {
43       case 'GET':
44         $this->grantPermissionsToTestedRole(['access content']);
45         break;
46
47       case 'POST':
48         $this->grantPermissionsToTestedRole(['create terms in camelids']);
49         break;
50
51       case 'PATCH':
52         // Grant the 'create url aliases' permission to test the case when
53         // the path field is accessible, see
54         // \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase
55         // for a negative test.
56         $this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
57         break;
58
59       case 'DELETE':
60         $this->grantPermissionsToTestedRole(['delete terms in camelids']);
61         break;
62
63     }
64   }
65
66   /**
67    * {@inheritdoc}
68    */
69   protected function createEntity() {
70     $vocabulary = Vocabulary::load('camelids');
71     if (!$vocabulary) {
72       // Create a "Camelids" vocabulary.
73       $vocabulary = Vocabulary::create([
74         'name' => 'Camelids',
75         'vid' => 'camelids',
76       ]);
77       $vocabulary->save();
78     }
79
80     // Create a "Llama" taxonomy term.
81     $term = Term::create(['vid' => $vocabulary->id()])
82       ->setName('Llama')
83       ->setDescription("It is a little known fact that llamas cannot count higher than seven.")
84       ->setChangedTime(123456789)
85       ->set('path', '/llama');
86     $term->save();
87
88     return $term;
89   }
90
91   /**
92    * {@inheritdoc}
93    */
94   protected function getExpectedNormalizedEntity() {
95     // We test with multiple parent terms, and combinations thereof.
96     // @see ::createEntity()
97     // @see ::testGet()
98     // @see ::testGetTermWithParent()
99     // @see ::providerTestGetTermWithParent()
100     $parent_term_ids = [];
101     for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
102       $parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
103     }
104
105     $expected_parent_normalization = FALSE;
106     switch ($parent_term_ids) {
107       case [0]:
108         $expected_parent_normalization = [
109           [
110             'target_id' => NULL,
111           ],
112         ];
113         break;
114       case [2]:
115         $expected_parent_normalization = [
116           [
117             'target_id' => 2,
118             'target_type' => 'taxonomy_term',
119             'target_uuid' => Term::load(2)->uuid(),
120             'url' => base_path() . 'taxonomy/term/2',
121           ],
122         ];
123         break;
124       case [0, 2]:
125         $expected_parent_normalization = [
126           [
127             'target_id' => NULL,
128           ],
129           [
130             'target_id' => 2,
131             'target_type' => 'taxonomy_term',
132             'target_uuid' => Term::load(2)->uuid(),
133             'url' => base_path() . 'taxonomy/term/2',
134           ],
135         ];
136         break;
137       case [3, 2]:
138         $expected_parent_normalization = [
139           [
140             'target_id' => 3,
141             'target_type' => 'taxonomy_term',
142             'target_uuid' => Term::load(3)->uuid(),
143             'url' => base_path() . 'taxonomy/term/3',
144           ],
145           [
146             'target_id' => 2,
147             'target_type' => 'taxonomy_term',
148             'target_uuid' => Term::load(2)->uuid(),
149             'url' => base_path() . 'taxonomy/term/2',
150           ],
151         ];
152         break;
153     }
154
155     return [
156       'tid' => [
157         ['value' => 1],
158       ],
159       'uuid' => [
160         ['value' => $this->entity->uuid()],
161       ],
162       'vid' => [
163         [
164           'target_id' => 'camelids',
165           'target_type' => 'taxonomy_vocabulary',
166           'target_uuid' => Vocabulary::load('camelids')->uuid(),
167         ],
168       ],
169       'name' => [
170         ['value' => 'Llama'],
171       ],
172       'description' => [
173         [
174           'value' => 'It is a little known fact that llamas cannot count higher than seven.',
175           'format' => NULL,
176           'processed' => "<p>It is a little known fact that llamas cannot count higher than seven.</p>\n",
177         ],
178       ],
179       'parent' => $expected_parent_normalization,
180       'weight' => [
181         ['value' => 0],
182       ],
183       'langcode' => [
184         [
185           'value' => 'en',
186         ],
187       ],
188       'changed' => [
189         $this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
190       ],
191       'default_langcode' => [
192         [
193           'value' => TRUE,
194         ],
195       ],
196       'path' => [
197         [
198           'alias' => '/llama',
199           'pid' => 1,
200           'langcode' => 'en',
201         ],
202       ],
203       'status' => [
204         [
205           'value' => TRUE,
206         ],
207       ],
208     ];
209   }
210
211   /**
212    * {@inheritdoc}
213    */
214   protected function getNormalizedPostEntity() {
215     return [
216       'vid' => [
217         [
218           'target_id' => 'camelids',
219         ],
220       ],
221       'name' => [
222         [
223           'value' => 'Dramallama',
224         ],
225       ],
226       'description' => [
227         [
228           'value' => 'Dramallamas are the coolest camelids.',
229           'format' => NULL,
230         ],
231       ],
232     ];
233   }
234
235   /**
236    * {@inheritdoc}
237    */
238   protected function getExpectedUnauthorizedAccessMessage($method) {
239     if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
240       return parent::getExpectedUnauthorizedAccessMessage($method);
241     }
242
243     switch ($method) {
244       case 'GET':
245         return "The 'access content' permission is required and the taxonomy term must be published.";
246       case 'POST':
247         return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
248       case 'PATCH':
249         return "The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.";
250       case 'DELETE':
251         return "The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.";
252       default:
253         return parent::getExpectedUnauthorizedAccessMessage($method);
254     }
255   }
256
257   /**
258    * Tests PATCHing a term's path.
259    *
260    * For a negative test, see the similar test coverage for Node.
261    *
262    * @see \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase::testPatchPath()
263    */
264   public function testPatchPath() {
265     $this->initAuthentication();
266     $this->provisionEntityResource();
267     $this->setUpAuthorization('GET');
268     $this->setUpAuthorization('PATCH');
269
270     $url = $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]);
271
272     // GET term's current normalization.
273     $response = $this->request('GET', $url, $this->getAuthenticationRequestOptions('GET'));
274     $normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
275
276     // Change term's path alias.
277     $normalization['path'][0]['alias'] .= 's-rule-the-world';
278
279     // Create term PATCH request.
280     $request_options = [];
281     $request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
282     $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
283     $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
284
285     // PATCH request: 200.
286     $response = $this->request('PATCH', $url, $request_options);
287     $this->assertResourceResponse(200, FALSE, $response);
288     $updated_normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
289     $this->assertSame($normalization['path'], $updated_normalization['path']);
290   }
291
292   /**
293    * {@inheritdoc}
294    */
295   protected function getExpectedCacheTags() {
296     return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text', 'config:filter.settings']);
297   }
298
299   /**
300    * {@inheritdoc}
301    */
302   protected function getExpectedCacheContexts() {
303     return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
304   }
305
306   /**
307    * Tests GETting a term with a parent term other than the default <root> (0).
308    *
309    * @see ::getExpectedNormalizedEntity()
310    *
311    * @dataProvider providerTestGetTermWithParent
312    */
313   public function testGetTermWithParent(array $parent_term_ids) {
314     // Create all possible parent terms.
315     Term::create(['vid' => Vocabulary::load('camelids')->id()])
316       ->setName('Lamoids')
317       ->save();
318     Term::create(['vid' => Vocabulary::load('camelids')->id()])
319       ->setName('Wimoids')
320       ->save();
321
322     // Modify the entity under test to use the provided parent terms.
323     $this->entity->set('parent', $parent_term_ids)->save();
324
325     $this->initAuthentication();
326     $url = $this->getEntityResourceUrl();
327     $url->setOption('query', ['_format' => static::$format]);
328     $request_options = $this->getAuthenticationRequestOptions('GET');
329     $this->provisionEntityResource();
330     $this->setUpAuthorization('GET');
331     $response = $this->request('GET', $url, $request_options);
332     $expected = $this->getExpectedNormalizedEntity();
333     static::recursiveKSort($expected);
334     $actual = $this->serializer->decode((string) $response->getBody(), static::$format);
335     static::recursiveKSort($actual);
336     $this->assertSame($expected, $actual);
337   }
338
339   public function providerTestGetTermWithParent() {
340     return [
341       'root parent: [0] (= no parent)' => [
342         [0],
343       ],
344       'non-root parent: [2]' => [
345         [2],
346       ],
347       'multiple parents: [0,2] (root + non-root parent)' => [
348         [0, 2],
349       ],
350       'multiple parents: [3,2] (both non-root parents)' => [
351         [3, 2],
352       ],
353     ];
354   }
355
356   /**
357    * {@inheritdoc}
358    */
359   protected function getExpectedUnauthorizedAccessCacheability() {
360     // @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
361     return parent::getExpectedUnauthorizedAccessCacheability()
362       ->addCacheTags(['taxonomy_term:1']);
363   }
364
365 }