vendor/doctrine/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     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\ORM\Mapping;
       
    21 
       
    22 use Doctrine\Common\Persistence\Mapping\ClassMetadata;
       
    23 use ReflectionClass;
       
    24 
       
    25 /**
       
    26  * A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
       
    27  * of an entity and it's associations.
       
    28  *
       
    29  * Once populated, ClassMetadata instances are usually cached in a serialized form.
       
    30  *
       
    31  * <b>IMPORTANT NOTE:</b>
       
    32  *
       
    33  * The fields of this class are only public for 2 reasons:
       
    34  * 1) To allow fast READ access.
       
    35  * 2) To drastically reduce the size of a serialized instance (private/protected members
       
    36  *    get the whole class name, namespace inclusive, prepended to every property in
       
    37  *    the serialized representation).
       
    38  *
       
    39  * @author Roman Borschel <roman@code-factory.org>
       
    40  * @author Jonathan H. Wage <jonwage@gmail.com>
       
    41  * @since 2.0
       
    42  */
       
    43 class ClassMetadataInfo implements ClassMetadata
       
    44 {
       
    45     /* The inheritance mapping types */
       
    46     /**
       
    47      * NONE means the class does not participate in an inheritance hierarchy
       
    48      * and therefore does not need an inheritance mapping type.
       
    49      */
       
    50     const INHERITANCE_TYPE_NONE = 1;
       
    51     /**
       
    52      * JOINED means the class will be persisted according to the rules of
       
    53      * <tt>Class Table Inheritance</tt>.
       
    54      */
       
    55     const INHERITANCE_TYPE_JOINED = 2;
       
    56     /**
       
    57      * SINGLE_TABLE means the class will be persisted according to the rules of
       
    58      * <tt>Single Table Inheritance</tt>.
       
    59      */
       
    60     const INHERITANCE_TYPE_SINGLE_TABLE = 3;
       
    61     /**
       
    62      * TABLE_PER_CLASS means the class will be persisted according to the rules
       
    63      * of <tt>Concrete Table Inheritance</tt>.
       
    64      */
       
    65     const INHERITANCE_TYPE_TABLE_PER_CLASS = 4;
       
    66 
       
    67     /* The Id generator types. */
       
    68     /**
       
    69      * AUTO means the generator type will depend on what the used platform prefers.
       
    70      * Offers full portability.
       
    71      */
       
    72     const GENERATOR_TYPE_AUTO = 1;
       
    73     /**
       
    74      * SEQUENCE means a separate sequence object will be used. Platforms that do
       
    75      * not have native sequence support may emulate it. Full portability is currently
       
    76      * not guaranteed.
       
    77      */
       
    78     const GENERATOR_TYPE_SEQUENCE = 2;
       
    79     /**
       
    80      * TABLE means a separate table is used for id generation.
       
    81      * Offers full portability.
       
    82      */
       
    83     const GENERATOR_TYPE_TABLE = 3;
       
    84     /**
       
    85      * IDENTITY means an identity column is used for id generation. The database
       
    86      * will fill in the id column on insertion. Platforms that do not support
       
    87      * native identity columns may emulate them. Full portability is currently
       
    88      * not guaranteed.
       
    89      */
       
    90     const GENERATOR_TYPE_IDENTITY = 4;
       
    91     /**
       
    92      * NONE means the class does not have a generated id. That means the class
       
    93      * must have a natural, manually assigned id.
       
    94      */
       
    95     const GENERATOR_TYPE_NONE = 5;
       
    96     /**
       
    97      * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
       
    98      * by doing a property-by-property comparison with the original data. This will
       
    99      * be done for all entities that are in MANAGED state at commit-time.
       
   100      *
       
   101      * This is the default change tracking policy.
       
   102      */
       
   103     const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
       
   104     /**
       
   105      * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
       
   106      * by doing a property-by-property comparison with the original data. This will
       
   107      * be done only for entities that were explicitly saved (through persist() or a cascade).
       
   108      */
       
   109     const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
       
   110     /**
       
   111      * NOTIFY means that Doctrine relies on the entities sending out notifications
       
   112      * when their properties change. Such entity classes must implement
       
   113      * the <tt>NotifyPropertyChanged</tt> interface.
       
   114      */
       
   115     const CHANGETRACKING_NOTIFY = 3;
       
   116     /**
       
   117      * Specifies that an association is to be fetched when it is first accessed.
       
   118      */
       
   119     const FETCH_LAZY = 2;
       
   120     /**
       
   121      * Specifies that an association is to be fetched when the owner of the
       
   122      * association is fetched. 
       
   123      */
       
   124     const FETCH_EAGER = 3;
       
   125     /**
       
   126      * Specifies that an association is to be fetched lazy (on first access) and that
       
   127      * commands such as Collection#count, Collection#slice are issued directly against
       
   128      * the database if the collection is not yet initialized.
       
   129      */
       
   130     const FETCH_EXTRA_LAZY = 4;
       
   131     /**
       
   132      * Identifies a one-to-one association.
       
   133      */
       
   134     const ONE_TO_ONE = 1;
       
   135     /**
       
   136      * Identifies a many-to-one association.
       
   137      */
       
   138     const MANY_TO_ONE = 2;
       
   139     /**
       
   140      * Combined bitmask for to-one (single-valued) associations.
       
   141      */
       
   142     const TO_ONE = 3;
       
   143     /**
       
   144      * Identifies a one-to-many association.
       
   145      */
       
   146     const ONE_TO_MANY = 4;
       
   147     /**
       
   148      * Identifies a many-to-many association.
       
   149      */
       
   150     const MANY_TO_MANY = 8;
       
   151     /**
       
   152      * Combined bitmask for to-many (collection-valued) associations.
       
   153      */
       
   154     const TO_MANY = 12;
       
   155 
       
   156     /**
       
   157      * READ-ONLY: The name of the entity class.
       
   158      */
       
   159     public $name;
       
   160 
       
   161     /**
       
   162      * READ-ONLY: The namespace the entity class is contained in.
       
   163      *
       
   164      * @var string
       
   165      * @todo Not really needed. Usage could be localized.
       
   166      */
       
   167     public $namespace;
       
   168 
       
   169     /**
       
   170      * READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance
       
   171      * hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
       
   172      * as {@link $entityName}.
       
   173      *
       
   174      * @var string
       
   175      */
       
   176     public $rootEntityName;
       
   177 
       
   178     /**
       
   179      * The name of the custom repository class used for the entity class.
       
   180      * (Optional).
       
   181      *
       
   182      * @var string
       
   183      */
       
   184     public $customRepositoryClassName;
       
   185 
       
   186     /**
       
   187      * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
       
   188      *
       
   189      * @var boolean
       
   190      */
       
   191     public $isMappedSuperclass = false;
       
   192 
       
   193     /**
       
   194      * READ-ONLY: The names of the parent classes (ancestors).
       
   195      *
       
   196      * @var array
       
   197      */
       
   198     public $parentClasses = array();
       
   199 
       
   200     /**
       
   201      * READ-ONLY: The names of all subclasses (descendants).
       
   202      *
       
   203      * @var array
       
   204      */
       
   205     public $subClasses = array();
       
   206 
       
   207     /**
       
   208      * READ-ONLY: The named queries allowed to be called directly from Repository.
       
   209      * 
       
   210      * @var array
       
   211      */
       
   212     public $namedQueries = array();
       
   213 
       
   214     /**
       
   215      * READ-ONLY: The field names of all fields that are part of the identifier/primary key
       
   216      * of the mapped entity class.
       
   217      *
       
   218      * @var array
       
   219      */
       
   220     public $identifier = array();
       
   221 
       
   222     /**
       
   223      * READ-ONLY: The inheritance mapping type used by the class.
       
   224      *
       
   225      * @var integer
       
   226      */
       
   227     public $inheritanceType = self::INHERITANCE_TYPE_NONE;
       
   228 
       
   229     /**
       
   230      * READ-ONLY: The Id generator type used by the class.
       
   231      *
       
   232      * @var string
       
   233      */
       
   234     public $generatorType = self::GENERATOR_TYPE_NONE;
       
   235 
       
   236     /**
       
   237      * READ-ONLY: The field mappings of the class.
       
   238      * Keys are field names and values are mapping definitions.
       
   239      *
       
   240      * The mapping definition array has the following values:
       
   241      *
       
   242      * - <b>fieldName</b> (string)
       
   243      * The name of the field in the Entity.
       
   244      *
       
   245      * - <b>type</b> (string)
       
   246      * The type name of the mapped field. Can be one of Doctrine's mapping types
       
   247      * or a custom mapping type.
       
   248      *
       
   249      * - <b>columnName</b> (string, optional)
       
   250      * The column name. Optional. Defaults to the field name.
       
   251      *
       
   252      * - <b>length</b> (integer, optional)
       
   253      * The database length of the column. Optional. Default value taken from
       
   254      * the type.
       
   255      *
       
   256      * - <b>id</b> (boolean, optional)
       
   257      * Marks the field as the primary key of the entity. Multiple fields of an
       
   258      * entity can have the id attribute, forming a composite key.
       
   259      *
       
   260      * - <b>nullable</b> (boolean, optional)
       
   261      * Whether the column is nullable. Defaults to FALSE.
       
   262      *
       
   263      * - <b>columnDefinition</b> (string, optional, schema-only)
       
   264      * The SQL fragment that is used when generating the DDL for the column.
       
   265      *
       
   266      * - <b>precision</b> (integer, optional, schema-only)
       
   267      * The precision of a decimal column. Only valid if the column type is decimal.
       
   268      *
       
   269      * - <b>scale</b> (integer, optional, schema-only)
       
   270      * The scale of a decimal column. Only valid if the column type is decimal.
       
   271      *
       
   272      [* - <b>'unique'] (string, optional, schema-only)</b>
       
   273      * Whether a unique constraint should be generated for the column.
       
   274      *
       
   275      * @var array
       
   276      */
       
   277     public $fieldMappings = array();
       
   278 
       
   279     /**
       
   280      * READ-ONLY: An array of field names. Used to look up field names from column names.
       
   281      * Keys are column names and values are field names.
       
   282      * This is the reverse lookup map of $_columnNames.
       
   283      *
       
   284      * @var array
       
   285      */
       
   286     public $fieldNames = array();
       
   287 
       
   288     /**
       
   289      * READ-ONLY: A map of field names to column names. Keys are field names and values column names.
       
   290      * Used to look up column names from field names.
       
   291      * This is the reverse lookup map of $_fieldNames.
       
   292      *
       
   293      * @var array
       
   294      * @todo We could get rid of this array by just using $fieldMappings[$fieldName]['columnName'].
       
   295      */
       
   296     public $columnNames = array();
       
   297 
       
   298     /**
       
   299      * READ-ONLY: The discriminator value of this class.
       
   300      *
       
   301      * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
       
   302      * where a discriminator column is used.</b>
       
   303      *
       
   304      * @var mixed
       
   305      * @see discriminatorColumn
       
   306      */
       
   307     public $discriminatorValue;
       
   308 
       
   309     /**
       
   310      * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
       
   311      *
       
   312      * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
       
   313      * where a discriminator column is used.</b>
       
   314      *
       
   315      * @var mixed
       
   316      * @see discriminatorColumn
       
   317      */
       
   318     public $discriminatorMap = array();
       
   319 
       
   320     /**
       
   321      * READ-ONLY: The definition of the descriminator column used in JOINED and SINGLE_TABLE
       
   322      * inheritance mappings.
       
   323      *
       
   324      * @var array
       
   325      */
       
   326     public $discriminatorColumn;
       
   327 
       
   328     /**
       
   329      * READ-ONLY: The primary table definition. The definition is an array with the
       
   330      * following entries:
       
   331      *
       
   332      * name => <tableName>
       
   333      * schema => <schemaName>
       
   334      * indexes => array
       
   335      * uniqueConstraints => array
       
   336      *
       
   337      * @var array
       
   338      */
       
   339     public $table;
       
   340 
       
   341     /**
       
   342      * READ-ONLY: The registered lifecycle callbacks for entities of this class.
       
   343      *
       
   344      * @var array
       
   345      */
       
   346     public $lifecycleCallbacks = array();
       
   347 
       
   348     /**
       
   349      * READ-ONLY: The association mappings of this class.
       
   350      *
       
   351      * The mapping definition array supports the following keys:
       
   352      *
       
   353      * - <b>fieldName</b> (string)
       
   354      * The name of the field in the entity the association is mapped to.
       
   355      *
       
   356      * - <b>targetEntity</b> (string)
       
   357      * The class name of the target entity. If it is fully-qualified it is used as is.
       
   358      * If it is a simple, unqualified class name the namespace is assumed to be the same
       
   359      * as the namespace of the source entity.
       
   360      *
       
   361      * - <b>mappedBy</b> (string, required for bidirectional associations)
       
   362      * The name of the field that completes the bidirectional association on the owning side.
       
   363      * This key must be specified on the inverse side of a bidirectional association.
       
   364      * 
       
   365      * - <b>inversedBy</b> (string, required for bidirectional associations)
       
   366      * The name of the field that completes the bidirectional association on the inverse side.
       
   367      * This key must be specified on the owning side of a bidirectional association.
       
   368      *
       
   369      * - <b>cascade</b> (array, optional)
       
   370      * The names of persistence operations to cascade on the association. The set of possible
       
   371      * values are: "persist", "remove", "detach", "merge", "refresh", "all" (implies all others).
       
   372      *
       
   373      * - <b>orderBy</b> (array, one-to-many/many-to-many only)
       
   374      * A map of field names (of the target entity) to sorting directions (ASC/DESC).
       
   375      * Example: array('priority' => 'desc')
       
   376      *
       
   377      * - <b>fetch</b> (integer, optional)
       
   378      * The fetching strategy to use for the association, usually defaults to FETCH_LAZY.
       
   379      * Possible values are: ClassMetadata::FETCH_EAGER, ClassMetadata::FETCH_LAZY.
       
   380      *
       
   381      * - <b>joinTable</b> (array, optional, many-to-many only)
       
   382      * Specification of the join table and its join columns (foreign keys).
       
   383      * Only valid for many-to-many mappings. Note that one-to-many associations can be mapped
       
   384      * through a join table by simply mapping the association as many-to-many with a unique
       
   385      * constraint on the join table.
       
   386      *
       
   387      * - <b>indexBy</b> (string, optional, to-many only)
       
   388      * Specification of a field on target-entity that is used to index the collection by.
       
   389      * This field HAS to be either the primary key or a unique column. Otherwise the collection
       
   390      * does not contain all the entities that are actually related.
       
   391      * 
       
   392      * A join table definition has the following structure:
       
   393      * <pre>
       
   394      * array(
       
   395      *     'name' => <join table name>,
       
   396      *      'joinColumns' => array(<join column mapping from join table to source table>),
       
   397      *      'inverseJoinColumns' => array(<join column mapping from join table to target table>)
       
   398      * )
       
   399      * </pre>
       
   400      *
       
   401      *
       
   402      * @var array
       
   403      */
       
   404     public $associationMappings = array();
       
   405 
       
   406     /**
       
   407      * READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite.
       
   408      *
       
   409      * @var boolean
       
   410      */
       
   411     public $isIdentifierComposite = false;
       
   412 
       
   413     /**
       
   414      * READ-ONLY: Flag indicating wheather the identifier/primary key contains at least one foreign key association.
       
   415      *
       
   416      * This flag is necessary because some code blocks require special treatment of this cases.
       
   417      *
       
   418      * @var boolean
       
   419      */
       
   420     public $containsForeignIdentifier = false;
       
   421 
       
   422     /**
       
   423      * READ-ONLY: The ID generator used for generating IDs for this class.
       
   424      *
       
   425      * @var AbstractIdGenerator
       
   426      * @todo Remove!
       
   427      */
       
   428     public $idGenerator;
       
   429 
       
   430     /**
       
   431      * READ-ONLY: The definition of the sequence generator of this class. Only used for the
       
   432      * SEQUENCE generation strategy.
       
   433      * 
       
   434      * The definition has the following structure:
       
   435      * <code>
       
   436      * array(
       
   437      *     'sequenceName' => 'name',
       
   438      *     'allocationSize' => 20,
       
   439      *     'initialValue' => 1
       
   440      * )
       
   441      * </code>
       
   442      *
       
   443      * @var array
       
   444      * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
       
   445      */
       
   446     public $sequenceGeneratorDefinition;
       
   447 
       
   448     /**
       
   449      * READ-ONLY: The definition of the table generator of this class. Only used for the
       
   450      * TABLE generation strategy.
       
   451      *
       
   452      * @var array
       
   453      * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
       
   454      */
       
   455     public $tableGeneratorDefinition;
       
   456 
       
   457     /**
       
   458      * READ-ONLY: The policy used for change-tracking on entities of this class.
       
   459      *
       
   460      * @var integer
       
   461      */
       
   462     public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
       
   463 
       
   464     /**
       
   465      * READ-ONLY: A flag for whether or not instances of this class are to be versioned
       
   466      * with optimistic locking.
       
   467      *
       
   468      * @var boolean $isVersioned
       
   469      */
       
   470     public $isVersioned;
       
   471 
       
   472     /**
       
   473      * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
       
   474      *
       
   475      * @var mixed $versionField
       
   476      */
       
   477     public $versionField;
       
   478 
       
   479     /**
       
   480      * The ReflectionClass instance of the mapped class.
       
   481      *
       
   482      * @var ReflectionClass
       
   483      */
       
   484     public $reflClass;
       
   485 
       
   486     /**
       
   487      * Is this entity marked as "read-only"?
       
   488      *
       
   489      * That means it is never considered for change-tracking in the UnitOfWork. It is a very helpful performance
       
   490      * optimization for entities that are immutable, either in your domain or through the relation database
       
   491      * (coming from a view, or a history table for example).
       
   492      *
       
   493      * @var bool
       
   494      */
       
   495     public $isReadOnly = false;
       
   496 
       
   497     /**
       
   498      * Initializes a new ClassMetadata instance that will hold the object-relational mapping
       
   499      * metadata of the class with the given name.
       
   500      *
       
   501      * @param string $entityName The name of the entity class the new instance is used for.
       
   502      */
       
   503     public function __construct($entityName)
       
   504     {
       
   505         $this->name = $entityName;
       
   506         $this->rootEntityName = $entityName;
       
   507     }
       
   508 
       
   509     /**
       
   510      * Gets the ReflectionClass instance of the mapped class.
       
   511      *
       
   512      * @return ReflectionClass
       
   513      */
       
   514     public function getReflectionClass()
       
   515     {
       
   516         if ( ! $this->reflClass) {
       
   517             $this->reflClass = new ReflectionClass($this->name);
       
   518         }
       
   519         return $this->reflClass;
       
   520     }
       
   521 
       
   522     /**
       
   523      * Sets the change tracking policy used by this class.
       
   524      *
       
   525      * @param integer $policy
       
   526      */
       
   527     public function setChangeTrackingPolicy($policy)
       
   528     {
       
   529         $this->changeTrackingPolicy = $policy;
       
   530     }
       
   531 
       
   532     /**
       
   533      * Whether the change tracking policy of this class is "deferred explicit".
       
   534      *
       
   535      * @return boolean
       
   536      */
       
   537     public function isChangeTrackingDeferredExplicit()
       
   538     {
       
   539         return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
       
   540     }
       
   541 
       
   542     /**
       
   543      * Whether the change tracking policy of this class is "deferred implicit".
       
   544      *
       
   545      * @return boolean
       
   546      */
       
   547     public function isChangeTrackingDeferredImplicit()
       
   548     {
       
   549         return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
       
   550     }
       
   551 
       
   552     /**
       
   553      * Whether the change tracking policy of this class is "notify".
       
   554      *
       
   555      * @return boolean
       
   556      */
       
   557     public function isChangeTrackingNotify()
       
   558     {
       
   559         return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
       
   560     }
       
   561 
       
   562     /**
       
   563      * Checks whether a field is part of the identifier/primary key field(s).
       
   564      *
       
   565      * @param string $fieldName  The field name
       
   566      * @return boolean  TRUE if the field is part of the table identifier/primary key field(s),
       
   567      *                  FALSE otherwise.
       
   568      */
       
   569     public function isIdentifier($fieldName)
       
   570     {
       
   571         if ( ! $this->isIdentifierComposite) {
       
   572             return $fieldName === $this->identifier[0];
       
   573         }
       
   574         return in_array($fieldName, $this->identifier);
       
   575     }
       
   576 
       
   577     /**
       
   578      * Check if the field is unique.
       
   579      *
       
   580      * @param string $fieldName  The field name
       
   581      * @return boolean  TRUE if the field is unique, FALSE otherwise.
       
   582      */
       
   583     public function isUniqueField($fieldName)
       
   584     {
       
   585         $mapping = $this->getFieldMapping($fieldName);
       
   586         if ($mapping !== false) {
       
   587             return isset($mapping['unique']) && $mapping['unique'] == true;
       
   588         }
       
   589         return false;
       
   590     }
       
   591 
       
   592     /**
       
   593      * Check if the field is not null.
       
   594      *
       
   595      * @param string $fieldName  The field name
       
   596      * @return boolean  TRUE if the field is not null, FALSE otherwise.
       
   597      */
       
   598     public function isNullable($fieldName)
       
   599     {
       
   600         $mapping = $this->getFieldMapping($fieldName);
       
   601         if ($mapping !== false) {
       
   602             return isset($mapping['nullable']) && $mapping['nullable'] == true;
       
   603         }
       
   604         return false;
       
   605     }
       
   606 
       
   607     /**
       
   608      * Gets a column name for a field name.
       
   609      * If the column name for the field cannot be found, the given field name
       
   610      * is returned.
       
   611      *
       
   612      * @param string $fieldName The field name.
       
   613      * @return string  The column name.
       
   614      */
       
   615     public function getColumnName($fieldName)
       
   616     {
       
   617         return isset($this->columnNames[$fieldName]) ?
       
   618                 $this->columnNames[$fieldName] : $fieldName;
       
   619     }
       
   620 
       
   621     /**
       
   622      * Gets the mapping of a (regular) field that holds some data but not a
       
   623      * reference to another object.
       
   624      *
       
   625      * @param string $fieldName  The field name.
       
   626      * @return array  The field mapping.
       
   627      */
       
   628     public function getFieldMapping($fieldName)
       
   629     {
       
   630         if ( ! isset($this->fieldMappings[$fieldName])) {
       
   631             throw MappingException::mappingNotFound($this->name, $fieldName);
       
   632         }
       
   633         return $this->fieldMappings[$fieldName];
       
   634     }
       
   635 
       
   636     /**
       
   637      * Gets the mapping of an association.
       
   638      *
       
   639      * @see ClassMetadataInfo::$associationMappings
       
   640      * @param string $fieldName  The field name that represents the association in
       
   641      *                           the object model.
       
   642      * @return array The mapping.
       
   643      */
       
   644     public function getAssociationMapping($fieldName)
       
   645     {
       
   646         if ( ! isset($this->associationMappings[$fieldName])) {
       
   647             throw MappingException::mappingNotFound($this->name, $fieldName);
       
   648         }
       
   649         return $this->associationMappings[$fieldName];
       
   650     }
       
   651 
       
   652     /**
       
   653      * Gets all association mappings of the class.
       
   654      *
       
   655      * @return array
       
   656      */
       
   657     public function getAssociationMappings()
       
   658     {
       
   659         return $this->associationMappings;
       
   660     }
       
   661 
       
   662     /**
       
   663      * Gets the field name for a column name.
       
   664      * If no field name can be found the column name is returned.
       
   665      *
       
   666      * @param string $columnName    column name
       
   667      * @return string               column alias
       
   668      */
       
   669     public function getFieldName($columnName)
       
   670     {
       
   671         return isset($this->fieldNames[$columnName]) ?
       
   672                 $this->fieldNames[$columnName] : $columnName;
       
   673     }
       
   674 
       
   675     /**
       
   676      * Gets the named query.
       
   677      *
       
   678      * @see ClassMetadataInfo::$namedQueries
       
   679      * @throws MappingException
       
   680      * @param string $queryName The query name
       
   681      * @return string
       
   682      */
       
   683     public function getNamedQuery($queryName)
       
   684     {
       
   685         if ( ! isset($this->namedQueries[$queryName])) {
       
   686             throw MappingException::queryNotFound($this->name, $queryName);
       
   687         }
       
   688         return $this->namedQueries[$queryName];
       
   689     }
       
   690 
       
   691     /**
       
   692      * Gets all named queries of the class.
       
   693      *
       
   694      * @return array
       
   695      */
       
   696     public function getNamedQueries()
       
   697     {
       
   698         return $this->namedQueries;
       
   699     }
       
   700 
       
   701     /**
       
   702      * Validates & completes the given field mapping.
       
   703      *
       
   704      * @param array $mapping  The field mapping to validated & complete.
       
   705      * @return array  The validated and completed field mapping.
       
   706      */
       
   707     protected function _validateAndCompleteFieldMapping(array &$mapping)
       
   708     {
       
   709         // Check mandatory fields
       
   710         if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
       
   711             throw MappingException::missingFieldName($this->name);
       
   712         }
       
   713         if ( ! isset($mapping['type'])) {
       
   714             // Default to string
       
   715             $mapping['type'] = 'string';
       
   716         }
       
   717 
       
   718         // Complete fieldName and columnName mapping
       
   719         if ( ! isset($mapping['columnName'])) {
       
   720             $mapping['columnName'] = $mapping['fieldName'];
       
   721         } else {
       
   722             if ($mapping['columnName'][0] == '`') {
       
   723                 $mapping['columnName'] = trim($mapping['columnName'], '`');
       
   724                 $mapping['quoted'] = true;
       
   725             }
       
   726         }
       
   727 
       
   728         $this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
       
   729         if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn != null && $this->discriminatorColumn['name'] == $mapping['columnName'])) {
       
   730             throw MappingException::duplicateColumnName($this->name, $mapping['columnName']);
       
   731         }
       
   732 
       
   733         $this->fieldNames[$mapping['columnName']] = $mapping['fieldName'];
       
   734 
       
   735         // Complete id mapping
       
   736         if (isset($mapping['id']) && $mapping['id'] === true) {
       
   737             if ($this->versionField == $mapping['fieldName']) {
       
   738                 throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']);
       
   739             }
       
   740 
       
   741             if ( ! in_array($mapping['fieldName'], $this->identifier)) {
       
   742                 $this->identifier[] = $mapping['fieldName'];
       
   743             }
       
   744             // Check for composite key
       
   745             if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
       
   746                 $this->isIdentifierComposite = true;
       
   747             }
       
   748         }
       
   749     }
       
   750 
       
   751     /**
       
   752      * Validates & completes the basic mapping information that is common to all
       
   753      * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
       
   754      *
       
   755      * @param array $mapping The mapping.
       
   756      * @return array The updated mapping.
       
   757      * @throws MappingException If something is wrong with the mapping.
       
   758      */
       
   759     protected function _validateAndCompleteAssociationMapping(array $mapping)
       
   760     {
       
   761         if ( ! isset($mapping['mappedBy'])) {
       
   762             $mapping['mappedBy'] = null;
       
   763         }
       
   764         if ( ! isset($mapping['inversedBy'])) {
       
   765             $mapping['inversedBy'] = null;
       
   766         }
       
   767         $mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
       
   768 
       
   769         // unset optional indexBy attribute if its empty
       
   770         if (!isset($mapping['indexBy']) || !$mapping['indexBy']) {
       
   771             unset($mapping['indexBy']);
       
   772         }
       
   773 
       
   774         // If targetEntity is unqualified, assume it is in the same namespace as
       
   775         // the sourceEntity.
       
   776         $mapping['sourceEntity'] = $this->name;
       
   777         if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false
       
   778                 && strlen($this->namespace) > 0) {
       
   779             $mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
       
   780         }
       
   781 
       
   782         // Complete id mapping
       
   783         if (isset($mapping['id']) && $mapping['id'] === true) {
       
   784             if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
       
   785                 throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']);
       
   786             }
       
   787 
       
   788             if ( ! in_array($mapping['fieldName'], $this->identifier)) {
       
   789                 if (count($mapping['joinColumns']) >= 2) {
       
   790                     throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
       
   791                         $mapping['targetEntity'], $this->name, $mapping['fieldName']
       
   792                     );
       
   793                 }
       
   794 
       
   795                 $this->identifier[] = $mapping['fieldName'];
       
   796                 $this->containsForeignIdentifier = true;
       
   797             }
       
   798             // Check for composite key
       
   799             if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
       
   800                 $this->isIdentifierComposite = true;
       
   801             }
       
   802         }
       
   803 
       
   804         // Mandatory attributes for both sides
       
   805         // Mandatory: fieldName, targetEntity
       
   806         if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
       
   807             throw MappingException::missingFieldName($this->name);
       
   808         }
       
   809         if ( ! isset($mapping['targetEntity'])) {
       
   810             throw MappingException::missingTargetEntity($mapping['fieldName']);
       
   811         }
       
   812         
       
   813         // Mandatory and optional attributes for either side
       
   814         if ( ! $mapping['mappedBy']) {
       
   815             if (isset($mapping['joinTable']) && $mapping['joinTable']) {
       
   816                 if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] == '`') {
       
   817                     $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
       
   818                     $mapping['joinTable']['quoted'] = true;
       
   819                 }
       
   820             }
       
   821         } else {
       
   822             $mapping['isOwningSide'] = false;
       
   823         }
       
   824 
       
   825         if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) {
       
   826             throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']);
       
   827         }
       
   828         
       
   829         // Fetch mode. Default fetch mode to LAZY, if not set.
       
   830         if ( ! isset($mapping['fetch'])) {
       
   831             $mapping['fetch'] = self::FETCH_LAZY;
       
   832         }
       
   833 
       
   834         // Cascades
       
   835         $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
       
   836         if (in_array('all', $cascades)) {
       
   837             $cascades = array(
       
   838                'remove',
       
   839                'persist',
       
   840                'refresh',
       
   841                'merge',
       
   842                'detach'
       
   843             );
       
   844         }
       
   845         $mapping['cascade'] = $cascades;
       
   846         $mapping['isCascadeRemove'] = in_array('remove',  $cascades);
       
   847         $mapping['isCascadePersist'] = in_array('persist',  $cascades);
       
   848         $mapping['isCascadeRefresh'] = in_array('refresh',  $cascades);
       
   849         $mapping['isCascadeMerge'] = in_array('merge',  $cascades);
       
   850         $mapping['isCascadeDetach'] = in_array('detach',  $cascades);
       
   851         
       
   852         return $mapping;
       
   853     }
       
   854 
       
   855     /**
       
   856      * Validates & completes a one-to-one association mapping.
       
   857      *
       
   858      * @param array $mapping  The mapping to validate & complete.
       
   859      * @return array The validated & completed mapping.
       
   860      * @override
       
   861      */
       
   862     protected function _validateAndCompleteOneToOneMapping(array $mapping)
       
   863     {
       
   864         $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
       
   865         
       
   866         if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
       
   867             $mapping['isOwningSide'] = true;
       
   868         }
       
   869         
       
   870         if ($mapping['isOwningSide']) {
       
   871             if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
       
   872                 // Apply default join column
       
   873                 $mapping['joinColumns'] = array(array(
       
   874                     'name' => $mapping['fieldName'] . '_id',
       
   875                     'referencedColumnName' => 'id'
       
   876                 ));
       
   877             }
       
   878 
       
   879             $uniqueContraintColumns = array();
       
   880             foreach ($mapping['joinColumns'] as $key => &$joinColumn) {
       
   881                 if ($mapping['type'] === self::ONE_TO_ONE) {
       
   882                     if (count($mapping['joinColumns']) == 1) {
       
   883                         $joinColumn['unique'] = true;
       
   884                     } else {
       
   885                         $uniqueContraintColumns[] = $joinColumn['name'];
       
   886                     }
       
   887                 }
       
   888                 if (empty($joinColumn['name'])) {
       
   889                     $joinColumn['name'] = $mapping['fieldName'] . '_id';
       
   890                 }
       
   891                 if (empty($joinColumn['referencedColumnName'])) {
       
   892                     $joinColumn['referencedColumnName'] = 'id';
       
   893                 }
       
   894                 $mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
       
   895                 $mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
       
   896                         ? $joinColumn['fieldName'] : $joinColumn['name'];
       
   897             }
       
   898 
       
   899             if ($uniqueContraintColumns) {
       
   900                 if (!$this->table) {
       
   901                     throw new \RuntimeException("ClassMetadataInfo::setTable() has to be called before defining a one to one relationship.");
       
   902                 }
       
   903                 $this->table['uniqueConstraints'][$mapping['fieldName']."_uniq"] = array(
       
   904                     'columns' => $uniqueContraintColumns
       
   905                 );
       
   906             }
       
   907 
       
   908             $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
       
   909         }
       
   910 
       
   911         //TODO: if orphanRemoval, cascade=remove is implicit!
       
   912         $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
       
   913                 (bool) $mapping['orphanRemoval'] : false;
       
   914 
       
   915         if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
       
   916             throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']);
       
   917         }
       
   918 
       
   919         return $mapping;
       
   920     }
       
   921 
       
   922     /**
       
   923      * Validates and completes the mapping.
       
   924      *
       
   925      * @param array $mapping The mapping to validate and complete.
       
   926      * @return array The validated and completed mapping.
       
   927      * @override
       
   928      */
       
   929     protected function _validateAndCompleteOneToManyMapping(array $mapping)
       
   930     {
       
   931         $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
       
   932 
       
   933         // OneToMany-side MUST be inverse (must have mappedBy)
       
   934         if ( ! isset($mapping['mappedBy'])) {
       
   935             throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
       
   936         }
       
   937         
       
   938         //TODO: if orphanRemoval, cascade=remove is implicit!
       
   939         $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
       
   940                 (bool) $mapping['orphanRemoval'] : false;
       
   941 
       
   942         if (isset($mapping['orderBy'])) {
       
   943             if ( ! is_array($mapping['orderBy'])) {
       
   944                 throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
       
   945             }
       
   946         }
       
   947         
       
   948         return $mapping;
       
   949     }
       
   950 
       
   951     protected function _validateAndCompleteManyToManyMapping(array $mapping)
       
   952     {
       
   953         $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
       
   954         if ($mapping['isOwningSide']) {
       
   955             if (strpos($mapping['sourceEntity'], '\\') !== false) {
       
   956                 $sourceShortName = strtolower(substr($mapping['sourceEntity'], strrpos($mapping['sourceEntity'], '\\') + 1));
       
   957             } else {
       
   958                 $sourceShortName = strtolower($mapping['sourceEntity']);
       
   959             }
       
   960             if (strpos($mapping['targetEntity'], '\\') !== false) {
       
   961                 $targetShortName = strtolower(substr($mapping['targetEntity'], strrpos($mapping['targetEntity'], '\\') + 1));
       
   962             } else {
       
   963                 $targetShortName = strtolower($mapping['targetEntity']);
       
   964             }
       
   965             
       
   966             // owning side MUST have a join table
       
   967             if ( ! isset($mapping['joinTable']['name'])) {
       
   968                 $mapping['joinTable']['name'] = $sourceShortName .'_' . $targetShortName;
       
   969             }
       
   970             if ( ! isset($mapping['joinTable']['joinColumns'])) {
       
   971                 $mapping['joinTable']['joinColumns'] = array(array(
       
   972                         'name' => $sourceShortName . '_id',
       
   973                         'referencedColumnName' => 'id',
       
   974                         'onDelete' => 'CASCADE'));
       
   975             }
       
   976             if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
       
   977                 $mapping['joinTable']['inverseJoinColumns'] = array(array(
       
   978                         'name' => $targetShortName . '_id',
       
   979                         'referencedColumnName' => 'id',
       
   980                         'onDelete' => 'CASCADE'));
       
   981             }
       
   982 
       
   983             foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
       
   984                 if (empty($joinColumn['name'])) {
       
   985                     $joinColumn['name'] = $sourceShortName . '_id';
       
   986                 }
       
   987                 if (empty($joinColumn['referencedColumnName'])) {
       
   988                     $joinColumn['referencedColumnName'] = 'id';
       
   989                 }
       
   990                 if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
       
   991                     $mapping['isOnDeleteCascade'] = true;
       
   992                 }
       
   993                 $mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
       
   994                 $mapping['joinTableColumns'][] = $joinColumn['name'];
       
   995             }
       
   996 
       
   997             foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
       
   998                 if (empty($inverseJoinColumn['name'])) {
       
   999                     $inverseJoinColumn['name'] = $targetShortName . '_id';
       
  1000                 }
       
  1001                 if (empty($inverseJoinColumn['referencedColumnName'])) {
       
  1002                     $inverseJoinColumn['referencedColumnName'] = 'id';
       
  1003                 }
       
  1004                 if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
       
  1005                     $mapping['isOnDeleteCascade'] = true;
       
  1006                 }
       
  1007                 $mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
       
  1008                 $mapping['joinTableColumns'][] = $inverseJoinColumn['name'];
       
  1009             }
       
  1010         }
       
  1011 
       
  1012         if (isset($mapping['orderBy'])) {
       
  1013             if ( ! is_array($mapping['orderBy'])) {
       
  1014                 throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
       
  1015             }
       
  1016         }
       
  1017 
       
  1018         return $mapping;
       
  1019     }
       
  1020 
       
  1021     /**
       
  1022      * Gets the identifier (primary key) field names of the class.
       
  1023      *
       
  1024      * @return mixed
       
  1025      */
       
  1026     public function getIdentifierFieldNames()
       
  1027     {
       
  1028         return $this->identifier;
       
  1029     }
       
  1030 
       
  1031     /**
       
  1032      * Gets the name of the single id field. Note that this only works on
       
  1033      * entity classes that have a single-field pk.
       
  1034      *
       
  1035      * @return string
       
  1036      * @throws MappingException If the class has a composite primary key.
       
  1037      */
       
  1038     public function getSingleIdentifierFieldName()
       
  1039     {
       
  1040         if ($this->isIdentifierComposite) {
       
  1041             throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name);
       
  1042         }
       
  1043         return $this->identifier[0];
       
  1044     }
       
  1045 
       
  1046     /**
       
  1047      * Gets the column name of the single id column. Note that this only works on
       
  1048      * entity classes that have a single-field pk.
       
  1049      *
       
  1050      * @return string
       
  1051      * @throws MappingException If the class has a composite primary key.
       
  1052      */
       
  1053     public function getSingleIdentifierColumnName()
       
  1054     {
       
  1055         return $this->getColumnName($this->getSingleIdentifierFieldName());
       
  1056     }
       
  1057 
       
  1058     /**
       
  1059      * INTERNAL:
       
  1060      * Sets the mapped identifier/primary key fields of this class.
       
  1061      * Mainly used by the ClassMetadataFactory to assign inherited identifiers.
       
  1062      *
       
  1063      * @param array $identifier
       
  1064      */
       
  1065     public function setIdentifier(array $identifier)
       
  1066     {
       
  1067         $this->identifier = $identifier;
       
  1068         $this->isIdentifierComposite = (count($this->identifier) > 1);
       
  1069     }
       
  1070 
       
  1071     /**
       
  1072      * Gets the mapped identifier field of this class.
       
  1073      *
       
  1074      * @return string $identifier
       
  1075      */
       
  1076     public function getIdentifier()
       
  1077     {
       
  1078         return $this->identifier;
       
  1079     }
       
  1080 
       
  1081     /**
       
  1082      * Checks whether the class has a (mapped) field with a certain name.
       
  1083      *
       
  1084      * @return boolean
       
  1085      */
       
  1086     public function hasField($fieldName)
       
  1087     {
       
  1088         return isset($this->fieldMappings[$fieldName]);
       
  1089     }
       
  1090 
       
  1091     /**
       
  1092      * Gets an array containing all the column names.
       
  1093      *
       
  1094      * @return array
       
  1095      */
       
  1096     public function getColumnNames(array $fieldNames = null)
       
  1097     {
       
  1098         if ($fieldNames === null) {
       
  1099             return array_keys($this->fieldNames);
       
  1100         } else {
       
  1101             $columnNames = array();
       
  1102             foreach ($fieldNames as $fieldName) {
       
  1103                 $columnNames[] = $this->getColumnName($fieldName);
       
  1104             }
       
  1105             return $columnNames;
       
  1106         }
       
  1107     }
       
  1108 
       
  1109     /**
       
  1110      * Returns an array with all the identifier column names.
       
  1111      *
       
  1112      * @return array
       
  1113      */
       
  1114     public function getIdentifierColumnNames()
       
  1115     {
       
  1116         if ($this->isIdentifierComposite) {
       
  1117             $columnNames = array();
       
  1118             foreach ($this->identifier as $idField) {
       
  1119                 if (isset($this->associationMappings[$idField])) {
       
  1120                     // no composite pk as fk entity assumption:
       
  1121                     $columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
       
  1122                 } else {
       
  1123                     $columnNames[] = $this->fieldMappings[$idField]['columnName'];
       
  1124                 }
       
  1125             }
       
  1126             return $columnNames;
       
  1127         } else if(isset($this->fieldMappings[$this->identifier[0]])) {
       
  1128             return array($this->fieldMappings[$this->identifier[0]]['columnName']);
       
  1129         } else {
       
  1130             // no composite pk as fk entity assumption:
       
  1131             return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']);
       
  1132         }
       
  1133     }
       
  1134 
       
  1135     /**
       
  1136      * Sets the type of Id generator to use for the mapped class.
       
  1137      */
       
  1138     public function setIdGeneratorType($generatorType)
       
  1139     {
       
  1140         $this->generatorType = $generatorType;
       
  1141     }
       
  1142 
       
  1143     /**
       
  1144      * Checks whether the mapped class uses an Id generator.
       
  1145      *
       
  1146      * @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
       
  1147      */
       
  1148     public function usesIdGenerator()
       
  1149     {
       
  1150         return $this->generatorType != self::GENERATOR_TYPE_NONE;
       
  1151     }
       
  1152 
       
  1153     /**
       
  1154      * @return boolean
       
  1155      */
       
  1156     public function isInheritanceTypeNone()
       
  1157     {
       
  1158         return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
       
  1159     }
       
  1160 
       
  1161     /**
       
  1162      * Checks whether the mapped class uses the JOINED inheritance mapping strategy.
       
  1163      *
       
  1164      * @return boolean TRUE if the class participates in a JOINED inheritance mapping,
       
  1165      *                 FALSE otherwise.
       
  1166      */
       
  1167     public function isInheritanceTypeJoined()
       
  1168     {
       
  1169         return $this->inheritanceType == self::INHERITANCE_TYPE_JOINED;
       
  1170     }
       
  1171 
       
  1172     /**
       
  1173      * Checks whether the mapped class uses the SINGLE_TABLE inheritance mapping strategy.
       
  1174      *
       
  1175      * @return boolean TRUE if the class participates in a SINGLE_TABLE inheritance mapping,
       
  1176      *                 FALSE otherwise.
       
  1177      */
       
  1178     public function isInheritanceTypeSingleTable()
       
  1179     {
       
  1180         return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_TABLE;
       
  1181     }
       
  1182 
       
  1183     /**
       
  1184      * Checks whether the mapped class uses the TABLE_PER_CLASS inheritance mapping strategy.
       
  1185      *
       
  1186      * @return boolean TRUE if the class participates in a TABLE_PER_CLASS inheritance mapping,
       
  1187      *                 FALSE otherwise.
       
  1188      */
       
  1189     public function isInheritanceTypeTablePerClass()
       
  1190     {
       
  1191         return $this->inheritanceType == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
       
  1192     }
       
  1193 
       
  1194     /**
       
  1195      * Checks whether the class uses an identity column for the Id generation.
       
  1196      *
       
  1197      * @return boolean TRUE if the class uses the IDENTITY generator, FALSE otherwise.
       
  1198      */
       
  1199     public function isIdGeneratorIdentity()
       
  1200     {
       
  1201         return $this->generatorType == self::GENERATOR_TYPE_IDENTITY;
       
  1202     }
       
  1203 
       
  1204     /**
       
  1205      * Checks whether the class uses a sequence for id generation.
       
  1206      *
       
  1207      * @return boolean TRUE if the class uses the SEQUENCE generator, FALSE otherwise.
       
  1208      */
       
  1209     public function isIdGeneratorSequence()
       
  1210     {
       
  1211         return $this->generatorType == self::GENERATOR_TYPE_SEQUENCE;
       
  1212     }
       
  1213 
       
  1214     /**
       
  1215      * Checks whether the class uses a table for id generation.
       
  1216      *
       
  1217      * @return boolean  TRUE if the class uses the TABLE generator, FALSE otherwise.
       
  1218      */
       
  1219     public function isIdGeneratorTable()
       
  1220     {
       
  1221         $this->generatorType == self::GENERATOR_TYPE_TABLE;
       
  1222     }
       
  1223 
       
  1224     /**
       
  1225      * Checks whether the class has a natural identifier/pk (which means it does
       
  1226      * not use any Id generator.
       
  1227      *
       
  1228      * @return boolean
       
  1229      */
       
  1230     public function isIdentifierNatural()
       
  1231     {
       
  1232         return $this->generatorType == self::GENERATOR_TYPE_NONE;
       
  1233     }
       
  1234 
       
  1235     /**
       
  1236      * Gets the type of a field.
       
  1237      *
       
  1238      * @param string $fieldName
       
  1239      * @return Doctrine\DBAL\Types\Type
       
  1240      */
       
  1241     public function getTypeOfField($fieldName)
       
  1242     {
       
  1243         return isset($this->fieldMappings[$fieldName]) ?
       
  1244                 $this->fieldMappings[$fieldName]['type'] : null;
       
  1245     }
       
  1246 
       
  1247     /**
       
  1248      * Gets the type of a column.
       
  1249      *
       
  1250      * @return Doctrine\DBAL\Types\Type
       
  1251      */
       
  1252     public function getTypeOfColumn($columnName)
       
  1253     {
       
  1254         return $this->getTypeOfField($this->getFieldName($columnName));
       
  1255     }
       
  1256 
       
  1257     /**
       
  1258      * Gets the name of the primary table.
       
  1259      *
       
  1260      * @return string
       
  1261      */
       
  1262     public function getTableName()
       
  1263     {
       
  1264         return $this->table['name'];
       
  1265     }
       
  1266 
       
  1267     /**
       
  1268      * Gets the table name to use for temporary identifier tables of this class.
       
  1269      *
       
  1270      * @return string
       
  1271      */
       
  1272     public function getTemporaryIdTableName()
       
  1273     {
       
  1274         // replace dots with underscores because PostgreSQL creates temporary tables in a special schema
       
  1275         return str_replace('.', '_', $this->table['name'] . '_id_tmp');
       
  1276     }
       
  1277 
       
  1278     /**
       
  1279      * Sets the mapped subclasses of this class.
       
  1280      *
       
  1281      * @param array $subclasses The names of all mapped subclasses.
       
  1282      */
       
  1283     public function setSubclasses(array $subclasses)
       
  1284     {
       
  1285         foreach ($subclasses as $subclass) {
       
  1286             if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
       
  1287                 $this->subClasses[] = $this->namespace . '\\' . $subclass;
       
  1288             } else {
       
  1289                 $this->subClasses[] = $subclass;
       
  1290             }
       
  1291         }
       
  1292     }
       
  1293 
       
  1294     /**
       
  1295      * Sets the parent class names.
       
  1296      * Assumes that the class names in the passed array are in the order:
       
  1297      * directParent -> directParentParent -> directParentParentParent ... -> root.
       
  1298      */
       
  1299     public function setParentClasses(array $classNames)
       
  1300     {
       
  1301         $this->parentClasses = $classNames;
       
  1302         if (count($classNames) > 0) {
       
  1303             $this->rootEntityName = array_pop($classNames);
       
  1304         }
       
  1305     }
       
  1306 
       
  1307     /**
       
  1308      * Sets the inheritance type used by the class and it's subclasses.
       
  1309      *
       
  1310      * @param integer $type
       
  1311      */
       
  1312     public function setInheritanceType($type)
       
  1313     {
       
  1314         if ( ! $this->_isInheritanceType($type)) {
       
  1315             throw MappingException::invalidInheritanceType($this->name, $type);
       
  1316         }
       
  1317         $this->inheritanceType = $type;
       
  1318     }
       
  1319 
       
  1320     /**
       
  1321      * Checks whether a mapped field is inherited from an entity superclass.
       
  1322      *
       
  1323      * @return boolean TRUE if the field is inherited, FALSE otherwise.
       
  1324      */
       
  1325     public function isInheritedField($fieldName)
       
  1326     {
       
  1327         return isset($this->fieldMappings[$fieldName]['inherited']);
       
  1328     }
       
  1329 
       
  1330     /**
       
  1331      * Checks whether a mapped association field is inherited from a superclass.
       
  1332      *
       
  1333      * @param string $fieldName
       
  1334      * @return boolean TRUE if the field is inherited, FALSE otherwise.
       
  1335      */
       
  1336     public function isInheritedAssociation($fieldName)
       
  1337     {
       
  1338         return isset($this->associationMappings[$fieldName]['inherited']);
       
  1339     }
       
  1340 
       
  1341     /**
       
  1342      * Sets the name of the primary table the class is mapped to.
       
  1343      *
       
  1344      * @param string $tableName The table name.
       
  1345      * @deprecated Use {@link setPrimaryTable}.
       
  1346      */
       
  1347     public function setTableName($tableName)
       
  1348     {
       
  1349         $this->table['name'] = $tableName;
       
  1350     }
       
  1351 
       
  1352     /**
       
  1353      * Sets the primary table definition. The provided array supports the
       
  1354      * following structure:
       
  1355      *
       
  1356      * name => <tableName> (optional, defaults to class name)
       
  1357      * indexes => array of indexes (optional)
       
  1358      * uniqueConstraints => array of constraints (optional)
       
  1359      *
       
  1360      * If a key is omitted, the current value is kept.
       
  1361      *
       
  1362      * @param array $table The table description.
       
  1363      */
       
  1364     public function setPrimaryTable(array $table)
       
  1365     {
       
  1366         if (isset($table['name'])) {
       
  1367             if ($table['name'][0] == '`') {
       
  1368                 $this->table['name'] = trim($table['name'], '`');
       
  1369                 $this->table['quoted'] = true;
       
  1370             } else {
       
  1371                 $this->table['name'] = $table['name'];
       
  1372             }
       
  1373         }
       
  1374         if (isset($table['indexes'])) {
       
  1375             $this->table['indexes'] = $table['indexes'];
       
  1376         }
       
  1377         if (isset($table['uniqueConstraints'])) {
       
  1378             $this->table['uniqueConstraints'] = $table['uniqueConstraints'];
       
  1379         }
       
  1380     }
       
  1381 
       
  1382     /**
       
  1383      * Checks whether the given type identifies an inheritance type.
       
  1384      *
       
  1385      * @param integer $type
       
  1386      * @return boolean TRUE if the given type identifies an inheritance type, FALSe otherwise.
       
  1387      */
       
  1388     private function _isInheritanceType($type)
       
  1389     {
       
  1390         return $type == self::INHERITANCE_TYPE_NONE ||
       
  1391                 $type == self::INHERITANCE_TYPE_SINGLE_TABLE ||
       
  1392                 $type == self::INHERITANCE_TYPE_JOINED ||
       
  1393                 $type == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
       
  1394     }
       
  1395 
       
  1396     /**
       
  1397      * Adds a mapped field to the class.
       
  1398      *
       
  1399      * @param array $mapping The field mapping.
       
  1400      */
       
  1401     public function mapField(array $mapping)
       
  1402     {
       
  1403         $this->_validateAndCompleteFieldMapping($mapping);
       
  1404         if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationMappings[$mapping['fieldName']])) {
       
  1405             throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
       
  1406         }
       
  1407         $this->fieldMappings[$mapping['fieldName']] = $mapping;
       
  1408     }
       
  1409 
       
  1410     /**
       
  1411      * INTERNAL:
       
  1412      * Adds an association mapping without completing/validating it.
       
  1413      * This is mainly used to add inherited association mappings to derived classes.
       
  1414      *
       
  1415      * @param array $mapping
       
  1416      */
       
  1417     public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
       
  1418     {
       
  1419         if (isset($this->associationMappings[$mapping['fieldName']])) {
       
  1420             throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']);
       
  1421         }
       
  1422         $this->associationMappings[$mapping['fieldName']] = $mapping;
       
  1423     }
       
  1424 
       
  1425     /**
       
  1426      * INTERNAL:
       
  1427      * Adds a field mapping without completing/validating it.
       
  1428      * This is mainly used to add inherited field mappings to derived classes.
       
  1429      *
       
  1430      * @param array $mapping
       
  1431      */
       
  1432     public function addInheritedFieldMapping(array $fieldMapping)
       
  1433     {
       
  1434         $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
       
  1435         $this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
       
  1436         $this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
       
  1437     }
       
  1438 
       
  1439     /**
       
  1440      * INTERNAL:
       
  1441      * Adds a named query to this class.
       
  1442      *
       
  1443      * @throws MappingException
       
  1444      * @param array $queryMapping
       
  1445      */
       
  1446     public function addNamedQuery(array $queryMapping)
       
  1447     {
       
  1448         if (isset($this->namedQueries[$queryMapping['name']])) {
       
  1449             throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
       
  1450         }
       
  1451         $query = str_replace('__CLASS__', $this->name, $queryMapping['query']);
       
  1452         $this->namedQueries[$queryMapping['name']] = $query;
       
  1453     }
       
  1454 
       
  1455     /**
       
  1456      * Adds a one-to-one mapping.
       
  1457      *
       
  1458      * @param array $mapping The mapping.
       
  1459      */
       
  1460     public function mapOneToOne(array $mapping)
       
  1461     {
       
  1462         $mapping['type'] = self::ONE_TO_ONE;
       
  1463         $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
       
  1464         $this->_storeAssociationMapping($mapping);
       
  1465     }
       
  1466 
       
  1467     /**
       
  1468      * Adds a one-to-many mapping.
       
  1469      *
       
  1470      * @param array $mapping The mapping.
       
  1471      */
       
  1472     public function mapOneToMany(array $mapping)
       
  1473     {
       
  1474         $mapping['type'] = self::ONE_TO_MANY;
       
  1475         $mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
       
  1476         $this->_storeAssociationMapping($mapping);
       
  1477     }
       
  1478 
       
  1479     /**
       
  1480      * Adds a many-to-one mapping.
       
  1481      *
       
  1482      * @param array $mapping The mapping.
       
  1483      */
       
  1484     public function mapManyToOne(array $mapping)
       
  1485     {
       
  1486         $mapping['type'] = self::MANY_TO_ONE;
       
  1487         // A many-to-one mapping is essentially a one-one backreference
       
  1488         $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
       
  1489         $this->_storeAssociationMapping($mapping);
       
  1490     }
       
  1491 
       
  1492     /**
       
  1493      * Adds a many-to-many mapping.
       
  1494      *
       
  1495      * @param array $mapping The mapping.
       
  1496      */
       
  1497     public function mapManyToMany(array $mapping)
       
  1498     {
       
  1499         $mapping['type'] = self::MANY_TO_MANY;
       
  1500         $mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
       
  1501         $this->_storeAssociationMapping($mapping);
       
  1502     }
       
  1503 
       
  1504     /**
       
  1505      * Stores the association mapping.
       
  1506      *
       
  1507      * @param AssociationMapping $assocMapping
       
  1508      */
       
  1509     protected function _storeAssociationMapping(array $assocMapping)
       
  1510     {
       
  1511         $sourceFieldName = $assocMapping['fieldName'];
       
  1512         if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
       
  1513             throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
       
  1514         }
       
  1515         $this->associationMappings[$sourceFieldName] = $assocMapping;
       
  1516     }
       
  1517 
       
  1518     /**
       
  1519      * Registers a custom repository class for the entity class.
       
  1520      *
       
  1521      * @param string $mapperClassName  The class name of the custom mapper.
       
  1522      */
       
  1523     public function setCustomRepositoryClass($repositoryClassName)
       
  1524     {
       
  1525         $this->customRepositoryClassName = $repositoryClassName;
       
  1526     }
       
  1527 
       
  1528     /**
       
  1529      * Dispatches the lifecycle event of the given entity to the registered
       
  1530      * lifecycle callbacks and lifecycle listeners.
       
  1531      *
       
  1532      * @param string $event The lifecycle event.
       
  1533      * @param Entity $entity The Entity on which the event occured.
       
  1534      */
       
  1535     public function invokeLifecycleCallbacks($lifecycleEvent, $entity)
       
  1536     {
       
  1537         foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) {
       
  1538             $entity->$callback();
       
  1539         }
       
  1540     }
       
  1541 
       
  1542     /**
       
  1543      * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
       
  1544      *
       
  1545      * @param string $lifecycleEvent
       
  1546      * @return boolean
       
  1547      */
       
  1548     public function hasLifecycleCallbacks($lifecycleEvent)
       
  1549     {
       
  1550         return isset($this->lifecycleCallbacks[$lifecycleEvent]);
       
  1551     }
       
  1552 
       
  1553     /**
       
  1554      * Gets the registered lifecycle callbacks for an event.
       
  1555      *
       
  1556      * @param string $event
       
  1557      * @return array
       
  1558      */
       
  1559     public function getLifecycleCallbacks($event)
       
  1560     {
       
  1561         return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
       
  1562     }
       
  1563 
       
  1564     /**
       
  1565      * Adds a lifecycle callback for entities of this class.
       
  1566      *
       
  1567      * Note: If the same callback is registered more than once, the old one
       
  1568      * will be overridden.
       
  1569      *
       
  1570      * @param string $callback
       
  1571      * @param string $event
       
  1572      */
       
  1573     public function addLifecycleCallback($callback, $event)
       
  1574     {
       
  1575         $this->lifecycleCallbacks[$event][] = $callback;
       
  1576     }
       
  1577 
       
  1578     /**
       
  1579      * Sets the lifecycle callbacks for entities of this class.
       
  1580      * Any previously registered callbacks are overwritten.
       
  1581      *
       
  1582      * @param array $callbacks
       
  1583      */
       
  1584     public function setLifecycleCallbacks(array $callbacks)
       
  1585     {
       
  1586         $this->lifecycleCallbacks = $callbacks;
       
  1587     }
       
  1588 
       
  1589     /**
       
  1590      * Sets the discriminator column definition.
       
  1591      *
       
  1592      * @param array $columnDef
       
  1593      * @see getDiscriminatorColumn()
       
  1594      */
       
  1595     public function setDiscriminatorColumn($columnDef)
       
  1596     {
       
  1597         if ($columnDef !== null) {
       
  1598             if (isset($this->fieldNames[$columnDef['name']])) {
       
  1599                 throw MappingException::duplicateColumnName($this->name, $columnDef['name']);
       
  1600             }
       
  1601 
       
  1602             if ( ! isset($columnDef['name'])) {
       
  1603                 throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name, $columnDef);
       
  1604             }
       
  1605             if ( ! isset($columnDef['fieldName'])) {
       
  1606                 $columnDef['fieldName'] = $columnDef['name'];
       
  1607             }
       
  1608             if ( ! isset($columnDef['type'])) {
       
  1609                 $columnDef['type'] = "string";
       
  1610             }
       
  1611             if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) {
       
  1612                 throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
       
  1613             }
       
  1614 
       
  1615             $this->discriminatorColumn = $columnDef;
       
  1616         }
       
  1617     }
       
  1618 
       
  1619     /**
       
  1620      * Sets the discriminator values used by this class.
       
  1621      * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
       
  1622      *
       
  1623      * @param array $map
       
  1624      */
       
  1625     public function setDiscriminatorMap(array $map)
       
  1626     {
       
  1627         foreach ($map as $value => $className) {
       
  1628             if (strpos($className, '\\') === false && strlen($this->namespace)) {
       
  1629                 $className = $this->namespace . '\\' . $className;
       
  1630             }
       
  1631             $className = ltrim($className, '\\');
       
  1632             $this->discriminatorMap[$value] = $className;
       
  1633             if ($this->name == $className) {
       
  1634                 $this->discriminatorValue = $value;
       
  1635             } else {
       
  1636                 if ( ! class_exists($className)) {
       
  1637                     throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
       
  1638                 }
       
  1639                 if (is_subclass_of($className, $this->name)) {
       
  1640                     $this->subClasses[] = $className;
       
  1641                 }
       
  1642             }
       
  1643         }
       
  1644     }
       
  1645 
       
  1646     /**
       
  1647      * Checks whether the class has a named query with the given query name.
       
  1648      *
       
  1649      * @param string $fieldName
       
  1650      * @return boolean
       
  1651      */
       
  1652     public function hasNamedQuery($queryName)
       
  1653     {
       
  1654         return isset($this->namedQueries[$queryName]);
       
  1655     }
       
  1656 
       
  1657     /**
       
  1658      * Checks whether the class has a mapped association with the given field name.
       
  1659      *
       
  1660      * @param string $fieldName
       
  1661      * @return boolean
       
  1662      */
       
  1663     public function hasAssociation($fieldName)
       
  1664     {
       
  1665         return isset($this->associationMappings[$fieldName]);
       
  1666     }
       
  1667 
       
  1668     /**
       
  1669      * Checks whether the class has a mapped association for the specified field
       
  1670      * and if yes, checks whether it is a single-valued association (to-one).
       
  1671      *
       
  1672      * @param string $fieldName
       
  1673      * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
       
  1674      */
       
  1675     public function isSingleValuedAssociation($fieldName)
       
  1676     {
       
  1677         return isset($this->associationMappings[$fieldName]) &&
       
  1678                 ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
       
  1679     }
       
  1680 
       
  1681     /**
       
  1682      * Checks whether the class has a mapped association for the specified field
       
  1683      * and if yes, checks whether it is a collection-valued association (to-many).
       
  1684      *
       
  1685      * @param string $fieldName
       
  1686      * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
       
  1687      */
       
  1688     public function isCollectionValuedAssociation($fieldName)
       
  1689     {
       
  1690         return isset($this->associationMappings[$fieldName]) &&
       
  1691                 ! ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
       
  1692     }
       
  1693 
       
  1694     /**
       
  1695      * Is this an association that only has a single join column?
       
  1696      *
       
  1697      * @param  string $fieldName
       
  1698      * @return bool
       
  1699      */
       
  1700     public function isAssociationWithSingleJoinColumn($fieldName)
       
  1701     {
       
  1702         return (
       
  1703             isset($this->associationMappings[$fieldName]) &&
       
  1704             isset($this->associationMappings[$fieldName]['joinColumns'][0]) &&
       
  1705             !isset($this->associationMappings[$fieldName]['joinColumns'][1])
       
  1706         );
       
  1707     }
       
  1708 
       
  1709     /**
       
  1710      * Return the single association join column (if any).
       
  1711      * 
       
  1712      * @param string $fieldName
       
  1713      * @return string
       
  1714      */
       
  1715     public function getSingleAssociationJoinColumnName($fieldName)
       
  1716     {
       
  1717         if (!$this->isAssociationWithSingleJoinColumn($fieldName)) {
       
  1718             throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
       
  1719         }
       
  1720         return $this->associationMappings[$fieldName]['joinColumns'][0]['name'];
       
  1721     }
       
  1722 
       
  1723     /**
       
  1724      * Return the single association referenced join column name (if any).
       
  1725      *
       
  1726      * @param string $fieldName
       
  1727      * @return string
       
  1728      */
       
  1729     public function getSingleAssociationReferencedJoinColumnName($fieldName)
       
  1730     {
       
  1731         if (!$this->isAssociationWithSingleJoinColumn($fieldName)) {
       
  1732             throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
       
  1733         }
       
  1734         return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName'];
       
  1735     }
       
  1736 
       
  1737     /**
       
  1738      * Used to retrieve a fieldname for either field or association from a given column,
       
  1739      *
       
  1740      * This method is used in foreign-key as primary-key contexts.
       
  1741      *
       
  1742      * @param  string $columnName
       
  1743      * @return string
       
  1744      */
       
  1745     public function getFieldForColumn($columnName)
       
  1746     {
       
  1747         if (isset($this->fieldNames[$columnName])) {
       
  1748             return $this->fieldNames[$columnName];
       
  1749         } else {
       
  1750             foreach ($this->associationMappings AS $assocName => $mapping) {
       
  1751                 if ($this->isAssociationWithSingleJoinColumn($assocName) &&
       
  1752                     $this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
       
  1753                     
       
  1754                     return $assocName;
       
  1755                 }
       
  1756             }
       
  1757 
       
  1758             throw MappingException::noFieldNameFoundForColumn($this->name, $columnName);
       
  1759         }
       
  1760     }
       
  1761 
       
  1762     /**
       
  1763      * Sets the ID generator used to generate IDs for instances of this class.
       
  1764      *
       
  1765      * @param AbstractIdGenerator $generator
       
  1766      */
       
  1767     public function setIdGenerator($generator)
       
  1768     {
       
  1769         $this->idGenerator = $generator;
       
  1770     }
       
  1771 
       
  1772     /**
       
  1773      * Sets the definition of the sequence ID generator for this class.
       
  1774      *
       
  1775      * The definition must have the following structure:
       
  1776      * <code>
       
  1777      * array(
       
  1778      *     'sequenceName' => 'name',
       
  1779      *     'allocationSize' => 20,
       
  1780      *     'initialValue' => 1
       
  1781      * )
       
  1782      * </code>
       
  1783      *
       
  1784      * @param array $definition
       
  1785      */
       
  1786     public function setSequenceGeneratorDefinition(array $definition)
       
  1787     {
       
  1788         $this->sequenceGeneratorDefinition = $definition;
       
  1789     }
       
  1790 
       
  1791     /**
       
  1792      * Sets the version field mapping used for versioning. Sets the default
       
  1793      * value to use depending on the column type.
       
  1794      *
       
  1795      * @param array $mapping   The version field mapping array
       
  1796      */
       
  1797     public function setVersionMapping(array &$mapping)
       
  1798     {
       
  1799         $this->isVersioned = true;
       
  1800         $this->versionField = $mapping['fieldName'];
       
  1801 
       
  1802         if ( ! isset($mapping['default'])) {
       
  1803             if ($mapping['type'] == 'integer') {
       
  1804                 $mapping['default'] = 1;
       
  1805             } else if ($mapping['type'] == 'datetime') {
       
  1806                 $mapping['default'] = 'CURRENT_TIMESTAMP';
       
  1807             } else {
       
  1808                 throw MappingException::unsupportedOptimisticLockingType($this->name, $mapping['fieldName'], $mapping['type']);
       
  1809             }
       
  1810         }
       
  1811     }
       
  1812 
       
  1813     /**
       
  1814      * Sets whether this class is to be versioned for optimistic locking.
       
  1815      *
       
  1816      * @param boolean $bool
       
  1817      */
       
  1818     public function setVersioned($bool)
       
  1819     {
       
  1820         $this->isVersioned = $bool;
       
  1821     }
       
  1822 
       
  1823     /**
       
  1824      * Sets the name of the field that is to be used for versioning if this class is
       
  1825      * versioned for optimistic locking.
       
  1826      *
       
  1827      * @param string $versionField
       
  1828      */
       
  1829     public function setVersionField($versionField)
       
  1830     {
       
  1831         $this->versionField = $versionField;
       
  1832     }
       
  1833 
       
  1834     /**
       
  1835      * Mark this class as read only, no change tracking is applied to it.
       
  1836      *
       
  1837      * @return void
       
  1838      */
       
  1839     public function markReadOnly()
       
  1840     {
       
  1841         $this->isReadOnly = true;
       
  1842     }
       
  1843     
       
  1844     /**
       
  1845      * A numerically indexed list of field names of this persistent class.
       
  1846      * 
       
  1847      * This array includes identifier fields if present on this class.
       
  1848      * 
       
  1849      * @return array
       
  1850      */
       
  1851     public function getFieldNames()
       
  1852     {
       
  1853         return array_keys($this->fieldMappings);
       
  1854     }
       
  1855     
       
  1856     /**
       
  1857      * A numerically indexed list of association names of this persistent class.
       
  1858      * 
       
  1859      * This array includes identifier associations if present on this class.
       
  1860      * 
       
  1861      * @return array
       
  1862      */
       
  1863     public function getAssociationNames()
       
  1864     {
       
  1865         return array_keys($this->associationMappings);
       
  1866     }
       
  1867     
       
  1868     /**
       
  1869      * Returns the target class name of the given association.
       
  1870      * 
       
  1871      * @param string $assocName
       
  1872      * @return string
       
  1873      */
       
  1874     public function getAssociationTargetClass($assocName)
       
  1875     {
       
  1876         if (!isset($this->associationMappings[$assocName])) {
       
  1877             throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
       
  1878         }
       
  1879         return $this->associationMappings[$assocName]['targetEntity'];
       
  1880     }
       
  1881     
       
  1882     /**
       
  1883      * Get fully-qualified class name of this persistent class.
       
  1884      * 
       
  1885      * @return string
       
  1886      */
       
  1887     public function getName()
       
  1888     {
       
  1889         return $this->name;
       
  1890     }
       
  1891 
       
  1892     /**
       
  1893      * Gets the (possibly quoted) column name of a mapped field for safe use
       
  1894      * in an SQL statement.
       
  1895      * 
       
  1896      * @param string $field
       
  1897      * @param AbstractPlatform $platform
       
  1898      * @return string
       
  1899      */
       
  1900     public function getQuotedColumnName($field, $platform)
       
  1901     {
       
  1902         return isset($this->fieldMappings[$field]['quoted']) ?
       
  1903                 $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) :
       
  1904                 $this->fieldMappings[$field]['columnName'];
       
  1905     }
       
  1906     
       
  1907     /**
       
  1908      * Gets the (possibly quoted) primary table name of this class for safe use
       
  1909      * in an SQL statement.
       
  1910      * 
       
  1911      * @param AbstractPlatform $platform
       
  1912      * @return string
       
  1913      */
       
  1914     public function getQuotedTableName($platform)
       
  1915     {
       
  1916         return isset($this->table['quoted']) ?
       
  1917                 $platform->quoteIdentifier($this->table['name']) :
       
  1918                 $this->table['name'];
       
  1919     }
       
  1920 
       
  1921     /**
       
  1922      * Gets the (possibly quoted) name of the join table.
       
  1923      *
       
  1924      * @param AbstractPlatform $platform
       
  1925      * @return string
       
  1926      */
       
  1927     public function getQuotedJoinTableName(array $assoc, $platform)
       
  1928     {
       
  1929         return isset($assoc['joinTable']['quoted'])
       
  1930             ? $platform->quoteIdentifier($assoc['joinTable']['name'])
       
  1931             : $assoc['joinTable']['name'];
       
  1932     }
       
  1933 }