|
1 <?php |
|
2 /* |
|
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
14 * |
|
15 * This software consists of voluntary contributions made by many individuals |
|
16 * and is licensed under the LGPL. For more information, see |
|
17 * <http://www.doctrine-project.org>. |
|
18 */ |
|
19 |
|
20 namespace Doctrine\Common\DataFixtures\Purger; |
|
21 |
|
22 use Doctrine\ORM\EntityManager; |
|
23 use Doctrine\ORM\Internal\CommitOrderCalculator; |
|
24 use Doctrine\ORM\Mapping\ClassMetadata; |
|
25 |
|
26 /** |
|
27 * Class responsible for purging databases of data before reloading data fixtures. |
|
28 * |
|
29 * @author Jonathan H. Wage <jonwage@gmail.com> |
|
30 * @author Benjamin Eberlei <kontakt@beberlei.de> |
|
31 */ |
|
32 class ORMPurger implements PurgerInterface |
|
33 { |
|
34 const PURGE_MODE_DELETE = 1; |
|
35 const PURGE_MODE_TRUNCATE = 2; |
|
36 |
|
37 /** EntityManager instance used for persistence. */ |
|
38 private $em; |
|
39 |
|
40 /** |
|
41 * If the purge should be done through DELETE or TRUNCATE statements |
|
42 * |
|
43 * @var int |
|
44 */ |
|
45 private $purgeMode = self::PURGE_MODE_DELETE; |
|
46 |
|
47 /** |
|
48 * Construct new purger instance. |
|
49 * |
|
50 * @param EntityManager $em EntityManager instance used for persistence. |
|
51 */ |
|
52 public function __construct(EntityManager $em = null) |
|
53 { |
|
54 $this->em = $em; |
|
55 } |
|
56 |
|
57 /** |
|
58 * Set the purge mode |
|
59 * |
|
60 * @param $mode |
|
61 * @return void |
|
62 */ |
|
63 public function setPurgeMode($mode) |
|
64 { |
|
65 $this->purgeMode = $mode; |
|
66 } |
|
67 |
|
68 /** |
|
69 * Get the purge mode |
|
70 * |
|
71 * @return int |
|
72 */ |
|
73 public function getPurgeMode() |
|
74 { |
|
75 return $this->purgeMode; |
|
76 } |
|
77 |
|
78 /** |
|
79 * Set the EntityManager instance this purger instance should use. |
|
80 * |
|
81 * @param EntityManager $em |
|
82 */ |
|
83 public function setEntityManager(EntityManager $em) |
|
84 { |
|
85 $this->em = $em; |
|
86 } |
|
87 |
|
88 /** @inheritDoc */ |
|
89 public function purge() |
|
90 { |
|
91 $classes = array(); |
|
92 $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); |
|
93 |
|
94 foreach ($metadatas as $metadata) { |
|
95 if ( ! $metadata->isMappedSuperclass) { |
|
96 $classes[] = $metadata; |
|
97 } |
|
98 } |
|
99 |
|
100 $commitOrder = $this->getCommitOrder($this->em, $classes); |
|
101 |
|
102 // Drop association tables first |
|
103 $orderedTables = $this->getAssociationTables($commitOrder); |
|
104 |
|
105 // Drop tables in reverse commit order |
|
106 for ($i = count($commitOrder) - 1; $i >= 0; --$i) { |
|
107 $class = $commitOrder[$i]; |
|
108 |
|
109 if (($class->isInheritanceTypeSingleTable() && $class->name != $class->rootEntityName) |
|
110 || $class->isMappedSuperclass) { |
|
111 continue; |
|
112 } |
|
113 |
|
114 $orderedTables[] = $class->getTableName(); |
|
115 } |
|
116 |
|
117 $platform = $this->em->getConnection()->getDatabasePlatform(); |
|
118 foreach($orderedTables as $tbl) { |
|
119 if ($this->purgeMode === self::PURGE_MODE_DELETE) { |
|
120 $this->em->getConnection()->executeUpdate("DELETE FROM " . $tbl); |
|
121 } else { |
|
122 $this->em->getConnection()->executeUpdate($platform->getTruncateTableSQL($tbl, true)); |
|
123 } |
|
124 } |
|
125 } |
|
126 |
|
127 private function getCommitOrder(EntityManager $em, array $classes) |
|
128 { |
|
129 $calc = new CommitOrderCalculator; |
|
130 |
|
131 foreach ($classes as $class) { |
|
132 $calc->addClass($class); |
|
133 |
|
134 foreach ($class->associationMappings as $assoc) { |
|
135 if ($assoc['isOwningSide']) { |
|
136 $targetClass = $em->getClassMetadata($assoc['targetEntity']); |
|
137 |
|
138 if ( ! $calc->hasClass($targetClass->name)) { |
|
139 $calc->addClass($targetClass); |
|
140 } |
|
141 |
|
142 // add dependency ($targetClass before $class) |
|
143 $calc->addDependency($targetClass, $class); |
|
144 } |
|
145 } |
|
146 } |
|
147 |
|
148 return $calc->getCommitOrder(); |
|
149 } |
|
150 |
|
151 private function getAssociationTables(array $classes) |
|
152 { |
|
153 $associationTables = array(); |
|
154 |
|
155 foreach ($classes as $class) { |
|
156 foreach ($class->associationMappings as $assoc) { |
|
157 if ($assoc['isOwningSide'] && $assoc['type'] == ClassMetadata::MANY_TO_MANY) { |
|
158 $associationTables[] = $assoc['joinTable']['name']; |
|
159 } |
|
160 } |
|
161 } |
|
162 |
|
163 return $associationTables; |
|
164 } |
|
165 } |