PageRenderTime 83ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/doctrine/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php

https://github.com/casoetan/ServerGroveLiveChat
PHP | 1742 lines | 735 code | 145 blank | 862 comment | 163 complexity | f8c36265fe079b5a27eeb33289725b98 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, ISC, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  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. namespace Doctrine\ORM\Mapping;
  20. use ReflectionClass;
  21. /**
  22. * A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
  23. * of an entity and it's associations.
  24. *
  25. * Once populated, ClassMetadata instances are usually cached in a serialized form.
  26. *
  27. * <b>IMPORTANT NOTE:</b>
  28. *
  29. * The fields of this class are only public for 2 reasons:
  30. * 1) To allow fast READ access.
  31. * 2) To drastically reduce the size of a serialized instance (private/protected members
  32. * get the whole class name, namespace inclusive, prepended to every property in
  33. * the serialized representation).
  34. *
  35. * @author Roman Borschel <roman@code-factory.org>
  36. * @author Jonathan H. Wage <jonwage@gmail.com>
  37. * @since 2.0
  38. */
  39. class ClassMetadataInfo
  40. {
  41. /* The inheritance mapping types */
  42. /**
  43. * NONE means the class does not participate in an inheritance hierarchy
  44. * and therefore does not need an inheritance mapping type.
  45. */
  46. const INHERITANCE_TYPE_NONE = 1;
  47. /**
  48. * JOINED means the class will be persisted according to the rules of
  49. * <tt>Class Table Inheritance</tt>.
  50. */
  51. const INHERITANCE_TYPE_JOINED = 2;
  52. /**
  53. * SINGLE_TABLE means the class will be persisted according to the rules of
  54. * <tt>Single Table Inheritance</tt>.
  55. */
  56. const INHERITANCE_TYPE_SINGLE_TABLE = 3;
  57. /**
  58. * TABLE_PER_CLASS means the class will be persisted according to the rules
  59. * of <tt>Concrete Table Inheritance</tt>.
  60. */
  61. const INHERITANCE_TYPE_TABLE_PER_CLASS = 4;
  62. /* The Id generator types. */
  63. /**
  64. * AUTO means the generator type will depend on what the used platform prefers.
  65. * Offers full portability.
  66. */
  67. const GENERATOR_TYPE_AUTO = 1;
  68. /**
  69. * SEQUENCE means a separate sequence object will be used. Platforms that do
  70. * not have native sequence support may emulate it. Full portability is currently
  71. * not guaranteed.
  72. */
  73. const GENERATOR_TYPE_SEQUENCE = 2;
  74. /**
  75. * TABLE means a separate table is used for id generation.
  76. * Offers full portability.
  77. */
  78. const GENERATOR_TYPE_TABLE = 3;
  79. /**
  80. * IDENTITY means an identity column is used for id generation. The database
  81. * will fill in the id column on insertion. Platforms that do not support
  82. * native identity columns may emulate them. Full portability is currently
  83. * not guaranteed.
  84. */
  85. const GENERATOR_TYPE_IDENTITY = 4;
  86. /**
  87. * NONE means the class does not have a generated id. That means the class
  88. * must have a natural, manually assigned id.
  89. */
  90. const GENERATOR_TYPE_NONE = 5;
  91. /**
  92. * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
  93. * by doing a property-by-property comparison with the original data. This will
  94. * be done for all entities that are in MANAGED state at commit-time.
  95. *
  96. * This is the default change tracking policy.
  97. */
  98. const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
  99. /**
  100. * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
  101. * by doing a property-by-property comparison with the original data. This will
  102. * be done only for entities that were explicitly saved (through persist() or a cascade).
  103. */
  104. const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
  105. /**
  106. * NOTIFY means that Doctrine relies on the entities sending out notifications
  107. * when their properties change. Such entity classes must implement
  108. * the <tt>NotifyPropertyChanged</tt> interface.
  109. */
  110. const CHANGETRACKING_NOTIFY = 3;
  111. /**
  112. * Specifies that an association is to be fetched when it is first accessed.
  113. */
  114. const FETCH_LAZY = 2;
  115. /**
  116. * Specifies that an association is to be fetched when the owner of the
  117. * association is fetched.
  118. */
  119. const FETCH_EAGER = 3;
  120. /**
  121. * Specifies that an association is to be fetched lazy (on first access) and that
  122. * commands such as Collection#count, Collection#slice are issued directly against
  123. * the database if the collection is not yet initialized.
  124. */
  125. const FETCH_EXTRA_LAZY = 4;
  126. /**
  127. * Identifies a one-to-one association.
  128. */
  129. const ONE_TO_ONE = 1;
  130. /**
  131. * Identifies a many-to-one association.
  132. */
  133. const MANY_TO_ONE = 2;
  134. /**
  135. * Combined bitmask for to-one (single-valued) associations.
  136. */
  137. const TO_ONE = 3;
  138. /**
  139. * Identifies a one-to-many association.
  140. */
  141. const ONE_TO_MANY = 4;
  142. /**
  143. * Identifies a many-to-many association.
  144. */
  145. const MANY_TO_MANY = 8;
  146. /**
  147. * Combined bitmask for to-many (collection-valued) associations.
  148. */
  149. const TO_MANY = 12;
  150. /**
  151. * READ-ONLY: The name of the entity class.
  152. */
  153. public $name;
  154. /**
  155. * READ-ONLY: The namespace the entity class is contained in.
  156. *
  157. * @var string
  158. * @todo Not really needed. Usage could be localized.
  159. */
  160. public $namespace;
  161. /**
  162. * READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance
  163. * hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
  164. * as {@link $entityName}.
  165. *
  166. * @var string
  167. */
  168. public $rootEntityName;
  169. /**
  170. * The name of the custom repository class used for the entity class.
  171. * (Optional).
  172. *
  173. * @var string
  174. */
  175. public $customRepositoryClassName;
  176. /**
  177. * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
  178. *
  179. * @var boolean
  180. */
  181. public $isMappedSuperclass = false;
  182. /**
  183. * READ-ONLY: The names of the parent classes (ancestors).
  184. *
  185. * @var array
  186. */
  187. public $parentClasses = array();
  188. /**
  189. * READ-ONLY: The names of all subclasses (descendants).
  190. *
  191. * @var array
  192. */
  193. public $subClasses = array();
  194. /**
  195. * READ-ONLY: The field names of all fields that are part of the identifier/primary key
  196. * of the mapped entity class.
  197. *
  198. * @var array
  199. */
  200. public $identifier = array();
  201. /**
  202. * READ-ONLY: The inheritance mapping type used by the class.
  203. *
  204. * @var integer
  205. */
  206. public $inheritanceType = self::INHERITANCE_TYPE_NONE;
  207. /**
  208. * READ-ONLY: The Id generator type used by the class.
  209. *
  210. * @var string
  211. */
  212. public $generatorType = self::GENERATOR_TYPE_NONE;
  213. /**
  214. * READ-ONLY: The field mappings of the class.
  215. * Keys are field names and values are mapping definitions.
  216. *
  217. * The mapping definition array has the following values:
  218. *
  219. * - <b>fieldName</b> (string)
  220. * The name of the field in the Entity.
  221. *
  222. * - <b>type</b> (string)
  223. * The type name of the mapped field. Can be one of Doctrine's mapping types
  224. * or a custom mapping type.
  225. *
  226. * - <b>columnName</b> (string, optional)
  227. * The column name. Optional. Defaults to the field name.
  228. *
  229. * - <b>length</b> (integer, optional)
  230. * The database length of the column. Optional. Default value taken from
  231. * the type.
  232. *
  233. * - <b>id</b> (boolean, optional)
  234. * Marks the field as the primary key of the entity. Multiple fields of an
  235. * entity can have the id attribute, forming a composite key.
  236. *
  237. * - <b>nullable</b> (boolean, optional)
  238. * Whether the column is nullable. Defaults to FALSE.
  239. *
  240. * - <b>columnDefinition</b> (string, optional, schema-only)
  241. * The SQL fragment that is used when generating the DDL for the column.
  242. *
  243. * - <b>precision</b> (integer, optional, schema-only)
  244. * The precision of a decimal column. Only valid if the column type is decimal.
  245. *
  246. * - <b>scale</b> (integer, optional, schema-only)
  247. * The scale of a decimal column. Only valid if the column type is decimal.
  248. *
  249. [* - <b>'unique'] (string, optional, schema-only)</b>
  250. * Whether a unique constraint should be generated for the column.
  251. *
  252. * @var array
  253. */
  254. public $fieldMappings = array();
  255. /**
  256. * READ-ONLY: An array of field names. Used to look up field names from column names.
  257. * Keys are column names and values are field names.
  258. * This is the reverse lookup map of $_columnNames.
  259. *
  260. * @var array
  261. */
  262. public $fieldNames = array();
  263. /**
  264. * READ-ONLY: A map of field names to column names. Keys are field names and values column names.
  265. * Used to look up column names from field names.
  266. * This is the reverse lookup map of $_fieldNames.
  267. *
  268. * @var array
  269. * @todo We could get rid of this array by just using $fieldMappings[$fieldName]['columnName'].
  270. */
  271. public $columnNames = array();
  272. /**
  273. * READ-ONLY: The discriminator value of this class.
  274. *
  275. * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
  276. * where a discriminator column is used.</b>
  277. *
  278. * @var mixed
  279. * @see discriminatorColumn
  280. */
  281. public $discriminatorValue;
  282. /**
  283. * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
  284. *
  285. * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
  286. * where a discriminator column is used.</b>
  287. *
  288. * @var mixed
  289. * @see discriminatorColumn
  290. */
  291. public $discriminatorMap = array();
  292. /**
  293. * READ-ONLY: The definition of the descriminator column used in JOINED and SINGLE_TABLE
  294. * inheritance mappings.
  295. *
  296. * @var array
  297. */
  298. public $discriminatorColumn;
  299. /**
  300. * READ-ONLY: The primary table definition. The definition is an array with the
  301. * following entries:
  302. *
  303. * name => <tableName>
  304. * schema => <schemaName>
  305. * indexes => array
  306. * uniqueConstraints => array
  307. *
  308. * @var array
  309. * @todo Rename to just $table
  310. */
  311. public $table;
  312. /**
  313. * READ-ONLY: The registered lifecycle callbacks for entities of this class.
  314. *
  315. * @var array
  316. */
  317. public $lifecycleCallbacks = array();
  318. /**
  319. * READ-ONLY: The association mappings of this class.
  320. *
  321. * The mapping definition array supports the following keys:
  322. *
  323. * - <b>fieldName</b> (string)
  324. * The name of the field in the entity the association is mapped to.
  325. *
  326. * - <b>targetEntity</b> (string)
  327. * The class name of the target entity. If it is fully-qualified it is used as is.
  328. * If it is a simple, unqualified class name the namespace is assumed to be the same
  329. * as the namespace of the source entity.
  330. *
  331. * - <b>mappedBy</b> (string, required for bidirectional associations)
  332. * The name of the field that completes the bidirectional association on the owning side.
  333. * This key must be specified on the inverse side of a bidirectional association.
  334. *
  335. * - <b>inversedBy</b> (string, required for bidirectional associations)
  336. * The name of the field that completes the bidirectional association on the inverse side.
  337. * This key must be specified on the owning side of a bidirectional association.
  338. *
  339. * - <b>cascade</b> (array, optional)
  340. * The names of persistence operations to cascade on the association. The set of possible
  341. * values are: "persist", "remove", "detach", "merge", "refresh", "all" (implies all others).
  342. *
  343. * - <b>orderBy</b> (array, one-to-many/many-to-many only)
  344. * A map of field names (of the target entity) to sorting directions (ASC/DESC).
  345. * Example: array('priority' => 'desc')
  346. *
  347. * - <b>fetch</b> (integer, optional)
  348. * The fetching strategy to use for the association, usually defaults to FETCH_LAZY.
  349. * Possible values are: ClassMetadata::FETCH_EAGER, ClassMetadata::FETCH_LAZY.
  350. *
  351. * - <b>joinTable</b> (array, optional, many-to-many only)
  352. * Specification of the join table and its join columns (foreign keys).
  353. * Only valid for many-to-many mappings. Note that one-to-many associations can be mapped
  354. * through a join table by simply mapping the association as many-to-many with a unique
  355. * constraint on the join table.
  356. *
  357. * A join table definition has the following structure:
  358. * <pre>
  359. * array(
  360. * 'name' => <join table name>,
  361. * 'joinColumns' => array(<join column mapping from join table to source table>),
  362. * 'inverseJoinColumns' => array(<join column mapping from join table to target table>)
  363. * )
  364. * </pre>
  365. *
  366. *
  367. * @var array
  368. */
  369. public $associationMappings = array();
  370. /**
  371. * READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite.
  372. *
  373. * @var boolean
  374. */
  375. public $isIdentifierComposite = false;
  376. /**
  377. * READ-ONLY: Flag indicating wheather the identifier/primary key contains at least one foreign key association.
  378. *
  379. * This flag is necessary because some code blocks require special treatment of this cases.
  380. *
  381. * @var boolean
  382. */
  383. public $containsForeignIdentifier = false;
  384. /**
  385. * READ-ONLY: The ID generator used for generating IDs for this class.
  386. *
  387. * @var AbstractIdGenerator
  388. * @todo Remove!
  389. */
  390. public $idGenerator;
  391. /**
  392. * READ-ONLY: The definition of the sequence generator of this class. Only used for the
  393. * SEQUENCE generation strategy.
  394. *
  395. * The definition has the following structure:
  396. * <code>
  397. * array(
  398. * 'sequenceName' => 'name',
  399. * 'allocationSize' => 20,
  400. * 'initialValue' => 1
  401. * )
  402. * </code>
  403. *
  404. * @var array
  405. * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
  406. */
  407. public $sequenceGeneratorDefinition;
  408. /**
  409. * READ-ONLY: The definition of the table generator of this class. Only used for the
  410. * TABLE generation strategy.
  411. *
  412. * @var array
  413. * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
  414. */
  415. public $tableGeneratorDefinition;
  416. /**
  417. * READ-ONLY: The policy used for change-tracking on entities of this class.
  418. *
  419. * @var integer
  420. */
  421. public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
  422. /**
  423. * READ-ONLY: A flag for whether or not instances of this class are to be versioned
  424. * with optimistic locking.
  425. *
  426. * @var boolean $isVersioned
  427. */
  428. public $isVersioned;
  429. /**
  430. * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
  431. *
  432. * @var mixed $versionField
  433. */
  434. public $versionField;
  435. /**
  436. * The ReflectionClass instance of the mapped class.
  437. *
  438. * @var ReflectionClass
  439. */
  440. public $reflClass;
  441. /**
  442. * Initializes a new ClassMetadata instance that will hold the object-relational mapping
  443. * metadata of the class with the given name.
  444. *
  445. * @param string $entityName The name of the entity class the new instance is used for.
  446. */
  447. public function __construct($entityName)
  448. {
  449. $this->name = $entityName;
  450. $this->rootEntityName = $entityName;
  451. }
  452. /**
  453. * Gets the ReflectionClass instance of the mapped class.
  454. *
  455. * @return ReflectionClass
  456. */
  457. public function getReflectionClass()
  458. {
  459. if ( ! $this->reflClass) {
  460. $this->reflClass = new ReflectionClass($this->name);
  461. }
  462. return $this->reflClass;
  463. }
  464. /**
  465. * Sets the change tracking policy used by this class.
  466. *
  467. * @param integer $policy
  468. */
  469. public function setChangeTrackingPolicy($policy)
  470. {
  471. $this->changeTrackingPolicy = $policy;
  472. }
  473. /**
  474. * Whether the change tracking policy of this class is "deferred explicit".
  475. *
  476. * @return boolean
  477. */
  478. public function isChangeTrackingDeferredExplicit()
  479. {
  480. return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
  481. }
  482. /**
  483. * Whether the change tracking policy of this class is "deferred implicit".
  484. *
  485. * @return boolean
  486. */
  487. public function isChangeTrackingDeferredImplicit()
  488. {
  489. return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
  490. }
  491. /**
  492. * Whether the change tracking policy of this class is "notify".
  493. *
  494. * @return boolean
  495. */
  496. public function isChangeTrackingNotify()
  497. {
  498. return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
  499. }
  500. /**
  501. * Checks whether a field is part of the identifier/primary key field(s).
  502. *
  503. * @param string $fieldName The field name
  504. * @return boolean TRUE if the field is part of the table identifier/primary key field(s),
  505. * FALSE otherwise.
  506. */
  507. public function isIdentifier($fieldName)
  508. {
  509. if ( ! $this->isIdentifierComposite) {
  510. return $fieldName === $this->identifier[0];
  511. }
  512. return in_array($fieldName, $this->identifier);
  513. }
  514. /**
  515. * Check if the field is unique.
  516. *
  517. * @param string $fieldName The field name
  518. * @return boolean TRUE if the field is unique, FALSE otherwise.
  519. */
  520. public function isUniqueField($fieldName)
  521. {
  522. $mapping = $this->getFieldMapping($fieldName);
  523. if ($mapping !== false) {
  524. return isset($mapping['unique']) && $mapping['unique'] == true;
  525. }
  526. return false;
  527. }
  528. /**
  529. * Check if the field is not null.
  530. *
  531. * @param string $fieldName The field name
  532. * @return boolean TRUE if the field is not null, FALSE otherwise.
  533. */
  534. public function isNullable($fieldName)
  535. {
  536. $mapping = $this->getFieldMapping($fieldName);
  537. if ($mapping !== false) {
  538. return isset($mapping['nullable']) && $mapping['nullable'] == true;
  539. }
  540. return false;
  541. }
  542. /**
  543. * Gets a column name for a field name.
  544. * If the column name for the field cannot be found, the given field name
  545. * is returned.
  546. *
  547. * @param string $fieldName The field name.
  548. * @return string The column name.
  549. */
  550. public function getColumnName($fieldName)
  551. {
  552. return isset($this->columnNames[$fieldName]) ?
  553. $this->columnNames[$fieldName] : $fieldName;
  554. }
  555. /**
  556. * Gets the mapping of a (regular) field that holds some data but not a
  557. * reference to another object.
  558. *
  559. * @param string $fieldName The field name.
  560. * @return array The field mapping.
  561. */
  562. public function getFieldMapping($fieldName)
  563. {
  564. if ( ! isset($this->fieldMappings[$fieldName])) {
  565. throw MappingException::mappingNotFound($this->name, $fieldName);
  566. }
  567. return $this->fieldMappings[$fieldName];
  568. }
  569. /**
  570. * Gets the mapping of an association.
  571. *
  572. * @see ClassMetadataInfo::$associationMappings
  573. * @param string $fieldName The field name that represents the association in
  574. * the object model.
  575. * @return array The mapping.
  576. */
  577. public function getAssociationMapping($fieldName)
  578. {
  579. if ( ! isset($this->associationMappings[$fieldName])) {
  580. throw MappingException::mappingNotFound($this->name, $fieldName);
  581. }
  582. return $this->associationMappings[$fieldName];
  583. }
  584. /**
  585. * Gets all association mappings of the class.
  586. *
  587. * @return array
  588. */
  589. public function getAssociationMappings()
  590. {
  591. return $this->associationMappings;
  592. }
  593. /**
  594. * Gets the field name for a column name.
  595. * If no field name can be found the column name is returned.
  596. *
  597. * @param string $columnName column name
  598. * @return string column alias
  599. */
  600. public function getFieldName($columnName)
  601. {
  602. return isset($this->fieldNames[$columnName]) ?
  603. $this->fieldNames[$columnName] : $columnName;
  604. }
  605. /**
  606. * Validates & completes the given field mapping.
  607. *
  608. * @param array $mapping The field mapping to validated & complete.
  609. * @return array The validated and completed field mapping.
  610. */
  611. protected function _validateAndCompleteFieldMapping(array &$mapping)
  612. {
  613. // Check mandatory fields
  614. if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
  615. throw MappingException::missingFieldName($this->name);
  616. }
  617. if ( ! isset($mapping['type'])) {
  618. // Default to string
  619. $mapping['type'] = 'string';
  620. }
  621. // Complete fieldName and columnName mapping
  622. if ( ! isset($mapping['columnName'])) {
  623. $mapping['columnName'] = $mapping['fieldName'];
  624. } else {
  625. if ($mapping['columnName'][0] == '`') {
  626. $mapping['columnName'] = trim($mapping['columnName'], '`');
  627. $mapping['quoted'] = true;
  628. }
  629. }
  630. $this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
  631. if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn != null && $this->discriminatorColumn['name'] == $mapping['columnName'])) {
  632. throw MappingException::duplicateColumnName($this->name, $mapping['columnName']);
  633. }
  634. $this->fieldNames[$mapping['columnName']] = $mapping['fieldName'];
  635. // Complete id mapping
  636. if (isset($mapping['id']) && $mapping['id'] === true) {
  637. if ($this->versionField == $mapping['fieldName']) {
  638. throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']);
  639. }
  640. if ( ! in_array($mapping['fieldName'], $this->identifier)) {
  641. $this->identifier[] = $mapping['fieldName'];
  642. }
  643. // Check for composite key
  644. if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
  645. $this->isIdentifierComposite = true;
  646. }
  647. }
  648. }
  649. /**
  650. * Validates & completes the basic mapping information that is common to all
  651. * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
  652. *
  653. * @param array $mapping The mapping.
  654. * @return array The updated mapping.
  655. * @throws MappingException If something is wrong with the mapping.
  656. */
  657. protected function _validateAndCompleteAssociationMapping(array $mapping)
  658. {
  659. if ( ! isset($mapping['mappedBy'])) {
  660. $mapping['mappedBy'] = null;
  661. }
  662. if ( ! isset($mapping['inversedBy'])) {
  663. $mapping['inversedBy'] = null;
  664. }
  665. $mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
  666. // If targetEntity is unqualified, assume it is in the same namespace as
  667. // the sourceEntity.
  668. $mapping['sourceEntity'] = $this->name;
  669. if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false
  670. && strlen($this->namespace) > 0) {
  671. $mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
  672. }
  673. // Complete id mapping
  674. if (isset($mapping['id']) && $mapping['id'] === true) {
  675. if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
  676. throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']);
  677. }
  678. if ( ! in_array($mapping['fieldName'], $this->identifier)) {
  679. if (count($mapping['joinColumns']) >= 2) {
  680. throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
  681. $mapping['targetEntity'], $this->name, $mapping['fieldName']
  682. );
  683. }
  684. $this->identifier[] = $mapping['fieldName'];
  685. $this->containsForeignIdentifier = true;
  686. }
  687. // Check for composite key
  688. if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
  689. $this->isIdentifierComposite = true;
  690. }
  691. }
  692. // Mandatory attributes for both sides
  693. // Mandatory: fieldName, targetEntity
  694. if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
  695. throw MappingException::missingFieldName($this->name);
  696. }
  697. if ( ! isset($mapping['targetEntity'])) {
  698. throw MappingException::missingTargetEntity($mapping['fieldName']);
  699. }
  700. // Mandatory and optional attributes for either side
  701. if ( ! $mapping['mappedBy']) {
  702. if (isset($mapping['joinTable']) && $mapping['joinTable']) {
  703. if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] == '`') {
  704. $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
  705. $mapping['joinTable']['quoted'] = true;
  706. }
  707. }
  708. } else {
  709. $mapping['isOwningSide'] = false;
  710. }
  711. if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & ClassMetadata::TO_MANY) {
  712. throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']);
  713. }
  714. // Fetch mode. Default fetch mode to LAZY, if not set.
  715. if ( ! isset($mapping['fetch'])) {
  716. $mapping['fetch'] = self::FETCH_LAZY;
  717. }
  718. // Cascades
  719. $cascades = isset($mapping['cascade']) ? $mapping['cascade'] : array();
  720. if (in_array('all', $cascades)) {
  721. $cascades = array(
  722. 'remove',
  723. 'persist',
  724. 'refresh',
  725. 'merge',
  726. 'detach'
  727. );
  728. }
  729. $mapping['cascade'] = $cascades;
  730. $mapping['isCascadeRemove'] = in_array('remove', $cascades);
  731. $mapping['isCascadePersist'] = in_array('persist', $cascades);
  732. $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
  733. $mapping['isCascadeMerge'] = in_array('merge', $cascades);
  734. $mapping['isCascadeDetach'] = in_array('detach', $cascades);
  735. return $mapping;
  736. }
  737. /**
  738. * Validates & completes a one-to-one association mapping.
  739. *
  740. * @param array $mapping The mapping to validate & complete.
  741. * @return array The validated & completed mapping.
  742. * @override
  743. */
  744. protected function _validateAndCompleteOneToOneMapping(array $mapping)
  745. {
  746. $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
  747. if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
  748. $mapping['isOwningSide'] = true;
  749. }
  750. if ($mapping['isOwningSide']) {
  751. if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
  752. // Apply default join column
  753. $mapping['joinColumns'] = array(array(
  754. 'name' => $mapping['fieldName'] . '_id',
  755. 'referencedColumnName' => 'id'
  756. ));
  757. }
  758. $uniqueContraintColumns = array();
  759. foreach ($mapping['joinColumns'] as $key => &$joinColumn) {
  760. if ($mapping['type'] === self::ONE_TO_ONE) {
  761. if (count($mapping['joinColumns']) == 1) {
  762. $joinColumn['unique'] = true;
  763. } else {
  764. $uniqueContraintColumns[] = $joinColumn['name'];
  765. }
  766. }
  767. if (empty($joinColumn['name'])) {
  768. $joinColumn['name'] = $mapping['fieldName'] . '_id';
  769. }
  770. if (empty($joinColumn['referencedColumnName'])) {
  771. $joinColumn['referencedColumnName'] = 'id';
  772. }
  773. $mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
  774. $mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
  775. ? $joinColumn['fieldName'] : $joinColumn['name'];
  776. }
  777. if ($uniqueContraintColumns) {
  778. if (!$this->table) {
  779. throw new \RuntimeException("ClassMetadataInfo::setTable() has to be called before defining a one to one relationship.");
  780. }
  781. $this->table['uniqueConstraints'][$mapping['fieldName']."_uniq"] = array(
  782. 'columns' => $uniqueContraintColumns
  783. );
  784. }
  785. $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
  786. }
  787. //TODO: if orphanRemoval, cascade=remove is implicit!
  788. $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
  789. (bool) $mapping['orphanRemoval'] : false;
  790. if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
  791. throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']);
  792. }
  793. return $mapping;
  794. }
  795. /**
  796. * Validates and completes the mapping.
  797. *
  798. * @param array $mapping The mapping to validate and complete.
  799. * @return array The validated and completed mapping.
  800. * @override
  801. */
  802. protected function _validateAndCompleteOneToManyMapping(array $mapping)
  803. {
  804. $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
  805. // OneToMany-side MUST be inverse (must have mappedBy)
  806. if ( ! isset($mapping['mappedBy'])) {
  807. throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
  808. }
  809. //TODO: if orphanRemoval, cascade=remove is implicit!
  810. $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
  811. (bool) $mapping['orphanRemoval'] : false;
  812. if (isset($mapping['orderBy'])) {
  813. if ( ! is_array($mapping['orderBy'])) {
  814. throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
  815. }
  816. }
  817. return $mapping;
  818. }
  819. protected function _validateAndCompleteManyToManyMapping(array $mapping)
  820. {
  821. $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
  822. if ($mapping['isOwningSide']) {
  823. if (strpos($mapping['sourceEntity'], '\\') !== false) {
  824. $sourceShortName = strtolower(substr($mapping['sourceEntity'], strrpos($mapping['sourceEntity'], '\\') + 1));
  825. } else {
  826. $sourceShortName = strtolower($mapping['sourceEntity']);
  827. }
  828. if (strpos($mapping['targetEntity'], '\\') !== false) {
  829. $targetShortName = strtolower(substr($mapping['targetEntity'], strrpos($mapping['targetEntity'], '\\') + 1));
  830. } else {
  831. $targetShortName = strtolower($mapping['targetEntity']);
  832. }
  833. // owning side MUST have a join table
  834. if ( ! isset($mapping['joinTable']['name'])) {
  835. $mapping['joinTable']['name'] = $sourceShortName .'_' . $targetShortName;
  836. }
  837. if ( ! isset($mapping['joinTable']['joinColumns'])) {
  838. $mapping['joinTable']['joinColumns'] = array(array(
  839. 'name' => $sourceShortName . '_id',
  840. 'referencedColumnName' => 'id',
  841. 'onDelete' => 'CASCADE'));
  842. }
  843. if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
  844. $mapping['joinTable']['inverseJoinColumns'] = array(array(
  845. 'name' => $targetShortName . '_id',
  846. 'referencedColumnName' => 'id',
  847. 'onDelete' => 'CASCADE'));
  848. }
  849. foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
  850. if (empty($joinColumn['name'])) {
  851. $joinColumn['name'] = $sourceShortName . '_id';
  852. }
  853. if (empty($joinColumn['referencedColumnName'])) {
  854. $joinColumn['referencedColumnName'] = 'id';
  855. }
  856. if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
  857. $mapping['isOnDeleteCascade'] = true;
  858. }
  859. $mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
  860. $mapping['joinTableColumns'][] = $joinColumn['name'];
  861. }
  862. foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
  863. if (empty($inverseJoinColumn['name'])) {
  864. $inverseJoinColumn['name'] = $targetShortName . '_id';
  865. }
  866. if (empty($inverseJoinColumn['referencedColumnName'])) {
  867. $inverseJoinColumn['referencedColumnName'] = 'id';
  868. }
  869. if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
  870. $mapping['isOnDeleteCascade'] = true;
  871. }
  872. $mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
  873. $mapping['joinTableColumns'][] = $inverseJoinColumn['name'];
  874. }
  875. }
  876. if (isset($mapping['orderBy'])) {
  877. if ( ! is_array($mapping['orderBy'])) {
  878. throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
  879. }
  880. }
  881. return $mapping;
  882. }
  883. /**
  884. * Gets the identifier (primary key) field names of the class.
  885. *
  886. * @return mixed
  887. */
  888. public function getIdentifierFieldNames()
  889. {
  890. return $this->identifier;
  891. }
  892. /**
  893. * Gets the name of the single id field. Note that this only works on
  894. * entity classes that have a single-field pk.
  895. *
  896. * @return string
  897. * @throws MappingException If the class has a composite primary key.
  898. */
  899. public function getSingleIdentifierFieldName()
  900. {
  901. if ($this->isIdentifierComposite) {
  902. throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name);
  903. }
  904. return $this->identifier[0];
  905. }
  906. /**
  907. * Gets the column name of the single id column. Note that this only works on
  908. * entity classes that have a single-field pk.
  909. *
  910. * @return string
  911. * @throws MappingException If the class has a composite primary key.
  912. */
  913. public function getSingleIdentifierColumnName()
  914. {
  915. return $this->getColumnName($this->getSingleIdentifierFieldName());
  916. }
  917. /**
  918. * INTERNAL:
  919. * Sets the mapped identifier/primary key fields of this class.
  920. * Mainly used by the ClassMetadataFactory to assign inherited identifiers.
  921. *
  922. * @param array $identifier
  923. */
  924. public function setIdentifier(array $identifier)
  925. {
  926. $this->identifier = $identifier;
  927. $this->isIdentifierComposite = (count($this->identifier) > 1);
  928. }
  929. /**
  930. * Checks whether the class has a (mapped) field with a certain name.
  931. *
  932. * @return boolean
  933. */
  934. public function hasField($fieldName)
  935. {
  936. return isset($this->fieldMappings[$fieldName]);
  937. }
  938. /**
  939. * Gets an array containing all the column names.
  940. *
  941. * @return array
  942. */
  943. public function getColumnNames(array $fieldNames = null)
  944. {
  945. if ($fieldNames === null) {
  946. return array_keys($this->fieldNames);
  947. } else {
  948. $columnNames = array();
  949. foreach ($fieldNames as $fieldName) {
  950. $columnNames[] = $this->getColumnName($fieldName);
  951. }
  952. return $columnNames;
  953. }
  954. }
  955. /**
  956. * Returns an array with all the identifier column names.
  957. *
  958. * @return array
  959. */
  960. public function getIdentifierColumnNames()
  961. {
  962. if ($this->isIdentifierComposite) {
  963. $columnNames = array();
  964. foreach ($this->identifier as $idField) {
  965. if (isset($this->associationMappings[$idField])) {
  966. // no composite pk as fk entity assumption:
  967. $columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
  968. } else {
  969. $columnNames[] = $this->fieldMappings[$idField]['columnName'];
  970. }
  971. }
  972. return $columnNames;
  973. } else if(isset($this->fieldMappings[$this->identifier[0]])) {
  974. return array($this->fieldMappings[$this->identifier[0]]['columnName']);
  975. } else {
  976. // no composite pk as fk entity assumption:
  977. return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']);
  978. }
  979. }
  980. /**
  981. * Sets the type of Id generator to use for the mapped class.
  982. */
  983. public function setIdGeneratorType($generatorType)
  984. {
  985. $this->generatorType = $generatorType;
  986. }
  987. /**
  988. * Checks whether the mapped class uses an Id generator.
  989. *
  990. * @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
  991. */
  992. public function usesIdGenerator()
  993. {
  994. return $this->generatorType != self::GENERATOR_TYPE_NONE;
  995. }
  996. /**
  997. * @return boolean
  998. */
  999. public function isInheritanceTypeNone()
  1000. {
  1001. return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
  1002. }
  1003. /**
  1004. * Checks whether the mapped class uses the JOINED inheritance mapping strategy.
  1005. *
  1006. * @return boolean TRUE if the class participates in a JOINED inheritance mapping,
  1007. * FALSE otherwise.
  1008. */
  1009. public function isInheritanceTypeJoined()
  1010. {
  1011. return $this->inheritanceType == self::INHERITANCE_TYPE_JOINED;
  1012. }
  1013. /**
  1014. * Checks whether the mapped class uses the SINGLE_TABLE inheritance mapping strategy.
  1015. *
  1016. * @return boolean TRUE if the class participates in a SINGLE_TABLE inheritance mapping,
  1017. * FALSE otherwise.
  1018. */
  1019. public function isInheritanceTypeSingleTable()
  1020. {
  1021. return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_TABLE;
  1022. }
  1023. /**
  1024. * Checks whether the mapped class uses the TABLE_PER_CLASS inheritance mapping strategy.
  1025. *
  1026. * @return boolean TRUE if the class participates in a TABLE_PER_CLASS inheritance mapping,
  1027. * FALSE otherwise.
  1028. */
  1029. public function isInheritanceTypeTablePerClass()
  1030. {
  1031. return $this->inheritanceType == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
  1032. }
  1033. /**
  1034. * Checks whether the class uses an identity column for the Id generation.
  1035. *
  1036. * @return boolean TRUE if the class uses the IDENTITY generator, FALSE otherwise.
  1037. */
  1038. public function isIdGeneratorIdentity()
  1039. {
  1040. return $this->generatorType == self::GENERATOR_TYPE_IDENTITY;
  1041. }
  1042. /**
  1043. * Checks whether the class uses a sequence for id generation.
  1044. *
  1045. * @return boolean TRUE if the class uses the SEQUENCE generator, FALSE otherwise.
  1046. */
  1047. public function isIdGeneratorSequence()
  1048. {
  1049. return $this->generatorType == self::GENERATOR_TYPE_SEQUENCE;
  1050. }
  1051. /**
  1052. * Checks whether the class uses a table for id generation.
  1053. *
  1054. * @return boolean TRUE if the class uses the TABLE generator, FALSE otherwise.
  1055. */
  1056. public function isIdGeneratorTable()
  1057. {
  1058. $this->generatorType == self::GENERATOR_TYPE_TABLE;
  1059. }
  1060. /**
  1061. * Checks whether the class has a natural identifier/pk (which means it does
  1062. * not use any Id generator.
  1063. *
  1064. * @return boolean
  1065. */
  1066. public function isIdentifierNatural()
  1067. {
  1068. return $this->generatorType == self::GENERATOR_TYPE_NONE;
  1069. }
  1070. /**
  1071. * Gets the type of a field.
  1072. *
  1073. * @param string $fieldName
  1074. * @return Doctrine\DBAL\Types\Type
  1075. */
  1076. public function getTypeOfField($fieldName)
  1077. {
  1078. return isset($this->fieldMappings[$fieldName]) ?
  1079. $this->fieldMappings[$fieldName]['type'] : null;
  1080. }
  1081. /**
  1082. * Gets the type of a column.
  1083. *
  1084. * @return Doctrine\DBAL\Types\Type
  1085. */
  1086. public function getTypeOfColumn($columnName)
  1087. {
  1088. return $this->getTypeOfField($this->getFieldName($columnName));
  1089. }
  1090. /**
  1091. * Gets the name of the primary table.
  1092. *
  1093. * @return string
  1094. */
  1095. public function getTableName()
  1096. {
  1097. return $this->table['name'];
  1098. }
  1099. /**
  1100. * Gets the table name to use for temporary identifier tables of this class.
  1101. *
  1102. * @return string
  1103. */
  1104. public function getTemporaryIdTableName()
  1105. {
  1106. return $this->table['name'] . '_id_tmp';
  1107. }
  1108. /**
  1109. * Sets the mapped subclasses of this class.
  1110. *
  1111. * @param array $subclasses The names of all mapped subclasses.
  1112. */
  1113. public function setSubclasses(array $subclasses)
  1114. {
  1115. foreach ($subclasses as $subclass) {
  1116. if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
  1117. $this->subClasses[] = $this->namespace . '\\' . $subclass;
  1118. } else {
  1119. $this->subClasses[] = $subclass;
  1120. }
  1121. }
  1122. }
  1123. /**
  1124. * Sets the parent class names.
  1125. * Assumes that the class names in the passed array are in the order:
  1126. * directParent -> directParentParent -> directParentParentParent ... -> root.
  1127. */
  1128. public function setParentClasses(array $classNames)
  1129. {
  1130. $this->parentClasses = $classNames;
  1131. if (count($classNames) > 0) {
  1132. $this->rootEntityName = array_pop($classNames);
  1133. }
  1134. }
  1135. /**
  1136. * Sets the inheritance type used by the class and it's subclasses.
  1137. *
  1138. * @param integer $type
  1139. */
  1140. public function setInheritanceType($type)
  1141. {
  1142. if ( ! $this->_isInheritanceType($type)) {
  1143. throw MappingException::invalidInheritanceType($this->name, $type);
  1144. }
  1145. $this->inheritanceType = $type;
  1146. }
  1147. /**
  1148. * Checks whether a mapped field is inherited from an entity superclass.
  1149. *
  1150. * @return boolean TRUE if the field is inherited, FALSE otherwise.
  1151. */
  1152. public function isInheritedField($fieldName)
  1153. {
  1154. return isset($this->fieldMappings[$fieldName]['inherited']);
  1155. }
  1156. /**
  1157. * Checks whether a mapped association field is inherited from a superclass.
  1158. *
  1159. * @param string $fieldName
  1160. * @return boolean TRUE if the field is inherited, FALSE otherwise.
  1161. */
  1162. public function isInheritedAssociation($fieldName)
  1163. {
  1164. return isset($this->associationMappings[$fieldName]['inherited']);
  1165. }
  1166. /**
  1167. * Sets the name of the primary table the class is mapped to.
  1168. *
  1169. * @param string $tableName The table name.
  1170. * @deprecated Use {@link setPrimaryTable}.
  1171. */
  1172. public function setTableName($tableName)
  1173. {
  1174. $this->table['name'] = $tableName;
  1175. }
  1176. /**
  1177. * Sets the primary table definition. The provided array supports the
  1178. * following structure:
  1179. *
  1180. * name => <tableName> (optional, defaults to class name)
  1181. * indexes => array of indexes (optional)
  1182. * uniqueConstraints => array of constraints (optional)
  1183. *
  1184. * If a key is omitted, the current value is kept.
  1185. *
  1186. * @param array $table The table description.
  1187. */
  1188. public function setPrimaryTable(array $table)
  1189. {
  1190. if (isset($table['name'])) {
  1191. if ($table['name'][0] == '`') {
  1192. $this->table['name'] = trim($table['name'], '`');
  1193. $this->table['quoted'] = true;
  1194. } else {
  1195. $this->table['name'] = $table['name'];
  1196. }
  1197. }
  1198. if (isset($table['indexes'])) {
  1199. $this->table['indexes'] = $table['indexes'];
  1200. }
  1201. if (isset($table['uniqueConstraints'])) {
  1202. $this->table['uniqueConstraints'] = $table['uniqueConstraints'];
  1203. }
  1204. }
  1205. /**
  1206. * Checks whether the given type identifies an inheritance type.
  1207. *
  1208. * @param integer $type
  1209. * @return boolean TRUE if the given type identifies an inheritance type, FALSe otherwise.
  1210. */
  1211. private function _isInheritanceType($type)
  1212. {
  1213. return $type == self::INHERITANCE_TYPE_NONE ||
  1214. $type == self::INHERITANCE_TYPE_SINGLE_TABLE ||
  1215. $type == self::INHERITANCE_TYPE_JOINED ||
  1216. $type == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
  1217. }
  1218. /**
  1219. * Adds a mapped field to the class.
  1220. *
  1221. * @param array $mapping The field mapping.
  1222. */
  1223. public function mapField(array $mapping)
  1224. {
  1225. $this->_validateAndCompleteFieldMapping($mapping);
  1226. if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationMappings[$mapping['fieldName']])) {
  1227. throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
  1228. }
  1229. $this->fieldMappings[$mapping['fieldName']] = $mapping;
  1230. }
  1231. /**
  1232. * INTERNAL:
  1233. * Adds an association mapping without completing/validating it.
  1234. * This is mainly used to add inherited association mappings to derived classes.
  1235. *
  1236. * @param AssociationMapping $mapping
  1237. * @param string $owningClassName The name of the class that defined this mapping.
  1238. */
  1239. public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
  1240. {
  1241. if (isset($this->associationMappings[$mapping['fieldName']])) {
  1242. throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']);
  1243. }
  1244. $this->associationMappings[$mapping['fieldName']] = $mapping;
  1245. }
  1246. /**
  1247. * INTERNAL:
  1248. * Adds a field mapping without completing/validating it.
  1249. * This is mainly used to add inherited field mappings to derived classes.
  1250. *
  1251. * @param array $mapping
  1252. * @todo Rename: addInheritedFieldMapping
  1253. */
  1254. public function addInheritedFieldMapping(array $fieldMapping)
  1255. {
  1256. $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
  1257. $this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
  1258. $this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
  1259. }
  1260. /**
  1261. * Adds a one-to-one mapping.
  1262. *
  1263. * @param array $mapping The mapping.
  1264. */
  1265. public function mapOneToOne(array $mapping)
  1266. {
  1267. $mapping['type'] = self::ONE_TO_ONE;
  1268. $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
  1269. $this->_storeAssociationMapping($mapping);
  1270. }
  1271. /**
  1272. * Adds a one-to-many mapping.
  1273. *
  1274. * @param array $mapping The mapping.
  1275. */
  1276. public function mapOneToMany(array $mapping)
  1277. {
  1278. $mapping['type'] = self::ONE_TO_MANY;
  1279. $mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
  1280. $this->_storeAssociationMapping($mapping);
  1281. }
  1282. /**
  1283. * Adds a many-to-one mapping.
  1284. *
  1285. * @param array $mapping The mapping.
  1286. */
  1287. public function mapManyToOne(array $mapping)
  1288. {
  1289. $mapping['type'] = self::MANY_TO_ONE;
  1290. // A many-to-one mapping is essentially a one-one backreference
  1291. $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
  1292. $this->_storeAssociationMapping($mapping);
  1293. }
  1294. /**
  1295. * Adds a many-to-many mapping.
  1296. *
  1297. * @param array $mapping The mapping.
  1298. */
  1299. public function mapManyToMany(array $mapping)
  1300. {
  1301. $mapping['type'] = self::MANY_TO_MANY;
  1302. $mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
  1303. $this->_storeAssociationMapping($mapping);
  1304. }
  1305. /**
  1306. * Stores the association mapping.
  1307. *
  1308. * @param AssociationMapping $assocMapping
  1309. */
  1310. protected function _storeAssociationMapping(array $assocMapping)
  1311. {
  1312. $sourceFieldName = $assocMapping['fieldName'];
  1313. if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
  1314. throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
  1315. }
  1316. $this->associationMappings[$sourceFieldName] = $assocMapping;
  1317. }
  1318. /**
  1319. * Registers a custom repository class for the entity class.
  1320. *
  1321. * @param string $mapperClassName The class name of the custom mapper.
  1322. */
  1323. public function setCustomRepositoryClass($repositoryClassName)
  1324. {
  1325. $this->customRepositoryClassName = $repositoryClassName;
  1326. }
  1327. /**
  1328. * Dispatches the lifecycle event of the given entity to the registered
  1329. * lifecycle callbacks and lifecycle listeners.
  1330. *
  1331. * @param string $event The lifecycle event.
  1332. * @param Entity $entity The Entity on which the event occured.
  1333. */
  1334. public function invokeLifecycleCallbacks($lifecycleEvent,

Large files files are truncated, but you can click here to view the full file