Skip to content

Commit

Permalink
Merge 2.11.x into 2.12.x (#9394)
Browse files Browse the repository at this point in the history
* Expose enumType to DBAL to make native DB Enum possible (#9382)

* Accessing private properties and methods from the same class is forbidden (#9311)

Resolves issue doctrine/common#934

Update docs/en/cookbook/accessing-private-properties-of-the-same-class-from-different-instance.rst

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>

Update docs/en/cookbook/accessing-private-properties-of-the-same-class-from-different-instance.rst

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>

Fix review issues

* Update baselines for DBAL 3.3 (#9393)

Co-authored-by: Vadim Borodavko <vadim.borodavko@gmail.com>
Co-authored-by: olsavmic <molsavsky1@gmail.com>
  • Loading branch information
3 people committed Jan 18, 2022
2 parents 07f1c4e + d6fd510 commit 2886d0d
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 5 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"doctrine/annotations": "^1.13",
"doctrine/coding-standard": "^9.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "1.4.0",
"phpstan/phpstan": "1.4.1",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"squizlabs/php_codesniffer": "3.6.2",
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Accessing private/protected properties/methods of the same class from different instance
========================================================================================

.. sectionauthor:: Michael Olsavsky (olsavmic)

As explained in the :doc:`restrictions for entity classes in the manual <../reference/architecture>`,
it is dangerous to access private/protected properties of different entity instance of the same class because of lazy loading.

The proxy instance that's injected instead of the real entity may not be initialized yet
and therefore not contain expected data which may result in unexpected behavior.
That's a limitation of current proxy implementation - only public methods automatically initialize proxies.

It is usually preferable to use a public interface to manipulate the object from outside the `$this`
context but it may not be convenient in some cases. The following example shows how to do it safely.

Safely accessing private properties from different instance of the same class
-----------------------------------------------------------------------------

To safely access private property of different instance of the same class, make sure to initialise
the proxy before use manually as follows:

.. code-block:: php
<?php
use Doctrine\Common\Proxy\Proxy;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Entity
{
// ...
/**
* @ORM\ManyToOne(targetEntity="Entity")
* @ORM\JoinColumn(nullable=false)
*/
private self $parent;
/**
* @ORM\Column(type="string", nullable=false)
*/
private string $name;
// ...
public function doSomethingWithParent()
{
// Always initializing the proxy before use
if ($this->parent instanceof Proxy) {
$this->parent->__load();
}
// Accessing the `$this->parent->name` property without loading the proxy first
// may throw error in case the Proxy has not been initialized yet.
$this->parent->name;
}
public function doSomethingWithAnotherInstance(self $instance)
{
// Always initializing the proxy before use
if ($instance instanceof Proxy) {
$instance->__load();
}
// Accessing the `$instance->name` property without loading the proxy first
// may throw error in case the Proxy has not been initialized yet.
$instance->name;
}
// ...
}
1 change: 1 addition & 0 deletions docs/en/reference/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ be any regular PHP class observing the following restrictions:
- An entity cannot make use of func_get_args() to implement variable parameters.
Generated proxies do not support this for performance reasons and your code might
actually fail to work when violating this restriction.
- Entity cannot access private/protected properties/methods of another entity of the same class or :doc:`do so safely <../cookbook/accessing-private-properties-of-the-same-class-from-different-instance>`.

Entities support inheritance, polymorphic associations, and
polymorphic queries. Both abstract and concrete classes can be
Expand Down
12 changes: 9 additions & 3 deletions lib/Doctrine/ORM/Tools/SchemaTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -781,12 +781,18 @@ private function gatherRelationJoinColumns(
*/
private function gatherColumnOptions(array $mapping): array
{
if (! isset($mapping['options'])) {
$mappingOptions = $mapping['options'] ?? [];

if (isset($mapping['enumType'])) {
$mappingOptions['enumType'] = $mapping['enumType'];
}

if (empty($mappingOptions)) {
return [];
}

$options = array_intersect_key($mapping['options'], array_flip(self::KNOWN_COLUMN_OPTIONS));
$options['customSchemaOptions'] = array_diff_key($mapping['options'], $options);
$options = array_intersect_key($mappingOptions, array_flip(self::KNOWN_COLUMN_OPTIONS));
$options['customSchemaOptions'] = array_diff_key($mappingOptions, $options);

return $options;
}
Expand Down
3 changes: 2 additions & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -703,8 +703,9 @@
<DeprecatedConstant occurrences="1">
<code>self::GENERATOR_TYPE_UUID</code>
</DeprecatedConstant>
<DeprecatedMethod occurrences="1">
<DeprecatedMethod occurrences="2">
<code>canEmulateSchemas</code>
<code>canRequireSQLConversion</code>
</DeprecatedMethod>
<DeprecatedProperty occurrences="4">
<code>$this-&gt;columnNames</code>
Expand Down
19 changes: 19 additions & 0 deletions tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedChildClass;
use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedIdentityClass;
use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedRootClass;
use Doctrine\Tests\Models\Enums\Card;
use Doctrine\Tests\Models\Enums\Suit;
use Doctrine\Tests\Models\Forum\ForumAvatar;
use Doctrine\Tests\Models\Forum\ForumUser;
use Doctrine\Tests\Models\NullDefault\NullDefaultColumn;
Expand Down Expand Up @@ -189,6 +191,23 @@ public function testNullDefaultNotAddedToCustomSchemaOptions(): void
self::assertSame([], $customSchemaOptions);
}

/**
* @requires PHP 8.1
*/
public function testEnumTypeAddedToCustomSchemaOptions(): void
{
$em = $this->getTestEntityManager();
$schemaTool = new SchemaTool($em);

$customSchemaOptions = $schemaTool->getSchemaFromMetadata([$em->getClassMetadata(Card::class)])
->getTable('Card')
->getColumn('suit')
->getCustomSchemaOptions();

self::assertArrayHasKey('enumType', $customSchemaOptions);
self::assertSame(Suit::class, $customSchemaOptions['enumType']);
}

/**
* @group DDC-3671
*/
Expand Down

0 comments on commit 2886d0d

Please sign in to comment.