| [4952] | 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | * $Id$ |
|---|
| 4 | * |
|---|
| 5 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|---|
| 6 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|---|
| 7 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|---|
| 8 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|---|
| 9 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|---|
| 10 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|---|
| 11 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|---|
| 12 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|---|
| 13 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|---|
| 14 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|---|
| 15 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 16 | * |
|---|
| 17 | * This software consists of voluntary contributions made by many individuals |
|---|
| 18 | * and is licensed under the LGPL. For more information, see |
|---|
| [5476] | 19 | * <http://www.doctrine-project.org>. |
|---|
| [4952] | 20 | */ |
|---|
| 21 | |
|---|
| [5396] | 22 | namespace Doctrine\ORM\Mapping; |
|---|
| [4952] | 23 | |
|---|
| 24 | /** |
|---|
| [6186] | 25 | * A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata |
|---|
| 26 | * of an entity and it's associations. |
|---|
| [6166] | 27 | * |
|---|
| 28 | * Once populated, ClassMetadata instances are usually cached in a serialized form. |
|---|
| [4952] | 29 | * |
|---|
| [5720] | 30 | * <b>IMPORTANT NOTE:</b> |
|---|
| 31 | * |
|---|
| 32 | * The fields of this class are only public for 2 reasons: |
|---|
| 33 | * 1) To allow fast READ access. |
|---|
| 34 | * 2) To drastically reduce the size of a serialized instance (private/protected members |
|---|
| 35 | * get the whole class name, namespace inclusive, prepended to every property in |
|---|
| 36 | * the serialized representation). |
|---|
| 37 | * |
|---|
| [4952] | 38 | * @author Roman Borschel <roman@code-factory.org> |
|---|
| [6430] | 39 | * @author Jonathan H. Wage <jonwage@gmail.com> |
|---|
| [4952] | 40 | * @since 2.0 |
|---|
| 41 | */ |
|---|
| [6971] | 42 | class ClassMetadata extends ClassMetadataInfo |
|---|
| [4952] | 43 | { |
|---|
| 44 | /** |
|---|
| [5334] | 45 | * The ReflectionClass instance of the mapped class. |
|---|
| 46 | * |
|---|
| 47 | * @var ReflectionClass |
|---|
| 48 | */ |
|---|
| [5720] | 49 | public $reflClass; |
|---|
| [5334] | 50 | |
|---|
| 51 | /** |
|---|
| 52 | * The ReflectionProperty instances of the mapped class. |
|---|
| 53 | * |
|---|
| 54 | * @var array |
|---|
| 55 | */ |
|---|
| [6411] | 56 | public $reflFields = array(); |
|---|
| [5313] | 57 | |
|---|
| [4952] | 58 | /** |
|---|
| [5468] | 59 | * Initializes a new ClassMetadata instance that will hold the object-relational mapping |
|---|
| 60 | * metadata of the class with the given name. |
|---|
| [4952] | 61 | * |
|---|
| [6112] | 62 | * @param string $entityName The name of the entity class the new instance is used for. |
|---|
| [4952] | 63 | */ |
|---|
| [5313] | 64 | public function __construct($entityName) |
|---|
| [4952] | 65 | { |
|---|
| [5720] | 66 | $this->name = $entityName; |
|---|
| [6174] | 67 | $this->reflClass = new \ReflectionClass($entityName); |
|---|
| 68 | $this->namespace = $this->reflClass->getNamespaceName(); |
|---|
| 69 | $this->primaryTable['name'] = $this->reflClass->getShortName(); |
|---|
| [5720] | 70 | $this->rootEntityName = $entityName; |
|---|
| [6644] | 71 | |
|---|
| 72 | //$this->prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name)); |
|---|
| [4952] | 73 | } |
|---|
| [5313] | 74 | |
|---|
| [5329] | 75 | /** |
|---|
| 76 | * Gets the ReflectionClass instance of the mapped class. |
|---|
| 77 | * |
|---|
| 78 | * @return ReflectionClass |
|---|
| 79 | */ |
|---|
| [5313] | 80 | public function getReflectionClass() |
|---|
| [4952] | 81 | { |
|---|
| [5720] | 82 | return $this->reflClass; |
|---|
| [4952] | 83 | } |
|---|
| 84 | |
|---|
| [5329] | 85 | /** |
|---|
| 86 | * Gets the ReflectionPropertys of the mapped class. |
|---|
| 87 | * |
|---|
| 88 | * @return array An array of ReflectionProperty instances. |
|---|
| 89 | */ |
|---|
| [5313] | 90 | public function getReflectionProperties() |
|---|
| 91 | { |
|---|
| [5720] | 92 | return $this->reflFields; |
|---|
| [5313] | 93 | } |
|---|
| 94 | |
|---|
| [5329] | 95 | /** |
|---|
| [5636] | 96 | * INTERNAL: |
|---|
| 97 | * Adds a reflection property. Usually only used by the ClassMetadataFactory |
|---|
| 98 | * while processing inheritance mappings. |
|---|
| 99 | * |
|---|
| 100 | * @param array $props |
|---|
| 101 | */ |
|---|
| 102 | public function addReflectionProperty($propName, \ReflectionProperty $property) |
|---|
| 103 | { |
|---|
| [5720] | 104 | $this->reflFields[$propName] = $property; |
|---|
| [5636] | 105 | } |
|---|
| 106 | |
|---|
| 107 | /** |
|---|
| [5329] | 108 | * Gets a ReflectionProperty for a specific field of the mapped class. |
|---|
| 109 | * |
|---|
| 110 | * @param string $name |
|---|
| 111 | * @return ReflectionProperty |
|---|
| 112 | */ |
|---|
| [5313] | 113 | public function getReflectionProperty($name) |
|---|
| 114 | { |
|---|
| [5720] | 115 | return $this->reflFields[$name]; |
|---|
| [5313] | 116 | } |
|---|
| 117 | |
|---|
| [5332] | 118 | /** |
|---|
| [5476] | 119 | * Gets the ReflectionProperty for the single identifier field. |
|---|
| [5332] | 120 | * |
|---|
| [5476] | 121 | * @return ReflectionProperty |
|---|
| [6791] | 122 | * @throws BadMethodCallException If the class has a composite identifier. |
|---|
| [5332] | 123 | */ |
|---|
| [5329] | 124 | public function getSingleIdReflectionProperty() |
|---|
| 125 | { |
|---|
| [5720] | 126 | if ($this->isIdentifierComposite) { |
|---|
| [6791] | 127 | throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier."); |
|---|
| [5329] | 128 | } |
|---|
| [5720] | 129 | return $this->reflFields[$this->identifier[0]]; |
|---|
| [5329] | 130 | } |
|---|
| [4952] | 131 | |
|---|
| 132 | /** |
|---|
| [5476] | 133 | * Validates & completes the given field mapping. |
|---|
| [4952] | 134 | * |
|---|
| 135 | * @param array $mapping The field mapping to validated & complete. |
|---|
| 136 | * @return array The validated and completed field mapping. |
|---|
| [7041] | 137 | * |
|---|
| 138 | * @throws MappingException |
|---|
| [4952] | 139 | */ |
|---|
| [6427] | 140 | protected function _validateAndCompleteFieldMapping(array &$mapping) |
|---|
| [4952] | 141 | { |
|---|
| [6427] | 142 | parent::_validateAndCompleteFieldMapping($mapping); |
|---|
| [5350] | 143 | |
|---|
| [5359] | 144 | // Store ReflectionProperty of mapped field |
|---|
| [7043] | 145 | $refProp = $this->reflClass->getProperty($mapping['fieldName']); |
|---|
| 146 | $refProp->setAccessible(true); |
|---|
| 147 | $this->reflFields[$mapping['fieldName']] = $refProp; |
|---|
| [5332] | 148 | } |
|---|
| [5313] | 149 | |
|---|
| [4952] | 150 | /** |
|---|
| [5706] | 151 | * Extracts the identifier values of an entity of this class. |
|---|
| [5880] | 152 | * |
|---|
| 153 | * For composite identifiers, the identifier values are returned as an array |
|---|
| 154 | * with the same order as the field order in {@link identifier}. |
|---|
| [5706] | 155 | * |
|---|
| 156 | * @param object $entity |
|---|
| 157 | * @return mixed |
|---|
| 158 | */ |
|---|
| 159 | public function getIdentifierValues($entity) |
|---|
| 160 | { |
|---|
| [5720] | 161 | if ($this->isIdentifierComposite) { |
|---|
| [5706] | 162 | $id = array(); |
|---|
| [5720] | 163 | foreach ($this->identifier as $idField) { |
|---|
| 164 | $value = $this->reflFields[$idField]->getValue($entity); |
|---|
| [5706] | 165 | if ($value !== null) { |
|---|
| [6791] | 166 | $id[$idField] = $value; |
|---|
| [5706] | 167 | } |
|---|
| 168 | } |
|---|
| 169 | return $id; |
|---|
| 170 | } else { |
|---|
| [6791] | 171 | return array($this->identifier[0] => $this->reflFields[$this->identifier[0]]->getValue($entity)); |
|---|
| [5706] | 172 | } |
|---|
| 173 | } |
|---|
| [6575] | 174 | |
|---|
| 175 | public function getColumnValues($entity, array $columns) |
|---|
| 176 | { |
|---|
| 177 | $values = array(); |
|---|
| 178 | foreach ($columns as $column) { |
|---|
| 179 | $values[] = $this->reflFields[$this->fieldNames[$column]]->getValue($entity); |
|---|
| 180 | } |
|---|
| 181 | return $values; |
|---|
| 182 | } |
|---|
| [5706] | 183 | |
|---|
| 184 | /** |
|---|
| 185 | * Populates the entity identifier of an entity. |
|---|
| 186 | * |
|---|
| 187 | * @param object $entity |
|---|
| 188 | * @param mixed $id |
|---|
| [5716] | 189 | * @todo Rename to assignIdentifier() |
|---|
| [5706] | 190 | */ |
|---|
| 191 | public function setIdentifierValues($entity, $id) |
|---|
| 192 | { |
|---|
| [5720] | 193 | if ($this->isIdentifierComposite) { |
|---|
| [5706] | 194 | foreach ((array)$id as $idField => $idValue) { |
|---|
| [5720] | 195 | $this->reflFields[$idField]->setValue($entity, $idValue); |
|---|
| [5706] | 196 | } |
|---|
| 197 | } else { |
|---|
| [5720] | 198 | $this->reflFields[$this->identifier[0]]->setValue($entity, $id); |
|---|
| [5706] | 199 | } |
|---|
| 200 | } |
|---|
| [5716] | 201 | |
|---|
| 202 | /** |
|---|
| 203 | * Sets the specified field to the specified value on the given entity. |
|---|
| 204 | * |
|---|
| 205 | * @param object $entity |
|---|
| 206 | * @param string $field |
|---|
| 207 | * @param mixed $value |
|---|
| 208 | */ |
|---|
| 209 | public function setFieldValue($entity, $field, $value) |
|---|
| 210 | { |
|---|
| [5720] | 211 | $this->reflFields[$field]->setValue($entity, $value); |
|---|
| [5716] | 212 | } |
|---|
| 213 | |
|---|
| 214 | /** |
|---|
| 215 | * Sets the field mapped to the specified column to the specified value on the given entity. |
|---|
| 216 | * |
|---|
| 217 | * @param object $entity |
|---|
| 218 | * @param string $field |
|---|
| 219 | * @param mixed $value |
|---|
| 220 | */ |
|---|
| 221 | public function setColumnValue($entity, $column, $value) |
|---|
| 222 | { |
|---|
| [5720] | 223 | $this->reflFields[$this->fieldNames[$column]]->setValue($entity, $value); |
|---|
| [5716] | 224 | } |
|---|
| [4952] | 225 | |
|---|
| 226 | /** |
|---|
| 227 | * Stores the association mapping. |
|---|
| 228 | * |
|---|
| [5468] | 229 | * @param AssociationMapping $assocMapping |
|---|
| [4952] | 230 | */ |
|---|
| [6427] | 231 | protected function _storeAssociationMapping(AssociationMapping $assocMapping) |
|---|
| [4952] | 232 | { |
|---|
| [6427] | 233 | parent::_storeAssociationMapping($assocMapping); |
|---|
| [5359] | 234 | |
|---|
| 235 | // Store ReflectionProperty of mapped field |
|---|
| [6427] | 236 | $sourceFieldName = $assocMapping->sourceFieldName; |
|---|
| [7041] | 237 | |
|---|
| [7043] | 238 | $refProp = $this->reflClass->getProperty($sourceFieldName); |
|---|
| 239 | $refProp->setAccessible(true); |
|---|
| 240 | $this->reflFields[$sourceFieldName] = $refProp; |
|---|
| [4952] | 241 | } |
|---|
| 242 | |
|---|
| 243 | /** |
|---|
| [5468] | 244 | * Dispatches the lifecycle event of the given entity to the registered |
|---|
| [4952] | 245 | * lifecycle callbacks and lifecycle listeners. |
|---|
| 246 | * |
|---|
| 247 | * @param string $event The lifecycle event. |
|---|
| 248 | * @param Entity $entity The Entity on which the event occured. |
|---|
| 249 | */ |
|---|
| [5396] | 250 | public function invokeLifecycleCallbacks($lifecycleEvent, $entity) |
|---|
| [4952] | 251 | { |
|---|
| [6112] | 252 | foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) { |
|---|
| [4952] | 253 | $entity->$callback(); |
|---|
| 254 | } |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | /** |
|---|
| [6222] | 258 | * Gets the (possibly quoted) column name of a mapped field for safe use |
|---|
| 259 | * in an SQL statement. |
|---|
| 260 | * |
|---|
| 261 | * @param string $field |
|---|
| 262 | * @param AbstractPlatform $platform |
|---|
| 263 | * @return string |
|---|
| 264 | */ |
|---|
| 265 | public function getQuotedColumnName($field, $platform) |
|---|
| 266 | { |
|---|
| 267 | return isset($this->fieldMappings[$field]['quoted']) ? |
|---|
| 268 | $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : |
|---|
| 269 | $this->fieldMappings[$field]['columnName']; |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | /** |
|---|
| 273 | * Gets the (possibly quoted) primary table name of this class for safe use |
|---|
| 274 | * in an SQL statement. |
|---|
| 275 | * |
|---|
| 276 | * @param AbstractPlatform $platform |
|---|
| 277 | * @return string |
|---|
| 278 | */ |
|---|
| 279 | public function getQuotedTableName($platform) |
|---|
| 280 | { |
|---|
| 281 | return isset($this->primaryTable['quoted']) ? |
|---|
| 282 | $platform->quoteIdentifier($this->primaryTable['name']) : |
|---|
| 283 | $this->primaryTable['name']; |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | /** |
|---|
| 287 | * Gets the (possibly quoted) name of the discriminator column for safe use |
|---|
| 288 | * in an SQL statement. |
|---|
| 289 | * |
|---|
| 290 | * @param AbstractPlatform $platform |
|---|
| 291 | * @return string |
|---|
| 292 | */ |
|---|
| 293 | public function getQuotedDiscriminatorColumnName($platform) |
|---|
| 294 | { |
|---|
| 295 | return isset($this->discriminatorColumn['quoted']) ? |
|---|
| 296 | $platform->quoteIdentifier($this->discriminatorColumn['name']) : |
|---|
| 297 | $this->discriminatorColumn['name']; |
|---|
| 298 | } |
|---|
| 299 | |
|---|
| 300 | /** |
|---|
| [5627] | 301 | * Creates a string representation of this instance. |
|---|
| 302 | * |
|---|
| 303 | * @return string The string representation of this instance. |
|---|
| [5838] | 304 | * @todo Construct meaningful string representation. |
|---|
| [5627] | 305 | */ |
|---|
| [4952] | 306 | public function __toString() |
|---|
| 307 | { |
|---|
| [5329] | 308 | return __CLASS__ . '@' . spl_object_hash($this); |
|---|
| [4952] | 309 | } |
|---|
| [6222] | 310 | |
|---|
| 311 | /** |
|---|
| 312 | * Determines which fields get serialized. |
|---|
| 313 | * |
|---|
| 314 | * Parts that are NOT serialized because they can not be properly unserialized: |
|---|
| 315 | * - reflClass (ReflectionClass) |
|---|
| 316 | * - reflFields (ReflectionProperty array) |
|---|
| 317 | * |
|---|
| 318 | * @return array The names of all the fields that should be serialized. |
|---|
| 319 | */ |
|---|
| 320 | public function __sleep() |
|---|
| 321 | { |
|---|
| 322 | return array( |
|---|
| [6971] | 323 | 'associationMappings', // unserialization bottleneck with many assocs |
|---|
| [6222] | 324 | 'changeTrackingPolicy', |
|---|
| [6971] | 325 | 'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName'] |
|---|
| [6222] | 326 | 'customRepositoryClassName', |
|---|
| 327 | 'discriminatorColumn', |
|---|
| 328 | 'discriminatorValue', |
|---|
| [6422] | 329 | 'discriminatorMap', |
|---|
| [6222] | 330 | 'fieldMappings', |
|---|
| [6971] | 331 | 'fieldNames', //TODO: Not all of this stuff needs to be serialized. Only type, columnName and fieldName. |
|---|
| [6222] | 332 | 'generatorType', |
|---|
| 333 | 'identifier', |
|---|
| [6971] | 334 | 'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime. |
|---|
| [6222] | 335 | 'inheritanceType', |
|---|
| 336 | 'inheritedAssociationFields', |
|---|
| [6908] | 337 | 'inverseMappings', //TODO: Remove! |
|---|
| [6222] | 338 | 'isIdentifierComposite', |
|---|
| 339 | 'isMappedSuperclass', |
|---|
| 340 | 'isVersioned', |
|---|
| 341 | 'lifecycleCallbacks', |
|---|
| 342 | 'name', |
|---|
| 343 | 'parentClasses', |
|---|
| 344 | 'primaryTable', |
|---|
| 345 | 'rootEntityName', |
|---|
| 346 | 'subClasses', |
|---|
| 347 | 'versionField' |
|---|
| 348 | ); |
|---|
| 349 | } |
|---|
| 350 | |
|---|
| 351 | /** |
|---|
| [6565] | 352 | * Restores some state that can not be serialized/unserialized. |
|---|
| [6222] | 353 | * |
|---|
| 354 | * @return void |
|---|
| 355 | */ |
|---|
| 356 | public function __wakeup() |
|---|
| 357 | { |
|---|
| 358 | // Restore ReflectionClass and properties |
|---|
| 359 | $this->reflClass = new \ReflectionClass($this->name); |
|---|
| [7041] | 360 | |
|---|
| [7030] | 361 | foreach ($this->fieldMappings as $field => $mapping) { |
|---|
| [7043] | 362 | if (isset($mapping['inherited'])) { |
|---|
| 363 | $reflField = new \ReflectionProperty($mapping['inherited'], $field); |
|---|
| 364 | } else { |
|---|
| 365 | $reflField = $this->reflClass->getProperty($field); |
|---|
| 366 | } |
|---|
| [7041] | 367 | |
|---|
| [7043] | 368 | $reflField->setAccessible(true); |
|---|
| 369 | $this->reflFields[$field] = $reflField; |
|---|
| [6222] | 370 | } |
|---|
| [7041] | 371 | |
|---|
| [6222] | 372 | foreach ($this->associationMappings as $field => $mapping) { |
|---|
| [7043] | 373 | if (isset($this->inheritedAssociationFields[$field])) { |
|---|
| 374 | $reflField = new \ReflectionProperty($this->inheritedAssociationFields[$field], $field); |
|---|
| 375 | } else { |
|---|
| 376 | $reflField = $this->reflClass->getProperty($field); |
|---|
| 377 | } |
|---|
| [7041] | 378 | |
|---|
| [7043] | 379 | $reflField->setAccessible(true); |
|---|
| 380 | $this->reflFields[$field] = $reflField; |
|---|
| [6222] | 381 | } |
|---|
| [6644] | 382 | |
|---|
| 383 | //$this->prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name)); |
|---|
| [6222] | 384 | } |
|---|
| [6644] | 385 | |
|---|
| 386 | //public $prototype; |
|---|
| [6120] | 387 | } |
|---|