Skip to content

Commit

Permalink
IBX-7911: Used strict getters for content tree loading code paths (#347)
Browse files Browse the repository at this point in the history
For more details see https://issues.ibexa.co/browse/IBX-7911 and #347

Key changes:

* Introduced dedicated strict getters and deprecated magic ones for Content, ContentInfo, Location, VersionInfo, ContentType\FieldDefinition, User\User, Security\User, and SimplifiedRequest Value Object properties.

* Replaced usages of magic getters with strict ones relevant to the issue

* [Tests] Added coverage for strict getters

* [Tests] Aligned tests with the changes

* [Tests] Introduced symfony/phpunit-bridge deprecations helper

* [Tests] Added coverage for the new deprecation message

* [PHPStan] Aligned baseline with the changes

* [PHPStan] Updated baseline after PHPStan release

---------

Co-authored-by: Paweł Niedzielski <Steveb-p@users.noreply.github.com>
Co-authored-by: Konrad Oboza <konradoboza@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 5, 2024
1 parent 216c669 commit 5848b1e
Show file tree
Hide file tree
Showing 37 changed files with 716 additions and 317 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"ibexa/code-style": "^1.0",
"phpunit/phpunit": "^8.2",
"matthiasnoback/symfony-dependency-injection-test": "^4.1",
"symfony/phpunit-bridge": "^5.1",
"symfony/phpunit-bridge": "^5.4",
"symfony/proxy-manager-bridge": "^5.3",
"symfony/runtime": "^5.3.0",
"phpstan/phpstan": "^1.2",
Expand Down
225 changes: 75 additions & 150 deletions phpstan-baseline.neon

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions phpunit-integration-legacy-solr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<env name="KERNEL_CLASS" value="Ibexa\Contracts\Solr\Test\IbexaSolrTestKernel"/>
<env name="SEARCH_ENGINE" value="solr"/>
<env name="DATABASE_URL" value="sqlite://:memory:" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/>
</php>
<testsuites>
<!-- Search service is used all over the place, so we must run entire integration test suite -->
Expand Down
1 change: 1 addition & 0 deletions phpunit-integration-legacy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<env name="DATABASE_URL" value="sqlite://:memory:" />
<env name="KERNEL_CLASS" value="Ibexa\Contracts\Core\Test\IbexaTestKernel"/>
<env name="SEARCH_ENGINE" value="legacy"/>
<env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/>
</php>
<testsuites>
<testsuite name="integration_core">
Expand Down
5 changes: 4 additions & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
>
<php>
<ini name="error_reporting" value="-1" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/>
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[total]=576&amp;verbose=0"/>
</php>
<testsuites>
<testsuite name="unit_core">
Expand All @@ -33,4 +33,7 @@
<directory>tests/bundle/LegacySearchEngineBundle</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
</listeners>
</phpunit>
14 changes: 12 additions & 2 deletions src/contracts/Repository/Values/Content/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@
/**
* this class represents a content object in a specific version.
*
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo convenience getter for getVersionInfo()->getContentInfo()
* @property-read int $id convenience getter for retrieving the contentId: $versionInfo->contentInfo->id
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Content::getContentInfo()} instead.
* @property-read int $id @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Content::getId()} instead.
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo $versionInfo calls getVersionInfo()
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\Field[] $fields access fields, calls getFields()
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\Thumbnail|null $thumbnail calls getThumbnail()
*/
abstract class Content extends ValueObject
{
public function getId(): int
{
return $this->getContentInfo()->getId();
}

public function getContentInfo(): ContentInfo
{
return $this->getVersionInfo()->getContentInfo();
}

/**
* Returns the VersionInfo for this version.
*
Expand Down
16 changes: 13 additions & 3 deletions src/contracts/Repository/Values/Content/ContentInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
/**
* This class provides all version independent information of the Content object.
*
* @property-read int $id @deprecated Use {@see ContentInfo::getId} instead. The unique id of the Content object
* @property-read int $id @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see ContentInfo::getId()} instead.
* @property-read int $contentTypeId The unique id of the content type item the Content object is an instance of
* @property-read string $name the computed name (via name schema) in the main language of the Content object
* @property-read string $name @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see ContentInfo::getName()} instead.
* @property-read int $sectionId @deprecated 4.6.2 Use {@see ContentInfo::getSectionId} instead. The section to which the Content object is assigned
* @property-read int $currentVersionNo Current Version number is the version number of the published version or the version number of a newly created draft (which is 1).
* @property-read bool $published true if there exists a published version false otherwise
Expand All @@ -29,7 +29,7 @@
* @property-read string $mainLanguageCode The main language code of the Content object. If the available flag is set to true the Content is shown in this language if the requested language does not exist.
* @property-read int|null $mainLocationId @deprecated Use {@see ContentInfo::getMainLocationId} instead
* @property-read int $status status of the Content object
* @property-read bool $isHidden status of the Content object
* @property-read bool $isHidden @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see ContentInfo::isHidden()} instead.
*/
class ContentInfo extends ValueObject
{
Expand Down Expand Up @@ -185,6 +185,11 @@ public function isTrashed(): bool
return $this->status === self::STATUS_TRASHED;
}

public function isHidden(): bool
{
return $this->isHidden;
}

public function getContentType(): ContentType
{
return $this->contentType;
Expand Down Expand Up @@ -229,6 +234,11 @@ public function getId(): int
{
return $this->id;
}

public function getName(): string
{
return $this->name;
}
}

class_alias(ContentInfo::class, 'eZ\Publish\API\Repository\Values\Content\ContentInfo');
89 changes: 81 additions & 8 deletions src/contracts/Repository/Values/Content/Location.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
* This class represents a location in the repository.
*
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo calls getContentInfo()
* @property-read int $contentId calls getContentInfo()->id
* @property-read int $id the id of the location
* @property-read int $contentId @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::getContentId()} instead.
* @property-read int $id @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::getId()} instead.
* @property-read int $priority Position of the Location among its siblings when sorted using priority
* @property-read bool $hidden Indicates that the Location entity is hidden (explicitly or hidden by content).
* @property-read bool $invisible Indicates that the Location is not visible, being either marked as hidden itself, or implicitly hidden by its Content or an ancestor Location
* @property-read bool $hidden @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::isHidden()} instead.
* @property-read bool $invisible @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::isInvisible()} instead.
* @property-read bool $explicitlyHidden Indicates that the Location entity has been explicitly marked as hidden.
* @property-read string $remoteId a global unique id of the content object
* @property-read int $parentLocationId the id of the parent location
* @property-read string $pathString @deprecated use {@see Location::getPathString()} instead.
* @property-read array $path Same as $pathString but as array, e.g. [ 1, 2, 4, 23 ]
* @property-read int $depth Depth location has in the location tree
* @property-read string $pathString @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::getPathString()} instead.
* @property-read array $path @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::getPath()} instead.
* @property-read int $depth @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see Location::getDepth()} instead.
* @property-read int $sortField Specifies which property the child locations should be sorted on. Valid values are found at {@link Location::SORT_FIELD_*}
* @property-read int $sortOrder Specifies whether the sort order should be ascending or descending. Valid values are {@link Location::SORT_ORDER_*}
*/
Expand Down Expand Up @@ -158,6 +158,13 @@ abstract class Location extends ValueObject
*/
protected $pathString;

/**
* Same as {@see Location::$pathString} but as array, e.g.: <code>[ '1', '2', '4', '23' ]</code>.
*
* @var string[]
*/
protected array $path;

/**
* Depth location has in the location tree.
*
Expand Down Expand Up @@ -194,12 +201,22 @@ abstract class Location extends ValueObject
abstract public function getContentInfo(): ContentInfo;

/**
* Return the parent location of of this location.
* Return the parent location of this location.
*
* @return \Ibexa\Contracts\Core\Repository\Values\Content\Location|null
*/
abstract public function getParentLocation(): ?Location;

public function getId(): int
{
return $this->id;
}

public function getContentId(): int
{
return $this->getContentInfo()->getId();
}

/**
* Returns true if current location is a draft.
*
Expand Down Expand Up @@ -248,6 +265,62 @@ public function getPathString(): string
{
return $this->pathString;
}

/**
* Same as {@see Location::getPathString()} but as array, e.g.: <code>[ '1', '2', '4', '23' ]</code>.
*
* @return string[]
*/
public function getPath(): array
{
if (isset($this->path)) {
return $this->path;
}

$pathString = trim($this->pathString ?? '', '/');

return $this->path = !empty($pathString) ? explode('/', $pathString) : [];
}

/**
* Indicates that the Location is not visible, being either marked as hidden itself, or implicitly hidden by
* its Content or an ancestor Location.
*/
public function isInvisible(): bool
{
return $this->invisible;
}

/**
* Indicates that the Location is hidden either explicitly or by content.
*/
public function isHidden(): bool
{
return $this->hidden;
}

public function getDepth(): int
{
return $this->depth;
}

public function __isset($property)
{
if ($property === 'path') {
return true;
}

return parent::__isset($property);
}

public function __get($property)
{
if ($property === 'path') {
return $this->getPath();
}

return parent::__get($property);
}
}

class_alias(Location::class, 'eZ\Publish\API\Repository\Values\Content\Location');
7 changes: 6 additions & 1 deletion src/contracts/Repository/Values/Content/VersionInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*
* @property-read \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo calls getContentInfo()
* @property-read mixed $id the internal id of the version
* @property-read int $versionNo the version number of this version (which only increments in scope of a single Content object)
* @property-read int $versionNo @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see VersionInfo::getVersionNo()} instead.
* @property-read \DateTime $modificationDate the last modified date of this version
* @property-read \DateTime $creationDate the creation date of this version
* @property-read mixed $creatorId the user id of the user which created this version
Expand Down Expand Up @@ -115,6 +115,11 @@ public function getLanguageCodes(): array
return $this->languageCodes;
}

public function getVersionNo(): int
{
return $this->versionNo;
}

/**
* Returns true if version is a draft.
*
Expand Down
7 changes: 6 additions & 1 deletion src/contracts/Repository/Values/ContentType/ContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* @property-read \Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinitionCollection $fieldDefinitions calls getFieldDefinitions() or on access getFieldDefinition($fieldDefIdentifier)
* @property-read mixed $id the id of the content type
* @property-read int $status the status of the content type. One of ContentType::STATUS_DEFINED|ContentType::STATUS_DRAFT|ContentType::STATUS_MODIFIED
* @property-read string $identifier the identifier of the content type
* @property-read string $identifier @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see ContentType::getIdentifier()} instead.
* @property-read \DateTime $creationDate the date of the creation of this content type
* @property-read \DateTime $modificationDate the date of the last modification of this content type
* @property-read mixed $creatorId the user id of the creator of this content type
Expand Down Expand Up @@ -176,6 +176,11 @@ abstract public function getContentTypeGroups();
*/
abstract public function getFieldDefinitions(): FieldDefinitionCollection;

public function getIdentifier(): string
{
return $this->identifier;
}

/**
* This method returns the field definition for the given identifier.
*
Expand Down
91 changes: 77 additions & 14 deletions src/contracts/Repository/Values/ContentType/FieldDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@
/**
* This class represents a field definition.
*
* @property-read array $fieldSettings calls getFieldSettings()
* @property-read array $validatorConfiguration calls getValidatorConfiguration()
* @property-read int $id the id of the field definition
* @property-read string $identifier the identifier of the field definition
* @property-read string $fieldGroup the field group name
* @property-read int $position the position of the field definition in the content type
* @property-read string $fieldTypeIdentifier String identifier of the field type
* @property-read bool $isTranslatable indicates if fields of this definition are translatable
* @property-read bool $isRequired indicates if this field is required in the content object
* @property-read bool $isSearchable indicates if the field is searchable
* @property-read bool $isThumbnail indicates if the field can be thumbnail
* @property-read bool $isInfoCollector indicates if this field is used for information collection
* @property-read mixed $defaultValue the default value of the field
* @property-read string $mainLanguageCode main Translation (language code) of a multilingual Field Definition
* @property-read array $fieldSettings @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getFieldSettings()} instead.
* @property-read array $validatorConfiguration @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getValidatorConfiguration()} instead.
* @property-read int $id @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getId()} instead.
* @property-read string $identifier @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getIdentifier()} instead.
* @property-read string $fieldGroup @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getFieldGroup()} instead.
* @property-read int $position @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getPosition()} instead.
* @property-read string $fieldTypeIdentifier @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getFieldTypeIdentifier()} instead.
* @property-read bool $isTranslatable @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::$isTranslatable()} instead.
* @property-read bool $isRequired @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::$isRequired()} instead.
* @property-read bool $isSearchable @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getIdentifier()} instead.
* @property-read bool $isThumbnail @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::isThumbnail()} instead.
* @property-read bool $isInfoCollector @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::$isInfoCollector()} instead.
* @property-read mixed $defaultValue @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getDefaultValue()} instead.
* @property-read string $mainLanguageCode @deprecated 4.6.7 accessing magic getter is deprecated and will be removed in 5.0.0. Use {@see FieldDefinition::getMainLanguageCode()} instead.
*/
abstract class FieldDefinition extends ValueObject implements MultiLanguageName, MultiLanguageDescription
{
Expand Down Expand Up @@ -129,6 +129,69 @@ abstract public function getFieldSettings(): array;
* @var string
*/
protected $mainLanguageCode;

public function getId(): int
{
return $this->id;
}

public function getFieldGroup(): string
{
return $this->fieldGroup;
}

public function getPosition(): int
{
return $this->position;
}

public function isTranslatable(): bool
{
return $this->isTranslatable;
}

public function isRequired(): bool
{
return $this->isRequired;
}

public function isInfoCollector(): bool
{
return $this->isInfoCollector;
}

/**
* @return mixed
*/
public function getDefaultValue()
{
return $this->defaultValue;
}

public function isSearchable(): bool
{
return $this->isSearchable;
}

public function getMainLanguageCode(): string
{
return $this->mainLanguageCode;
}

public function isThumbnail(): bool
{
return $this->isThumbnail;
}

public function getIdentifier(): string
{
return $this->identifier;
}

public function getFieldTypeIdentifier(): string
{
return $this->fieldTypeIdentifier;
}
}

class_alias(FieldDefinition::class, 'eZ\Publish\API\Repository\Values\ContentType\FieldDefinition');
Loading

0 comments on commit 5848b1e

Please sign in to comment.