Skip to content

Commit

Permalink
Document stdClass structures used by CommitOrderCalculator (#10315)
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus authored Dec 19, 2022
1 parent 8093c2e commit 82a4063
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 57 deletions.
10 changes: 10 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Upgrade to 2.14

## Deprecated constants of `Doctrine\ORM\Internal\CommitOrderCalculator`

The following public constants have been deprecated:

* `CommitOrderCalculator::NOT_VISITED`
* `CommitOrderCalculator::IN_PROGRESS`
* `CommitOrderCalculator::VISITED`

These constants were used for internal purposes. Relying on them is discouraged.

## Deprecated `Doctrine\ORM\Query\AST\InExpression`

The AST parser will create a `InListExpression` or a `InSubselectExpression` when
Expand Down
34 changes: 34 additions & 0 deletions lib/Doctrine/ORM/Internal/CommitOrder/Edge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Internal\CommitOrder;

/** @internal */
final class Edge
{
/**
* @var string
* @readonly
*/
public $from;

/**
* @var string
* @readonly
*/
public $to;

/**
* @var int
* @readonly
*/
public $weight;

public function __construct(string $from, string $to, int $weight)
{
$this->from = $from;
$this->to = $to;
$this->weight = $weight;
}
}
38 changes: 38 additions & 0 deletions lib/Doctrine/ORM/Internal/CommitOrder/Vertex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Internal\CommitOrder;

use Doctrine\ORM\Mapping\ClassMetadata;

/** @internal */
final class Vertex
{
/**
* @var string
* @readonly
*/
public $hash;

/**
* @var int
* @psalm-var VertexState::*
*/
public $state = VertexState::NOT_VISITED;

/**
* @var ClassMetadata
* @readonly
*/
public $value;

/** @var array<string, Edge> */
public $dependencyList = [];

public function __construct(string $hash, ClassMetadata $value)
{
$this->hash = $hash;
$this->value = $value;
}
}
17 changes: 17 additions & 0 deletions lib/Doctrine/ORM/Internal/CommitOrder/VertexState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Internal\CommitOrder;

/** @internal */
final class VertexState
{
public const NOT_VISITED = 0;
public const IN_PROGRESS = 1;
public const VISITED = 2;

private function __construct()
{
}
}
77 changes: 31 additions & 46 deletions lib/Doctrine/ORM/Internal/CommitOrderCalculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

namespace Doctrine\ORM\Internal;

use stdClass;
use Doctrine\ORM\Internal\CommitOrder\Edge;
use Doctrine\ORM\Internal\CommitOrder\Vertex;
use Doctrine\ORM\Internal\CommitOrder\VertexState;
use Doctrine\ORM\Mapping\ClassMetadata;

use function array_reverse;

Expand All @@ -17,33 +20,28 @@
*/
class CommitOrderCalculator
{
public const NOT_VISITED = 0;
public const IN_PROGRESS = 1;
public const VISITED = 2;
/** @deprecated */
public const NOT_VISITED = VertexState::NOT_VISITED;

/** @deprecated */
public const IN_PROGRESS = VertexState::IN_PROGRESS;

/** @deprecated */
public const VISITED = VertexState::VISITED;

/**
* Matrix of nodes (aka. vertex).
* Keys are provided hashes and values are the node definition objects.
*
* The node state definition contains the following properties:
*
* - <b>state</b> (integer)
* Whether the node is NOT_VISITED or IN_PROGRESS
*
* - <b>value</b> (object)
* Actual node value
*
* - <b>dependencyList</b> (array<string>)
* Map of node dependencies defined as hashes.
* Keys are provided hashes and values are the node definition objects.
*
* @var array<stdClass>
* @var array<string, Vertex>
*/
private $nodeList = [];

/**
* Volatile variable holding calculated nodes during sorting process.
*
* @psalm-var list<object>
* @psalm-var list<ClassMetadata>
*/
private $sortedNodeList = [];

Expand All @@ -62,21 +60,14 @@ public function hasNode($hash)
/**
* Adds a new node (vertex) to the graph, assigning its hash and value.
*
* @param string $hash
* @param object $node
* @param string $hash
* @param ClassMetadata $node
*
* @return void
*/
public function addNode($hash, $node)
{
$vertex = new stdClass();

$vertex->hash = $hash;
$vertex->state = self::NOT_VISITED;
$vertex->value = $node;
$vertex->dependencyList = [];

$this->nodeList[$hash] = $vertex;
$this->nodeList[$hash] = new Vertex($hash, $node);
}

/**
Expand All @@ -90,14 +81,8 @@ public function addNode($hash, $node)
*/
public function addDependency($fromHash, $toHash, $weight)
{
$vertex = $this->nodeList[$fromHash];
$edge = new stdClass();

$edge->from = $fromHash;
$edge->to = $toHash;
$edge->weight = $weight;

$vertex->dependencyList[$toHash] = $edge;
$this->nodeList[$fromHash]->dependencyList[$toHash]
= new Edge($fromHash, $toHash, $weight);
}

/**
Expand All @@ -106,12 +91,12 @@ public function addDependency($fromHash, $toHash, $weight)
*
* {@internal Highly performance-sensitive method.}
*
* @psalm-return list<object>
* @psalm-return list<ClassMetadata>
*/
public function sort()
{
foreach ($this->nodeList as $vertex) {
if ($vertex->state !== self::NOT_VISITED) {
if ($vertex->state !== VertexState::NOT_VISITED) {
continue;
}

Expand All @@ -131,19 +116,19 @@ public function sort()
*
* {@internal Highly performance-sensitive method.}
*/
private function visit(stdClass $vertex): void
private function visit(Vertex $vertex): void
{
$vertex->state = self::IN_PROGRESS;
$vertex->state = VertexState::IN_PROGRESS;

foreach ($vertex->dependencyList as $edge) {
$adjacentVertex = $this->nodeList[$edge->to];

switch ($adjacentVertex->state) {
case self::VISITED:
case VertexState::VISITED:
// Do nothing, since node was already visited
break;

case self::IN_PROGRESS:
case VertexState::IN_PROGRESS:
if (
isset($adjacentVertex->dependencyList[$vertex->hash]) &&
$adjacentVertex->dependencyList[$vertex->hash]->weight < $edge->weight
Expand All @@ -153,25 +138,25 @@ private function visit(stdClass $vertex): void
foreach ($adjacentVertex->dependencyList as $adjacentEdge) {
$adjacentEdgeVertex = $this->nodeList[$adjacentEdge->to];

if ($adjacentEdgeVertex->state === self::NOT_VISITED) {
if ($adjacentEdgeVertex->state === VertexState::NOT_VISITED) {
$this->visit($adjacentEdgeVertex);
}
}

$adjacentVertex->state = self::VISITED;
$adjacentVertex->state = VertexState::VISITED;

$this->sortedNodeList[] = $adjacentVertex->value;
}

break;

case self::NOT_VISITED:
case VertexState::NOT_VISITED:
$this->visit($adjacentVertex);
}
}

if ($vertex->state !== self::VISITED) {
$vertex->state = self::VISITED;
if ($vertex->state !== VertexState::VISITED) {
$vertex->state = VertexState::VISITED;

$this->sortedNodeList[] = $vertex->value;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/UnitOfWork.php
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ private function executeDeletions(ClassMetadata $class): void
/**
* Gets the commit order.
*
* @return list<object>
* @return list<ClassMetadata>
*/
private function getCommitOrder(): array
{
Expand Down
12 changes: 2 additions & 10 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,9 @@
</UndefinedMethod>
</file>
<file src="lib/Doctrine/ORM/Internal/CommitOrderCalculator.php">
<InvalidPropertyAssignmentValue occurrences="2">
<code>$this-&gt;sortedNodeList</code>
<code>$this-&gt;sortedNodeList</code>
</InvalidPropertyAssignmentValue>
<RedundantCondition occurrences="2">
<code>$vertex-&gt;state !== self::VISITED</code>
<code>$vertex-&gt;state !== self::VISITED</code>
<code>$vertex-&gt;state !== VertexState::VISITED</code>
<code>$vertex-&gt;state !== VertexState::VISITED</code>
</RedundantCondition>
</file>
<file src="lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php">
Expand Down Expand Up @@ -2895,10 +2891,6 @@
</UnresolvableInclude>
</file>
<file src="lib/Doctrine/ORM/UnitOfWork.php">
<ArgumentTypeCoercion occurrences="2">
<code>$class</code>
<code>$class</code>
</ArgumentTypeCoercion>
<DocblockTypeContradiction occurrences="2">
<code>! is_object($object)</code>
<code>is_object($object)</code>
Expand Down

0 comments on commit 82a4063

Please sign in to comment.