Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
2807a83d
Commit
2807a83d
authored
Jul 27, 2009
by
romanb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[2.0] Started to simplify commit order calculation.
parent
56a70884
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
80 additions
and
242 deletions
+80
-242
CommitOrderCalculator.php
lib/Doctrine/ORM/Internal/CommitOrderCalculator.php
+48
-61
CommitOrderNode.php
lib/Doctrine/ORM/Internal/CommitOrderNode.php
+0
-144
UnitOfWork.php
lib/Doctrine/ORM/UnitOfWork.php
+8
-17
CommitOrderCalculatorTest.php
tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php
+24
-20
No files found.
lib/Doctrine/ORM/Internal/CommitOrderCalculator.php
View file @
2807a83d
...
...
@@ -30,107 +30,94 @@ namespace Doctrine\ORM\Internal;
*/
class
CommitOrderCalculator
{
private
$_currentTime
;
const
NOT_VISITED
=
1
;
const
IN_PROGRESS
=
2
;
const
VISITED
=
3
;
/**
* The node list used for sorting.
*
* @var array
*/
private
$_nodes
=
array
();
private
$_nodeStates
=
array
();
private
$_classes
=
array
();
// The nodes to sort
private
$_relatedClasses
=
array
();
private
$_sorted
=
array
();
/**
* The topologically sorted list of items. Note that these are not nodes
* but the wrapped items.
* Clears the current graph and the last result.
*
* @
var array
* @
return void
*/
private
$_sorted
;
public
function
clear
()
{
$this
->
_nodes
=
array
();
$this
->
_sorted
=
array
();
}
/**
*
Orders the given list of CommitOrderNodes based on their dependenci
es.
*
Gets a valid commit order for all current nod
es.
*
* Uses a depth-first search (DFS) to traverse the graph.
* The desired topological sorting is the reverse postorder of these searches.
*
* @param array $nodes The list of (unordered) CommitOrderNodes.
* @return array The list of ordered items. These are the items wrapped in the nodes.
*/
public
function
getCommitOrder
()
{
// Check whether we need to do anything. 0 or 1 node is easy.
$nodeCount
=
count
(
$this
->
_
nod
es
);
$nodeCount
=
count
(
$this
->
_
class
es
);
if
(
$nodeCount
==
0
)
{
return
array
();
}
else
if
(
$nodeCount
==
1
)
{
$node
=
array_pop
(
$this
->
_nodes
);
return
array
(
$node
->
getClass
());
return
$this
->
_classes
;
}
$this
->
_sorted
=
array
();
// Init
foreach
(
$this
->
_nodes
as
$node
)
{
$node
->
markNotVisited
();
$node
->
setPredecessor
(
null
);
$this
->
_sorted
=
array
();
$this
->
_nodeStates
=
array
();
foreach
(
$this
->
_classes
as
$node
)
{
$this
->
_nodeStates
[
$node
->
name
]
=
self
::
NOT_VISITED
;
}
$this
->
_currentTime
=
0
;
// Go
foreach
(
$this
->
_
nod
es
as
$node
)
{
if
(
$
node
->
isNotVisited
()
)
{
$
node
->
visit
(
);
foreach
(
$this
->
_
class
es
as
$node
)
{
if
(
$
this
->
_nodeStates
[
$node
->
name
]
==
self
::
NOT_VISITED
)
{
$
this
->
_visitNode
(
$node
);
}
}
return
$this
->
_sorted
;
return
array_reverse
(
$this
->
_sorted
)
;
}
/**
* Adds a node to consider when ordering.
*
* @param mixed $key Somme arbitrary key for the node (must be unique!).
* @param unknown_type $node
*/
public
function
addNode
(
$key
,
$node
)
private
function
_visitNode
(
$node
)
{
$this
->
_nodes
[
$key
]
=
$node
;
}
public
function
addNodeWithItem
(
$key
,
$item
)
{
$this
->
_nodes
[
$key
]
=
new
CommitOrderNode
(
$item
,
$this
);
}
$this
->
_nodeStates
[
$node
->
name
]
=
self
::
IN_PROGRESS
;
if
(
isset
(
$this
->
_relatedClasses
[
$node
->
name
]))
{
foreach
(
$this
->
_relatedClasses
[
$node
->
name
]
as
$relatedNode
)
{
if
(
$this
->
_nodeStates
[
$relatedNode
->
name
]
==
self
::
NOT_VISITED
)
{
$this
->
_visitNode
(
$relatedNode
);
}
if
(
$this
->
_nodeStates
[
$relatedNode
->
name
]
==
self
::
IN_PROGRESS
)
{
// back edge => cycle
//TODO: anything to do here?
}
}
}
$this
->
_nodeStates
[
$node
->
name
]
=
self
::
VISITED
;
public
function
getNodeForKey
(
$key
)
{
return
$this
->
_nodes
[
$key
];
}
public
function
hasNodeWithKey
(
$key
)
{
return
isset
(
$this
->
_nodes
[
$key
]);
$this
->
_sorted
[]
=
$node
;
}
/**
* Clears the current graph and the last result.
*
* @return void
*/
public
function
clear
()
public
function
addDependency
(
$fromClass
,
$toClass
)
{
$this
->
_nodes
=
array
();
$this
->
_sorted
=
array
();
$this
->
_relatedClasses
[
$fromClass
->
name
][]
=
$toClass
;
}
public
function
getNextTime
(
)
public
function
hasClass
(
$className
)
{
return
++
$this
->
_currentTime
;
return
isset
(
$this
->
_classes
[
$className
])
;
}
public
function
prependNode
(
$node
)
public
function
addClass
(
$class
)
{
array_unshift
(
$this
->
_sorted
,
$node
->
getClass
())
;
$this
->
_classes
[
$class
->
name
]
=
$class
;
}
}
\ No newline at end of file
lib/Doctrine/ORM/Internal/CommitOrderNode.php
deleted
100644 → 0
View file @
56a70884
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace
Doctrine\ORM\Internal
;
/**
* A CommitOrderNode is a temporary wrapper around ClassMetadata instances
* that is used to sort the order of commits in a UnitOfWork.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class
CommitOrderNode
{
const
NOT_VISITED
=
1
;
const
IN_PROGRESS
=
2
;
const
VISITED
=
3
;
private
$_traversalState
;
private
$_predecessor
;
private
$_status
;
private
$_calculator
;
private
$_relatedNodes
=
array
();
/* The "time" when this node was first discovered during traversal */
public
$discoveryTime
;
/* The "time" when this node was finished during traversal */
public
$finishingTime
;
/* The wrapped object */
private
$_wrappedObj
;
/**
* Constructor.
* Creates a new node.
*
* @param mixed $wrappedObj The object to wrap.
* @param Doctrine\ORM\Internal\CommitOrderCalculator $calc The calculator.
*/
public
function
__construct
(
$wrappedObj
,
CommitOrderCalculator
$calc
)
{
$this
->
_wrappedObj
=
$wrappedObj
;
$this
->
_calculator
=
$calc
;
}
/**
* Gets the wrapped object.
*
* @return mixed
*/
public
function
getClass
()
{
return
$this
->
_wrappedObj
;
}
public
function
setPredecessor
(
$node
)
{
$this
->
_predecessor
=
$node
;
}
public
function
getPredecessor
()
{
return
$this
->
_predecessor
;
}
public
function
markNotVisited
()
{
$this
->
_traversalState
=
self
::
NOT_VISITED
;
}
public
function
markInProgress
()
{
$this
->
_traversalState
=
self
::
IN_PROGRESS
;
}
public
function
markVisited
()
{
$this
->
_traversalState
=
self
::
VISITED
;
}
public
function
isNotVisited
()
{
return
$this
->
_traversalState
==
self
::
NOT_VISITED
;
}
public
function
isInProgress
()
{
return
$this
->
_traversalState
==
self
::
IN_PROGRESS
;
}
public
function
visit
()
{
$this
->
markInProgress
();
$this
->
discoveryTime
=
$this
->
_calculator
->
getNextTime
();
foreach
(
$this
->
getRelatedNodes
()
as
$node
)
{
if
(
$node
->
isNotVisited
())
{
$node
->
setPredecessor
(
$this
);
$node
->
visit
();
}
if
(
$node
->
isInProgress
())
{
// back edge => cycle
//TODO: anything to do here?
}
}
$this
->
markVisited
();
$this
->
_calculator
->
prependNode
(
$this
);
$this
->
finishingTime
=
$this
->
_calculator
->
getNextTime
();
}
public
function
getRelatedNodes
()
{
return
$this
->
_relatedNodes
;
}
/**
* Adds a directed dependency (an edge on the graph). "$this -before-> $other".
*
* @param Doctrine\ORM\Internal\CommitOrderNode $node
*/
public
function
before
(
CommitOrderNode
$node
)
{
$this
->
_relatedNodes
[]
=
$node
;
}
}
\ No newline at end of file
lib/Doctrine/ORM/UnitOfWork.php
View file @
2807a83d
...
...
@@ -798,33 +798,24 @@ class UnitOfWork implements PropertyChangedListener
$newNodes
=
array
();
foreach
(
$entityChangeSet
as
$entity
)
{
$className
=
get_class
(
$entity
);
if
(
!
$this
->
_commitOrderCalculator
->
hasNodeWithKey
(
$className
))
{
$this
->
_commitOrderCalculator
->
addNodeWithItem
(
$className
,
// index/key
$this
->
_em
->
getClassMetadata
(
$className
)
// item
);
$newNodes
[]
=
$this
->
_commitOrderCalculator
->
getNodeForKey
(
$className
);
if
(
!
$this
->
_commitOrderCalculator
->
hasClass
(
$className
))
{
$class
=
$this
->
_em
->
getClassMetadata
(
$className
);
$this
->
_commitOrderCalculator
->
addClass
(
$class
);
$newNodes
[]
=
$class
;
}
}
// Calculate dependencies for new nodes
foreach
(
$newNodes
as
$node
)
{
$class
=
$node
->
getClass
();
foreach
(
$newNodes
as
$class
)
{
foreach
(
$class
->
associationMappings
as
$assocMapping
)
{
//TODO: should skip target classes that are not in the changeset.
if
(
$assocMapping
->
isOwningSide
)
{
$targetClass
=
$this
->
_em
->
getClassMetadata
(
$assocMapping
->
targetEntityName
);
$targetClassName
=
$targetClass
->
name
;
// If the target class does not yet have a node, create it
if
(
!
$this
->
_commitOrderCalculator
->
hasNodeWithKey
(
$targetClassName
))
{
$this
->
_commitOrderCalculator
->
addNodeWithItem
(
$targetClassName
,
// index/key
$targetClass
// item
);
if
(
!
$this
->
_commitOrderCalculator
->
hasClass
(
$targetClass
->
name
))
{
$this
->
_commitOrderCalculator
->
addClass
(
$targetClass
);
}
// add dependency
$otherNode
=
$this
->
_commitOrderCalculator
->
getNodeForKey
(
$targetClassName
);
$otherNode
->
before
(
$node
);
$this
->
_commitOrderCalculator
->
addDependency
(
$targetClass
,
$class
);
}
}
}
...
...
tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php
View file @
2807a83d
...
...
@@ -2,6 +2,8 @@
namespace
Doctrine\Tests\ORM
;
use
Doctrine\ORM\Mapping\ClassMetadata
;
require_once
__DIR__
.
'/../TestInit.php'
;
/**
...
...
@@ -19,34 +21,36 @@ class CommitOrderCalculatorTest extends \Doctrine\Tests\OrmTestCase
{
$this
->
_calc
=
new
\Doctrine\ORM\Internal\CommitOrderCalculator
();
}
/** Helper to create an array of nodes */
private
function
_createNodes
(
array
$names
)
{
$nodes
=
array
();
foreach
(
$names
as
$name
)
{
$node
=
new
\Doctrine\ORM\Internal\CommitOrderNode
(
$name
,
$this
->
_calc
);
$nodes
[
$name
]
=
$node
;
$this
->
_calc
->
addNode
(
$node
->
getClass
(),
$node
);
}
return
$nodes
;
}
public
function
testCommitOrdering1
()
{
$nodes
=
$this
->
_createNodes
(
array
(
"node1"
,
"node2"
,
"node3"
,
"node4"
,
"node5"
));
$class1
=
new
ClassMetadata
(
__NAMESPACE__
.
'\NodeClass1'
);
$class2
=
new
ClassMetadata
(
__NAMESPACE__
.
'\NodeClass2'
);
$class3
=
new
ClassMetadata
(
__NAMESPACE__
.
'\NodeClass3'
);
$class4
=
new
ClassMetadata
(
__NAMESPACE__
.
'\NodeClass4'
);
$class5
=
new
ClassMetadata
(
__NAMESPACE__
.
'\NodeClass5'
);
$nodes
[
'node1'
]
->
before
(
$nodes
[
'node2'
]);
$nodes
[
'node2'
]
->
before
(
$nodes
[
'node3'
]);
$nodes
[
'node3'
]
->
before
(
$nodes
[
'node4'
]);
$nodes
[
'node5'
]
->
before
(
$nodes
[
'node1'
]);
$this
->
_calc
->
addClass
(
$class1
);
$this
->
_calc
->
addClass
(
$class2
);
$this
->
_calc
->
addClass
(
$class3
);
$this
->
_calc
->
addClass
(
$class4
);
$this
->
_calc
->
addClass
(
$class5
);
shuffle
(
$nodes
);
// some randomness
$this
->
_calc
->
addDependency
(
$class1
,
$class2
);
$this
->
_calc
->
addDependency
(
$class2
,
$class3
);
$this
->
_calc
->
addDependency
(
$class3
,
$class4
);
$this
->
_calc
->
addDependency
(
$class5
,
$class1
);
$sorted
=
$this
->
_calc
->
getCommitOrder
();
// There is only 1 valid ordering for this constellation
$correctOrder
=
array
(
"node5"
,
"node1"
,
"node2"
,
"node3"
,
"node4"
);
$correctOrder
=
array
(
$class5
,
$class1
,
$class2
,
$class3
,
$class4
);
$this
->
assertSame
(
$correctOrder
,
$sorted
);
}
}
\ No newline at end of file
}
class
NodeClass1
{}
class
NodeClass2
{}
class
NodeClass3
{}
class
NodeClass4
{}
class
NodeClass5
{}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment