Completed
Push — master ( da8bd4...675284 )
by André
60:46 queued 35:33
created

SearchEngineIndexingTest::testDeleteUserGroup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 12

Duplication

Lines 19
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 12
c 1
b 0
f 1
nc 1
nop 0
dl 19
loc 19
rs 9.4285
1
<?php
2
3
/**
4
 * This file is part of the eZ Publish Kernel package.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 *
9
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\API\Repository\Tests;
12
13
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
14
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
15
use eZ\Publish\API\Repository\Values\Content\Query;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
17
use DateTime;
18
19
/**
20
 * Test case for indexing operations with a search engine.
21
 *
22
 * @group integration
23
 * @group search
24
 * @group indexing
25
 */
26
class SearchEngineIndexingTest extends BaseTest
27
{
28
    /**
29
     * EZP-26186: Make sure index is NOT deleted on removal of version draft (affected Solr & content index on Elastic).
30
     */
31
    public function testDeleteVersion()
32
    {
33
        $repository = $this->getRepository();
34
        $contentService = $repository->getContentService();
35
        $searchService = $repository->getSearchService();
36
37
        $membersContentId = $this->generateId('content', 11);
38
        $contentInfo = $contentService->loadContentInfo($membersContentId);
39
40
        $draft = $contentService->createContentDraft($contentInfo);
41
        $contentService->deleteVersion($draft->getVersionInfo());
42
43
        $this->refreshSearch($repository);
44
45
        // Found
46
        $criterion = new Criterion\LocationId($contentInfo->mainLocationId);
47
        $query = new Query(array('filter' => $criterion));
48
        $result = $searchService->findContentInfo($query);
49
        $this->assertEquals(1, $result->totalCount);
50
        $this->assertEquals(
51
            $contentInfo->id,
52
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
53
        );
54
    }
55
56
    /**
57
     * EZP-26186: Make sure affected child locations are deleted on content deletion (affected Solr & Elastic).
58
     */
59 View Code Duplication
    public function testDeleteContent()
60
    {
61
        $repository = $this->getRepository();
62
        $contentService = $repository->getContentService();
63
        $searchService = $repository->getSearchService();
64
65
        $anonymousUsersContentId = $this->generateId('content', 42);
66
        $contentInfo = $contentService->loadContentInfo($anonymousUsersContentId);
67
68
        $contentService->deleteContent($contentInfo);
69
70
        $this->refreshSearch($repository);
71
72
        // Should not be found
73
        $criterion = new Criterion\ParentLocationId($contentInfo->mainLocationId);
74
        $query = new LocationQuery(array('filter' => $criterion));
75
        $result = $searchService->findLocations($query);
76
        $this->assertEquals(0, $result->totalCount);
77
    }
78
79
    /**
80
     * EZP-26186: Make sure index is deleted on removal of Users  (affected Solr & Elastic).
81
     */
82 View Code Duplication
    public function testDeleteUser()
83
    {
84
        $repository = $this->getRepository();
85
        $userService = $repository->getUserService();
86
        $searchService = $repository->getSearchService();
87
88
        $anonymousContentId = $this->generateId('user', 10);
89
        $user = $userService->loadUser($anonymousContentId);
90
91
        $userService->deleteUser($user);
92
93
        $this->refreshSearch($repository);
94
95
        // Should not be found
96
        $criterion = new Criterion\ContentId($user->id);
97
        $query = new Query(array('filter' => $criterion));
98
        $result = $searchService->findContentInfo($query);
99
        $this->assertEquals(0, $result->totalCount);
100
    }
101
102
    /**
103
     * EZP-26186: Make sure index is deleted on removal of UserGroups  (affected Solr & Elastic).
104
     */
105 View Code Duplication
    public function testDeleteUserGroup()
106
    {
107
        $repository = $this->getRepository();
108
        $userService = $repository->getUserService();
109
        $searchService = $repository->getSearchService();
110
111
        $membersContentId = $this->generateId('user_group', 11);
112
        $userGroup = $userService->loadUserGroup($membersContentId);
113
114
        $userService->deleteUserGroup($userGroup);
115
116
        $this->refreshSearch($repository);
117
118
        // Should not be found
119
        $criterion = new Criterion\ContentId($userGroup->id);
120
        $query = new Query(array('filter' => $criterion));
121
        $result = $searchService->findContentInfo($query);
122
        $this->assertEquals(0, $result->totalCount);
123
    }
124
125
    public function testCreateLocation()
126
    {
127
        $repository = $this->getRepository();
128
        $locationService = $repository->getLocationService();
129
        $contentService = $repository->getContentService();
130
        $searchService = $repository->getSearchService();
131
132
        $rootLocationId = 2;
133
        $membersContentId = 11;
134
        $membersContentInfo = $contentService->loadContentInfo($membersContentId);
135
136
        $locationCreateStruct = $locationService->newLocationCreateStruct($rootLocationId);
137
        $membersLocation = $locationService->createLocation($membersContentInfo, $locationCreateStruct);
138
139
        $this->refreshSearch($repository);
140
141
        // Found
142
        $criterion = new Criterion\LocationId($membersLocation->id);
143
        $query = new LocationQuery(array('filter' => $criterion));
144
        $result = $searchService->findLocations($query);
145
        $this->assertEquals(1, $result->totalCount);
146
        $this->assertEquals(
147
            $membersLocation->id,
148
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
149
        );
150
    }
151
152
    public function testMoveSubtree()
153
    {
154
        $repository = $this->getRepository();
155
        $locationService = $repository->getLocationService();
156
        $contentService = $repository->getContentService();
157
        $searchService = $repository->getSearchService();
158
159
        $rootLocationId = 2;
160
        $membersContentId = 11;
161
        $adminsContentId = 12;
162
        $editorsContentId = 13;
163
        $membersContentInfo = $contentService->loadContentInfo($membersContentId);
164
        $adminsContentInfo = $contentService->loadContentInfo($adminsContentId);
165
        $editorsContentInfo = $contentService->loadContentInfo($editorsContentId);
166
167
        $locationCreateStruct = $locationService->newLocationCreateStruct($rootLocationId);
168
        $membersLocation = $locationService->createLocation($membersContentInfo, $locationCreateStruct);
169
        $editorsLocation = $locationService->createLocation($editorsContentInfo, $locationCreateStruct);
170
        $adminsLocation = $locationService->createLocation(
171
            $adminsContentInfo,
172
            $locationService->newLocationCreateStruct($membersLocation->id)
173
        );
174
175
        $this->refreshSearch($repository);
176
177
        // Not found under Editors
178
        $criterion = new Criterion\ParentLocationId($editorsLocation->id);
179
        $query = new LocationQuery(array('filter' => $criterion));
180
        $result = $searchService->findLocations($query);
181
        $this->assertEquals(0, $result->totalCount);
182
183
        // Found under Members
184
        $criterion = new Criterion\ParentLocationId($membersLocation->id);
185
        $query = new LocationQuery(array('filter' => $criterion));
186
        $result = $searchService->findLocations($query);
187
        $this->assertEquals(1, $result->totalCount);
188
        $this->assertEquals(
189
            $adminsLocation->id,
190
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
191
        );
192
193
        $locationService->moveSubtree($adminsLocation, $editorsLocation);
194
        $this->refreshSearch($repository);
195
196
        // Found under Editors
197
        $criterion = new Criterion\ParentLocationId($editorsLocation->id);
198
        $query = new LocationQuery(array('filter' => $criterion));
199
        $result = $searchService->findLocations($query);
200
        $this->assertEquals(1, $result->totalCount);
201
        $this->assertEquals(
202
            $adminsLocation->id,
203
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
204
        );
205
206
        // Not found under Members
207
        $criterion = new Criterion\ParentLocationId($membersLocation->id);
208
        $query = new LocationQuery(array('filter' => $criterion));
209
        $result = $searchService->findLocations($query);
210
        $this->assertEquals(0, $result->totalCount);
211
    }
212
213
    /**
214
     * Testing that content is indexed even when containing only fields with values
215
     * considered to be empty by the search engine.
216
     */
217
    public function testIndexContentWithNullField()
218
    {
219
        $repository = $this->getRepository();
220
        $contentService = $repository->getContentService();
221
        $contentTypeService = $repository->getContentTypeService();
222
        $searchService = $repository->getSearchService();
223
224
        $createStruct = $contentTypeService->newContentTypeCreateStruct('test-type');
225
        $createStruct->mainLanguageCode = 'eng-GB';
226
        $createStruct->names = array('eng-GB' => 'Test type');
227
        $createStruct->creatorId = 14;
228
        $createStruct->creationDate = new DateTime();
229
230
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct(
231
            'integer',
232
            'ezinteger'
233
        );
234
        $translatableFieldCreate->names = array('eng-GB' => 'Simple translatable integer field');
235
        $translatableFieldCreate->fieldGroup = 'main';
236
        $translatableFieldCreate->position = 1;
237
        $translatableFieldCreate->isTranslatable = true;
238
        $translatableFieldCreate->isSearchable = true;
239
240
        $createStruct->addFieldDefinition($translatableFieldCreate);
241
242
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
243
        $contentTypeDraft = $contentTypeService->createContentType(
244
            $createStruct,
245
            array($contentGroup)
246
        );
247
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
248
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repositor...ContentType\ContentType. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
249
250
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
251
        $createStruct->alwaysAvailable = false;
252
        $createStruct->mainLanguageCode = 'eng-GB';
253
254
        $draft = $contentService->createContent($createStruct);
255
        $content = $contentService->publishVersion($draft->getVersionInfo());
256
257
        $this->refreshSearch($repository);
258
259
        // Found
260
        $criterion = new Criterion\ContentId($content->id);
261
        $query = new Query(array('filter' => $criterion));
262
        $result = $searchService->findContent($query);
263
        $this->assertEquals(1, $result->totalCount);
264
        $this->assertEquals(
265
            $content->id,
266
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
267
        );
268
    }
269
270
    public function testUpdateLocation()
271
    {
272
        $repository = $this->getRepository();
273
        $locationService = $repository->getLocationService();
274
        $searchService = $repository->getSearchService();
275
276
        $rootLocationId = 2;
277
        $locationToUpdate = $locationService->loadLocation($rootLocationId);
278
279
        $criterion = new Criterion\LogicalAnd([
280
            new Criterion\LocationId($rootLocationId),
281
            new Criterion\Location\Priority(Criterion\Operator::GT, 0),
282
        ]);
283
284
        $query = new LocationQuery(array('filter' => $criterion));
285
        $result = $searchService->findLocations($query);
286
287
        $this->assertEquals(0, $result->totalCount);
288
289
        $locationUpdateStruct = $locationService->newLocationUpdateStruct();
290
        $locationUpdateStruct->priority = 4;
291
        $locationService->updateLocation($locationToUpdate, $locationUpdateStruct);
292
293
        $this->refreshSearch($repository);
294
295
        $result = $searchService->findLocations($query);
296
297
        $this->assertEquals(1, $result->totalCount);
298
        $this->assertEquals(
299
            $locationToUpdate->id,
300
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
301
        );
302
    }
303
304
    /**
305
     * Testing that content will be deleted with all of its subitems but subitems with additional location will stay as
306
     * they are.
307
     */
308
    public function testDeleteLocation()
309
    {
310
        $repository = $this->getRepository();
311
        $locationService = $repository->getLocationService();
312
313
        $treeContainerContent = $this->createContentWithName('Tree Container', [2]);
314
        $supposeBeDeletedSubItem = $this->createContentWithName(
315
            'Suppose to be deleted sub-item',
316
            [$treeContainerContent->contentInfo->mainLocationId]
317
        );
318
        $supposeSurviveSubItem = $this->createContentWithName(
319
            'Suppose to Survive Item',
320
            [2, $treeContainerContent->contentInfo->mainLocationId]
321
        );
322
323
        $treeContainerLocation = $locationService->loadLocation($treeContainerContent->contentInfo->mainLocationId);
324
325
        $this->refreshSearch($repository);
326
327
        $this->assertContentIdSearch($treeContainerContent->id, 1);
328
        $this->assertContentIdSearch($supposeSurviveSubItem->id, 1);
329
        $this->assertContentIdSearch($supposeBeDeletedSubItem->id, 1);
330
331
        $locationService->deleteLocation($treeContainerLocation);
332
333
        $this->refreshSearch($repository);
334
335
        $this->assertContentIdSearch($supposeSurviveSubItem->id, 1);
336
        $this->assertContentIdSearch($treeContainerContent->id, 0);
337
        $this->assertContentIdSearch($supposeBeDeletedSubItem->id, 0);
338
    }
339
340
    /**
341
     * Will create if not exists an simple content type for deletion test purpose with just and required field name.
342
     *
343
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
344
     */
345
    protected function createDeletionTestContentType()
346
    {
347
        $repository = $this->getRepository();
348
        $contentTypeService = $repository->getContentTypeService();
349
        try {
350
            return $contentTypeService->loadContentTypeByIdentifier('deletion-test');
351
        } catch (NotFoundException $e) {
352
            // continue creation process
353
        }
354
355
        $nameField = $contentTypeService->newFieldDefinitionCreateStruct('name', 'ezstring');
356
        $nameField->fieldGroup = 'main';
357
        $nameField->position = 1;
358
        $nameField->isTranslatable = true;
359
        $nameField->isSearchable = true;
360
        $nameField->isRequired = true;
361
362
        $contentTypeStruct = $contentTypeService->newContentTypeCreateStruct('deletion-test');
363
        $contentTypeStruct->mainLanguageCode = 'eng-GB';
364
        $contentTypeStruct->creatorId = 14;
365
        $contentTypeStruct->creationDate = new DateTime();
366
        $contentTypeStruct->names = ['eng-GB' => 'Deletion test'];
367
        $contentTypeStruct->addFieldDefinition($nameField);
368
369
        $contentTypeGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
370
371
        $contentTypeDraft = $contentTypeService->createContentType($contentTypeStruct, [$contentTypeGroup]);
372
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
373
374
        return $contentTypeService->loadContentTypeByIdentifier('deletion-test');
375
    }
376
377
    /**
378
     * Will create and publish an content with a filed with a given content name in location provided into
379
     * $parentLocationIdList.
380
     *
381
     * @param string $contentName
382
     * @param array $parentLocationIdList
383
     *
384
     * @return \eZ\Publish\API\Repository\Values\Content\Content
385
     */
386
    protected function createContentWithName($contentName, array $parentLocationIdList = array())
387
    {
388
        $contentService = $this->getRepository()->getContentService();
389
        $locationService = $this->getRepository()->getLocationService();
390
391
        $testableContentType = $this->createDeletionTestContentType();
392
393
        $rootContentStruct = $contentService->newContentCreateStruct($testableContentType, 'eng-GB');
394
        $rootContentStruct->setField('name', $contentName);
395
396
        $parentLocationList = [];
397
        foreach ($parentLocationIdList as $locationID) {
398
            $parentLocationList[] = $locationService->newLocationCreateStruct($locationID);
399
        }
400
401
        $contentDraft = $contentService->createContent($rootContentStruct, $parentLocationList);
402
        $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo());
403
404
        return $publishedContent;
405
    }
406
407
    /**
408
     * Asserts an content id if it exists still in the solr core.
409
     *
410
     * @param int $contentId
411
     * @param int $expectedCount
412
     */
413
    protected function assertContentIdSearch($contentId, $expectedCount)
414
    {
415
        $searchService = $this->getRepository()->getSearchService();
416
417
        $criterion = new Criterion\ContentId($contentId);
418
        $query = new Query(array('filter' => $criterion));
419
        $result = $searchService->findContent($query);
420
421
        $this->assertEquals($expectedCount, $result->totalCount);
422
        if ($expectedCount == 0) {
423
            return;
424
        }
425
426
        $this->assertEquals(
427
            $contentId,
428
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
429
        );
430
    }
431
}
432