ClassMetadataInfo.php 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820
  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 MIT license. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\ORM\Mapping;
  20. use BadMethodCallException;
  21. use InvalidArgumentException;
  22. use RuntimeException;
  23. use Doctrine\DBAL\Types\Type;
  24. use ReflectionClass;
  25. use Doctrine\Common\Persistence\Mapping\ClassMetadata;
  26. use Doctrine\Common\ClassLoader;
  27. /**
  28. * A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
  29. * of an entity and it's associations.
  30. *
  31. * Once populated, ClassMetadata instances are usually cached in a serialized form.
  32. *
  33. * <b>IMPORTANT NOTE:</b>
  34. *
  35. * The fields of this class are only public for 2 reasons:
  36. * 1) To allow fast READ access.
  37. * 2) To drastically reduce the size of a serialized instance (private/protected members
  38. * get the whole class name, namespace inclusive, prepended to every property in
  39. * the serialized representation).
  40. *
  41. * @author Roman Borschel <roman@code-factory.org>
  42. * @author Jonathan H. Wage <jonwage@gmail.com>
  43. * @since 2.0
  44. */
  45. class ClassMetadataInfo implements ClassMetadata
  46. {
  47. /* The inheritance mapping types */
  48. /**
  49. * NONE means the class does not participate in an inheritance hierarchy
  50. * and therefore does not need an inheritance mapping type.
  51. */
  52. const INHERITANCE_TYPE_NONE = 1;
  53. /**
  54. * JOINED means the class will be persisted according to the rules of
  55. * <tt>Class Table Inheritance</tt>.
  56. */
  57. const INHERITANCE_TYPE_JOINED = 2;
  58. /**
  59. * SINGLE_TABLE means the class will be persisted according to the rules of
  60. * <tt>Single Table Inheritance</tt>.
  61. */
  62. const INHERITANCE_TYPE_SINGLE_TABLE = 3;
  63. /**
  64. * TABLE_PER_CLASS means the class will be persisted according to the rules
  65. * of <tt>Concrete Table Inheritance</tt>.
  66. */
  67. const INHERITANCE_TYPE_TABLE_PER_CLASS = 4;
  68. /* The Id generator types. */
  69. /**
  70. * AUTO means the generator type will depend on what the used platform prefers.
  71. * Offers full portability.
  72. */
  73. const GENERATOR_TYPE_AUTO = 1;
  74. /**
  75. * SEQUENCE means a separate sequence object will be used. Platforms that do
  76. * not have native sequence support may emulate it. Full portability is currently
  77. * not guaranteed.
  78. */
  79. const GENERATOR_TYPE_SEQUENCE = 2;
  80. /**
  81. * TABLE means a separate table is used for id generation.
  82. * Offers full portability.
  83. */
  84. const GENERATOR_TYPE_TABLE = 3;
  85. /**
  86. * IDENTITY means an identity column is used for id generation. The database
  87. * will fill in the id column on insertion. Platforms that do not support
  88. * native identity columns may emulate them. Full portability is currently
  89. * not guaranteed.
  90. */
  91. const GENERATOR_TYPE_IDENTITY = 4;
  92. /**
  93. * NONE means the class does not have a generated id. That means the class
  94. * must have a natural, manually assigned id.
  95. */
  96. const GENERATOR_TYPE_NONE = 5;
  97. /**
  98. * UUID means that a UUID/GUID expression is used for id generation. Full
  99. * portability is currently not guaranteed.
  100. */
  101. const GENERATOR_TYPE_UUID = 6;
  102. /**
  103. * CUSTOM means that customer will use own ID generator that supposedly work
  104. */
  105. const GENERATOR_TYPE_CUSTOM = 7;
  106. /**
  107. * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
  108. * by doing a property-by-property comparison with the original data. This will
  109. * be done for all entities that are in MANAGED state at commit-time.
  110. *
  111. * This is the default change tracking policy.
  112. */
  113. const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
  114. /**
  115. * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
  116. * by doing a property-by-property comparison with the original data. This will
  117. * be done only for entities that were explicitly saved (through persist() or a cascade).
  118. */
  119. const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
  120. /**
  121. * NOTIFY means that Doctrine relies on the entities sending out notifications
  122. * when their properties change. Such entity classes must implement
  123. * the <tt>NotifyPropertyChanged</tt> interface.
  124. */
  125. const CHANGETRACKING_NOTIFY = 3;
  126. /**
  127. * Specifies that an association is to be fetched when it is first accessed.
  128. */
  129. const FETCH_LAZY = 2;
  130. /**
  131. * Specifies that an association is to be fetched when the owner of the
  132. * association is fetched.
  133. */
  134. const FETCH_EAGER = 3;
  135. /**
  136. * Specifies that an association is to be fetched lazy (on first access) and that
  137. * commands such as Collection#count, Collection#slice are issued directly against
  138. * the database if the collection is not yet initialized.
  139. */
  140. const FETCH_EXTRA_LAZY = 4;
  141. /**
  142. * Identifies a one-to-one association.
  143. */
  144. const ONE_TO_ONE = 1;
  145. /**
  146. * Identifies a many-to-one association.
  147. */
  148. const MANY_TO_ONE = 2;
  149. /**
  150. * Identifies a one-to-many association.
  151. */
  152. const ONE_TO_MANY = 4;
  153. /**
  154. * Identifies a many-to-many association.
  155. */
  156. const MANY_TO_MANY = 8;
  157. /**
  158. * Combined bitmask for to-one (single-valued) associations.
  159. */
  160. const TO_ONE = 3;
  161. /**
  162. * Combined bitmask for to-many (collection-valued) associations.
  163. */
  164. const TO_MANY = 12;
  165. /**
  166. * READ-ONLY: The name of the entity class.
  167. */
  168. public $name;
  169. /**
  170. * READ-ONLY: The namespace the entity class is contained in.
  171. *
  172. * @var string
  173. * @todo Not really needed. Usage could be localized.
  174. */
  175. public $namespace;
  176. /**
  177. * READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance
  178. * hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
  179. * as {@link $entityName}.
  180. *
  181. * @var string
  182. */
  183. public $rootEntityName;
  184. /**
  185. * READ-ONLY: The definition of custom generator. Only used for CUSTOM
  186. * generator type
  187. *
  188. * The definition has the following structure:
  189. * <code>
  190. * array(
  191. * 'class' => 'ClassName',
  192. * )
  193. * </code>
  194. *
  195. * @var array
  196. * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
  197. */
  198. public $customGeneratorDefinition;
  199. /**
  200. * The name of the custom repository class used for the entity class.
  201. * (Optional).
  202. *
  203. * @var string
  204. */
  205. public $customRepositoryClassName;
  206. /**
  207. * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
  208. *
  209. * @var boolean
  210. */
  211. public $isMappedSuperclass = false;
  212. /**
  213. * READ-ONLY: The names of the parent classes (ancestors).
  214. *
  215. * @var array
  216. */
  217. public $parentClasses = array();
  218. /**
  219. * READ-ONLY: The names of all subclasses (descendants).
  220. *
  221. * @var array
  222. */
  223. public $subClasses = array();
  224. /**
  225. * READ-ONLY: The named queries allowed to be called directly from Repository.
  226. *
  227. * @var array
  228. */
  229. public $namedQueries = array();
  230. /**
  231. * READ-ONLY: The named native queries allowed to be called directly from Repository.
  232. *
  233. * A native SQL named query definition has the following structure:
  234. * <pre>
  235. * array(
  236. * 'name' => <query name>,
  237. * 'query' => <sql query>,
  238. * 'resultClass' => <class of the result>,
  239. * 'resultSetMapping' => <name of a SqlResultSetMapping>
  240. * )
  241. * </pre>
  242. */
  243. public $namedNativeQueries = array();
  244. /**
  245. * READ-ONLY: The mappings of the results of native SQL queries.
  246. *
  247. * A native result mapping definition has the following structure:
  248. * <pre>
  249. * array(
  250. * 'name' => <result name>,
  251. * 'entities' => array(<entity result mapping>),
  252. * 'columns' => array(<column result mapping>)
  253. * )
  254. * </pre>
  255. */
  256. public $sqlResultSetMappings = array();
  257. /**
  258. * READ-ONLY: The field names of all fields that are part of the identifier/primary key
  259. * of the mapped entity class.
  260. *
  261. * @var array
  262. */
  263. public $identifier = array();
  264. /**
  265. * READ-ONLY: The inheritance mapping type used by the class.
  266. *
  267. * @var integer
  268. */
  269. public $inheritanceType = self::INHERITANCE_TYPE_NONE;
  270. /**
  271. * READ-ONLY: The Id generator type used by the class.
  272. *
  273. * @var string
  274. */
  275. public $generatorType = self::GENERATOR_TYPE_NONE;
  276. /**
  277. * READ-ONLY: The field mappings of the class.
  278. * Keys are field names and values are mapping definitions.
  279. *
  280. * The mapping definition array has the following values:
  281. *
  282. * - <b>fieldName</b> (string)
  283. * The name of the field in the Entity.
  284. *
  285. * - <b>type</b> (string)
  286. * The type name of the mapped field. Can be one of Doctrine's mapping types
  287. * or a custom mapping type.
  288. *
  289. * - <b>columnName</b> (string, optional)
  290. * The column name. Optional. Defaults to the field name.
  291. *
  292. * - <b>length</b> (integer, optional)
  293. * The database length of the column. Optional. Default value taken from
  294. * the type.
  295. *
  296. * - <b>id</b> (boolean, optional)
  297. * Marks the field as the primary key of the entity. Multiple fields of an
  298. * entity can have the id attribute, forming a composite key.
  299. *
  300. * - <b>nullable</b> (boolean, optional)
  301. * Whether the column is nullable. Defaults to FALSE.
  302. *
  303. * - <b>columnDefinition</b> (string, optional, schema-only)
  304. * The SQL fragment that is used when generating the DDL for the column.
  305. *
  306. * - <b>precision</b> (integer, optional, schema-only)
  307. * The precision of a decimal column. Only valid if the column type is decimal.
  308. *
  309. * - <b>scale</b> (integer, optional, schema-only)
  310. * The scale of a decimal column. Only valid if the column type is decimal.
  311. *
  312. [* - <b>'unique'] (string, optional, schema-only)</b>
  313. * Whether a unique constraint should be generated for the column.
  314. *
  315. * @var array
  316. */
  317. public $fieldMappings = array();
  318. /**
  319. * READ-ONLY: An array of field names. Used to look up field names from column names.
  320. * Keys are column names and values are field names.
  321. * This is the reverse lookup map of $_columnNames.
  322. *
  323. * @var array
  324. */
  325. public $fieldNames = array();
  326. /**
  327. * READ-ONLY: A map of field names to column names. Keys are field names and values column names.
  328. * Used to look up column names from field names.
  329. * This is the reverse lookup map of $_fieldNames.
  330. *
  331. * @var array
  332. * @todo We could get rid of this array by just using $fieldMappings[$fieldName]['columnName'].
  333. */
  334. public $columnNames = array();
  335. /**
  336. * READ-ONLY: The discriminator value of this class.
  337. *
  338. * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
  339. * where a discriminator column is used.</b>
  340. *
  341. * @var mixed
  342. * @see discriminatorColumn
  343. */
  344. public $discriminatorValue;
  345. /**
  346. * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
  347. *
  348. * <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
  349. * where a discriminator column is used.</b>
  350. *
  351. * @var mixed
  352. * @see discriminatorColumn
  353. */
  354. public $discriminatorMap = array();
  355. /**
  356. * READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
  357. * inheritance mappings.
  358. *
  359. * @var array
  360. */
  361. public $discriminatorColumn;
  362. /**
  363. * READ-ONLY: The primary table definition. The definition is an array with the
  364. * following entries:
  365. *
  366. * name => <tableName>
  367. * schema => <schemaName>
  368. * indexes => array
  369. * uniqueConstraints => array
  370. *
  371. * @var array
  372. */
  373. public $table;
  374. /**
  375. * READ-ONLY: The registered lifecycle callbacks for entities of this class.
  376. *
  377. * @var array
  378. */
  379. public $lifecycleCallbacks = array();
  380. /**
  381. * READ-ONLY: The association mappings of this class.
  382. *
  383. * The mapping definition array supports the following keys:
  384. *
  385. * - <b>fieldName</b> (string)
  386. * The name of the field in the entity the association is mapped to.
  387. *
  388. * - <b>targetEntity</b> (string)
  389. * The class name of the target entity. If it is fully-qualified it is used as is.
  390. * If it is a simple, unqualified class name the namespace is assumed to be the same
  391. * as the namespace of the source entity.
  392. *
  393. * - <b>mappedBy</b> (string, required for bidirectional associations)
  394. * The name of the field that completes the bidirectional association on the owning side.
  395. * This key must be specified on the inverse side of a bidirectional association.
  396. *
  397. * - <b>inversedBy</b> (string, required for bidirectional associations)
  398. * The name of the field that completes the bidirectional association on the inverse side.
  399. * This key must be specified on the owning side of a bidirectional association.
  400. *
  401. * - <b>cascade</b> (array, optional)
  402. * The names of persistence operations to cascade on the association. The set of possible
  403. * values are: "persist", "remove", "detach", "merge", "refresh", "all" (implies all others).
  404. *
  405. * - <b>orderBy</b> (array, one-to-many/many-to-many only)
  406. * A map of field names (of the target entity) to sorting directions (ASC/DESC).
  407. * Example: array('priority' => 'desc')
  408. *
  409. * - <b>fetch</b> (integer, optional)
  410. * The fetching strategy to use for the association, usually defaults to FETCH_LAZY.
  411. * Possible values are: ClassMetadata::FETCH_EAGER, ClassMetadata::FETCH_LAZY.
  412. *
  413. * - <b>joinTable</b> (array, optional, many-to-many only)
  414. * Specification of the join table and its join columns (foreign keys).
  415. * Only valid for many-to-many mappings. Note that one-to-many associations can be mapped
  416. * through a join table by simply mapping the association as many-to-many with a unique
  417. * constraint on the join table.
  418. *
  419. * - <b>indexBy</b> (string, optional, to-many only)
  420. * Specification of a field on target-entity that is used to index the collection by.
  421. * This field HAS to be either the primary key or a unique column. Otherwise the collection
  422. * does not contain all the entities that are actually related.
  423. *
  424. * A join table definition has the following structure:
  425. * <pre>
  426. * array(
  427. * 'name' => <join table name>,
  428. * 'joinColumns' => array(<join column mapping from join table to source table>),
  429. * 'inverseJoinColumns' => array(<join column mapping from join table to target table>)
  430. * )
  431. * </pre>
  432. *
  433. *
  434. * @var array
  435. */
  436. public $associationMappings = array();
  437. /**
  438. * READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite.
  439. *
  440. * @var boolean
  441. */
  442. public $isIdentifierComposite = false;
  443. /**
  444. * READ-ONLY: Flag indicating wheather the identifier/primary key contains at least one foreign key association.
  445. *
  446. * This flag is necessary because some code blocks require special treatment of this cases.
  447. *
  448. * @var boolean
  449. */
  450. public $containsForeignIdentifier = false;
  451. /**
  452. * READ-ONLY: The ID generator used for generating IDs for this class.
  453. *
  454. * @var \Doctrine\ORM\Id\AbstractIdGenerator
  455. * @todo Remove!
  456. */
  457. public $idGenerator;
  458. /**
  459. * READ-ONLY: The definition of the sequence generator of this class. Only used for the
  460. * SEQUENCE generation strategy.
  461. *
  462. * The definition has the following structure:
  463. * <code>
  464. * array(
  465. * 'sequenceName' => 'name',
  466. * 'allocationSize' => 20,
  467. * 'initialValue' => 1
  468. * )
  469. * </code>
  470. *
  471. * @var array
  472. * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
  473. */
  474. public $sequenceGeneratorDefinition;
  475. /**
  476. * READ-ONLY: The definition of the table generator of this class. Only used for the
  477. * TABLE generation strategy.
  478. *
  479. * @var array
  480. * @todo Merge with tableGeneratorDefinition into generic generatorDefinition
  481. */
  482. public $tableGeneratorDefinition;
  483. /**
  484. * READ-ONLY: The policy used for change-tracking on entities of this class.
  485. *
  486. * @var integer
  487. */
  488. public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
  489. /**
  490. * READ-ONLY: A flag for whether or not instances of this class are to be versioned
  491. * with optimistic locking.
  492. *
  493. * @var boolean $isVersioned
  494. */
  495. public $isVersioned;
  496. /**
  497. * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
  498. *
  499. * @var mixed $versionField
  500. */
  501. public $versionField;
  502. /**
  503. * The ReflectionClass instance of the mapped class.
  504. *
  505. * @var ReflectionClass
  506. */
  507. public $reflClass;
  508. /**
  509. * Is this entity marked as "read-only"?
  510. *
  511. * That means it is never considered for change-tracking in the UnitOfWork. It is a very helpful performance
  512. * optimization for entities that are immutable, either in your domain or through the relation database
  513. * (coming from a view, or a history table for example).
  514. *
  515. * @var bool
  516. */
  517. public $isReadOnly = false;
  518. /**
  519. * NamingStrategy determining the default column and table names
  520. *
  521. * @var \Doctrine\ORM\Mapping\NamingStrategy
  522. */
  523. protected $namingStrategy;
  524. /**
  525. * The ReflectionProperty instances of the mapped class.
  526. *
  527. * @var array
  528. */
  529. public $reflFields = array();
  530. /**
  531. * The prototype from which new instances of the mapped class are created.
  532. *
  533. * @var object
  534. */
  535. private $_prototype;
  536. /**
  537. * Initializes a new ClassMetadata instance that will hold the object-relational mapping
  538. * metadata of the class with the given name.
  539. *
  540. * @param string $entityName The name of the entity class the new instance is used for.
  541. * @param NamingStrategy $namingStrategy
  542. */
  543. public function __construct($entityName, NamingStrategy $namingStrategy = null)
  544. {
  545. $this->name = $entityName;
  546. $this->rootEntityName = $entityName;
  547. $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy();
  548. }
  549. /**
  550. * Gets the ReflectionPropertys of the mapped class.
  551. *
  552. * @return array An array of ReflectionProperty instances.
  553. */
  554. public function getReflectionProperties()
  555. {
  556. return $this->reflFields;
  557. }
  558. /**
  559. * Gets a ReflectionProperty for a specific field of the mapped class.
  560. *
  561. * @param string $name
  562. * @return \ReflectionProperty
  563. */
  564. public function getReflectionProperty($name)
  565. {
  566. return $this->reflFields[$name];
  567. }
  568. /**
  569. * Gets the ReflectionProperty for the single identifier field.
  570. *
  571. * @return \ReflectionProperty
  572. * @throws BadMethodCallException If the class has a composite identifier.
  573. */
  574. public function getSingleIdReflectionProperty()
  575. {
  576. if ($this->isIdentifierComposite) {
  577. throw new BadMethodCallException("Class " . $this->name . " has a composite identifier.");
  578. }
  579. return $this->reflFields[$this->identifier[0]];
  580. }
  581. /**
  582. * Extracts the identifier values of an entity of this class.
  583. *
  584. * For composite identifiers, the identifier values are returned as an array
  585. * with the same order as the field order in {@link identifier}.
  586. *
  587. * @param object $entity
  588. * @return array
  589. */
  590. public function getIdentifierValues($entity)
  591. {
  592. if ($this->isIdentifierComposite) {
  593. $id = array();
  594. foreach ($this->identifier as $idField) {
  595. $value = $this->reflFields[$idField]->getValue($entity);
  596. if ($value !== null) {
  597. $id[$idField] = $value;
  598. }
  599. }
  600. return $id;
  601. }
  602. $value = $this->reflFields[$this->identifier[0]]->getValue($entity);
  603. if ($value !== null) {
  604. return array($this->identifier[0] => $value);
  605. }
  606. return array();
  607. }
  608. /**
  609. * Populates the entity identifier of an entity.
  610. *
  611. * @param object $entity
  612. * @param mixed $id
  613. * @todo Rename to assignIdentifier()
  614. */
  615. public function setIdentifierValues($entity, array $id)
  616. {
  617. foreach ($id as $idField => $idValue) {
  618. $this->reflFields[$idField]->setValue($entity, $idValue);
  619. }
  620. }
  621. /**
  622. * Sets the specified field to the specified value on the given entity.
  623. *
  624. * @param object $entity
  625. * @param string $field
  626. * @param mixed $value
  627. */
  628. public function setFieldValue($entity, $field, $value)
  629. {
  630. $this->reflFields[$field]->setValue($entity, $value);
  631. }
  632. /**
  633. * Gets the specified field's value off the given entity.
  634. *
  635. * @param object $entity
  636. * @param string $field
  637. */
  638. public function getFieldValue($entity, $field)
  639. {
  640. return $this->reflFields[$field]->getValue($entity);
  641. }
  642. /**
  643. * Creates a string representation of this instance.
  644. *
  645. * @return string The string representation of this instance.
  646. * @todo Construct meaningful string representation.
  647. */
  648. public function __toString()
  649. {
  650. return __CLASS__ . '@' . spl_object_hash($this);
  651. }
  652. /**
  653. * Determines which fields get serialized.
  654. *
  655. * It is only serialized what is necessary for best unserialization performance.
  656. * That means any metadata properties that are not set or empty or simply have
  657. * their default value are NOT serialized.
  658. *
  659. * Parts that are also NOT serialized because they can not be properly unserialized:
  660. * - reflClass (ReflectionClass)
  661. * - reflFields (ReflectionProperty array)
  662. *
  663. * @return array The names of all the fields that should be serialized.
  664. */
  665. public function __sleep()
  666. {
  667. // This metadata is always serialized/cached.
  668. $serialized = array(
  669. 'associationMappings',
  670. 'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
  671. 'fieldMappings',
  672. 'fieldNames',
  673. 'identifier',
  674. 'isIdentifierComposite', // TODO: REMOVE
  675. 'name',
  676. 'namespace', // TODO: REMOVE
  677. 'table',
  678. 'rootEntityName',
  679. 'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
  680. );
  681. // The rest of the metadata is only serialized if necessary.
  682. if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
  683. $serialized[] = 'changeTrackingPolicy';
  684. }
  685. if ($this->customRepositoryClassName) {
  686. $serialized[] = 'customRepositoryClassName';
  687. }
  688. if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
  689. $serialized[] = 'inheritanceType';
  690. $serialized[] = 'discriminatorColumn';
  691. $serialized[] = 'discriminatorValue';
  692. $serialized[] = 'discriminatorMap';
  693. $serialized[] = 'parentClasses';
  694. $serialized[] = 'subClasses';
  695. }
  696. if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
  697. $serialized[] = 'generatorType';
  698. if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
  699. $serialized[] = 'sequenceGeneratorDefinition';
  700. }
  701. }
  702. if ($this->isMappedSuperclass) {
  703. $serialized[] = 'isMappedSuperclass';
  704. }
  705. if ($this->containsForeignIdentifier) {
  706. $serialized[] = 'containsForeignIdentifier';
  707. }
  708. if ($this->isVersioned) {
  709. $serialized[] = 'isVersioned';
  710. $serialized[] = 'versionField';
  711. }
  712. if ($this->lifecycleCallbacks) {
  713. $serialized[] = 'lifecycleCallbacks';
  714. }
  715. if ($this->namedQueries) {
  716. $serialized[] = 'namedQueries';
  717. }
  718. if ($this->namedNativeQueries) {
  719. $serialized[] = 'namedNativeQueries';
  720. }
  721. if ($this->sqlResultSetMappings) {
  722. $serialized[] = 'sqlResultSetMappings';
  723. }
  724. if ($this->isReadOnly) {
  725. $serialized[] = 'isReadOnly';
  726. }
  727. if ($this->customGeneratorDefinition) {
  728. $serialized[] = "customGeneratorDefinition";
  729. }
  730. return $serialized;
  731. }
  732. /**
  733. * Creates a new instance of the mapped class, without invoking the constructor.
  734. *
  735. * @return object
  736. */
  737. public function newInstance()
  738. {
  739. if ($this->_prototype === null) {
  740. $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
  741. }
  742. return clone $this->_prototype;
  743. }
  744. /**
  745. * Restores some state that can not be serialized/unserialized.
  746. *
  747. * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
  748. * @return void
  749. */
  750. public function wakeupReflection($reflService)
  751. {
  752. // Restore ReflectionClass and properties
  753. $this->reflClass = $reflService->getClass($this->name);
  754. foreach ($this->fieldMappings as $field => $mapping) {
  755. $this->reflFields[$field] = isset($mapping['declared'])
  756. ? $reflService->getAccessibleProperty($mapping['declared'], $field)
  757. : $reflService->getAccessibleProperty($this->name, $field);
  758. }
  759. foreach ($this->associationMappings as $field => $mapping) {
  760. $this->reflFields[$field] = isset($mapping['declared'])
  761. ? $reflService->getAccessibleProperty($mapping['declared'], $field)
  762. : $reflService->getAccessibleProperty($this->name, $field);
  763. }
  764. }
  765. /**
  766. * Initializes a new ClassMetadata instance that will hold the object-relational mapping
  767. * metadata of the class with the given name.
  768. *
  769. * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service.
  770. */
  771. public function initializeReflection($reflService)
  772. {
  773. $this->reflClass = $reflService->getClass($this->name);
  774. $this->namespace = $reflService->getClassNamespace($this->name);
  775. if ($this->reflClass) {
  776. $this->name = $this->rootEntityName = $this->reflClass->getName();
  777. }
  778. $this->table['name'] = $this->namingStrategy->classToTableName($this->name);
  779. }
  780. /**
  781. * Validate Identifier
  782. *
  783. * @throws MappingException
  784. * @return void
  785. */
  786. public function validateIdentifier()
  787. {
  788. // Verify & complete identifier mapping
  789. if ( ! $this->identifier && ! $this->isMappedSuperclass) {
  790. throw MappingException::identifierRequired($this->name);
  791. }
  792. if ($this->usesIdGenerator() && $this->isIdentifierComposite) {
  793. throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name);
  794. }
  795. }
  796. /**
  797. * Validate association targets actually exist.
  798. *
  799. * @throws MappingException
  800. * @return void
  801. */
  802. public function validateAssocations()
  803. {
  804. foreach ($this->associationMappings as $mapping) {
  805. if ( ! ClassLoader::classExists($mapping['targetEntity']) ) {
  806. throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']);
  807. }
  808. }
  809. }
  810. /**
  811. * Validate lifecycle callbacks
  812. *
  813. * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
  814. * @throws MappingException
  815. * @return void
  816. */
  817. public function validateLifecycleCallbacks($reflService)
  818. {
  819. foreach ($this->lifecycleCallbacks as $callbacks) {
  820. foreach ($callbacks as $callbackFuncName) {
  821. if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) {
  822. throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName);
  823. }
  824. }
  825. }
  826. }
  827. /**
  828. * {@inheritDoc}
  829. */
  830. public function getReflectionClass()
  831. {
  832. return $this->reflClass;
  833. }
  834. /**
  835. * Sets the change tracking policy used by this class.
  836. *
  837. * @param integer $policy
  838. */
  839. public function setChangeTrackingPolicy($policy)
  840. {
  841. $this->changeTrackingPolicy = $policy;
  842. }
  843. /**
  844. * Whether the change tracking policy of this class is "deferred explicit".
  845. *
  846. * @return boolean
  847. */
  848. public function isChangeTrackingDeferredExplicit()
  849. {
  850. return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
  851. }
  852. /**
  853. * Whether the change tracking policy of this class is "deferred implicit".
  854. *
  855. * @return boolean
  856. */
  857. public function isChangeTrackingDeferredImplicit()
  858. {
  859. return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
  860. }
  861. /**
  862. * Whether the change tracking policy of this class is "notify".
  863. *
  864. * @return boolean
  865. */
  866. public function isChangeTrackingNotify()
  867. {
  868. return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
  869. }
  870. /**
  871. * Checks whether a field is part of the identifier/primary key field(s).
  872. *
  873. * @param string $fieldName The field name
  874. * @return boolean TRUE if the field is part of the table identifier/primary key field(s),
  875. * FALSE otherwise.
  876. */
  877. public function isIdentifier($fieldName)
  878. {
  879. if ( ! $this->isIdentifierComposite) {
  880. return $fieldName === $this->identifier[0];
  881. }
  882. return in_array($fieldName, $this->identifier);
  883. }
  884. /**
  885. * Check if the field is unique.
  886. *
  887. * @param string $fieldName The field name
  888. * @return boolean TRUE if the field is unique, FALSE otherwise.
  889. */
  890. public function isUniqueField($fieldName)
  891. {
  892. $mapping = $this->getFieldMapping($fieldName);
  893. if ($mapping !== false) {
  894. return isset($mapping['unique']) && $mapping['unique'] == true;
  895. }
  896. return false;
  897. }
  898. /**
  899. * Check if the field is not null.
  900. *
  901. * @param string $fieldName The field name
  902. * @return boolean TRUE if the field is not null, FALSE otherwise.
  903. */
  904. public function isNullable($fieldName)
  905. {
  906. $mapping = $this->getFieldMapping($fieldName);
  907. if ($mapping !== false) {
  908. return isset($mapping['nullable']) && $mapping['nullable'] == true;
  909. }
  910. return false;
  911. }
  912. /**
  913. * Gets a column name for a field name.
  914. * If the column name for the field cannot be found, the given field name
  915. * is returned.
  916. *
  917. * @param string $fieldName The field name.
  918. * @return string The column name.
  919. */
  920. public function getColumnName($fieldName)
  921. {
  922. return isset($this->columnNames[$fieldName]) ?
  923. $this->columnNames[$fieldName] : $fieldName;
  924. }
  925. /**
  926. * Gets the mapping of a (regular) field that holds some data but not a
  927. * reference to another object.
  928. *
  929. * @param string $fieldName The field name.
  930. * @throws MappingException
  931. * @return array The field mapping.
  932. */
  933. public function getFieldMapping($fieldName)
  934. {
  935. if ( ! isset($this->fieldMappings[$fieldName])) {
  936. throw MappingException::mappingNotFound($this->name, $fieldName);
  937. }
  938. return $this->fieldMappings[$fieldName];
  939. }
  940. /**
  941. * Gets the mapping of an association.
  942. *
  943. * @see ClassMetadataInfo::$associationMappings
  944. * @param string $fieldName The field name that represents the association in
  945. * the object model.
  946. * @throws MappingException
  947. * @return array The mapping.
  948. */
  949. public function getAssociationMapping($fieldName)
  950. {
  951. if ( ! isset($this->associationMappings[$fieldName])) {
  952. throw MappingException::mappingNotFound($this->name, $fieldName);
  953. }
  954. return $this->associationMappings[$fieldName];
  955. }
  956. /**
  957. * Gets all association mappings of the class.
  958. *
  959. * @return array
  960. */
  961. public function getAssociationMappings()
  962. {
  963. return $this->associationMappings;
  964. }
  965. /**
  966. * Gets the field name for a column name.
  967. * If no field name can be found the column name is returned.
  968. *
  969. * @param string $columnName column name
  970. * @return string column alias
  971. */
  972. public function getFieldName($columnName)
  973. {
  974. return isset($this->fieldNames[$columnName]) ?
  975. $this->fieldNames[$columnName] : $columnName;
  976. }
  977. /**
  978. * Gets the named query.
  979. *
  980. * @see ClassMetadataInfo::$namedQueries
  981. * @throws MappingException
  982. * @param string $queryName The query name
  983. * @return string
  984. */
  985. public function getNamedQuery($queryName)
  986. {
  987. if ( ! isset($this->namedQueries[$queryName])) {
  988. throw MappingException::queryNotFound($this->name, $queryName);
  989. }
  990. return $this->namedQueries[$queryName]['dql'];
  991. }
  992. /**
  993. * Gets all named queries of the class.
  994. *
  995. * @return array
  996. */
  997. public function getNamedQueries()
  998. {
  999. return $this->namedQueries;
  1000. }
  1001. /**
  1002. * Gets the named native query.
  1003. *
  1004. * @see ClassMetadataInfo::$namedNativeQueries
  1005. * @throws MappingException
  1006. * @param string $queryName The query name
  1007. * @return array
  1008. */
  1009. public function getNamedNativeQuery($queryName)
  1010. {
  1011. if ( ! isset($this->namedNativeQueries[$queryName])) {
  1012. throw MappingException::queryNotFound($this->name, $queryName);
  1013. }
  1014. return $this->namedNativeQueries[$queryName];
  1015. }
  1016. /**
  1017. * Gets all named native queries of the class.
  1018. *
  1019. * @return array
  1020. */
  1021. public function getNamedNativeQueries()
  1022. {
  1023. return $this->namedNativeQueries;
  1024. }
  1025. /**
  1026. * Gets the result set mapping.
  1027. *
  1028. * @see ClassMetadataInfo::$sqlResultSetMappings
  1029. * @throws MappingException
  1030. * @param string $name The result set mapping name
  1031. * @return array
  1032. */
  1033. public function getSqlResultSetMapping($name)
  1034. {
  1035. if ( ! isset($this->sqlResultSetMappings[$name])) {
  1036. throw MappingException::resultMappingNotFound($this->name, $name);
  1037. }
  1038. return $this->sqlResultSetMappings[$name];
  1039. }
  1040. /**
  1041. * Gets all sql result set mappings of the class.
  1042. *
  1043. * @return array
  1044. */
  1045. public function getSqlResultSetMappings()
  1046. {
  1047. return $this->sqlResultSetMappings;
  1048. }
  1049. /**
  1050. * Validates & completes the given field mapping.
  1051. *
  1052. * @param array $mapping The field mapping to validated & complete.
  1053. * @throws MappingException
  1054. * @return array The validated and completed field mapping.
  1055. */
  1056. protected function _validateAndCompleteFieldMapping(array &$mapping)
  1057. {
  1058. // Check mandatory fields
  1059. if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
  1060. throw MappingException::missingFieldName($this->name);
  1061. }
  1062. if ( ! isset($mapping['type'])) {
  1063. // Default to string
  1064. $mapping['type'] = 'string';
  1065. }
  1066. // Complete fieldName and columnName mapping
  1067. if ( ! isset($mapping['columnName'])) {
  1068. $mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName']);
  1069. }
  1070. if ($mapping['columnName'][0] === '`') {
  1071. $mapping['columnName'] = trim($mapping['columnName'], '`');
  1072. $mapping['quoted'] = true;
  1073. }
  1074. $this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
  1075. if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn != null && $this->discriminatorColumn['name'] == $mapping['columnName'])) {
  1076. throw MappingException::duplicateColumnName($this->name, $mapping['columnName']);
  1077. }
  1078. $this->fieldNames[$mapping['columnName']] = $mapping['fieldName'];
  1079. // Complete id mapping
  1080. if (isset($mapping['id']) && $mapping['id'] === true) {
  1081. if ($this->versionField == $mapping['fieldName']) {
  1082. throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']);
  1083. }
  1084. if ( ! in_array($mapping['fieldName'], $this->identifier)) {
  1085. $this->identifier[] = $mapping['fieldName'];
  1086. }
  1087. // Check for composite key
  1088. if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
  1089. $this->isIdentifierComposite = true;
  1090. }
  1091. }
  1092. if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
  1093. if (isset($mapping['id']) && $mapping['id'] === true) {
  1094. throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
  1095. }
  1096. $mapping['requireSQLConversion'] = true;
  1097. }
  1098. }
  1099. /**
  1100. * Validates & completes the basic mapping information that is common to all
  1101. * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
  1102. *
  1103. * @param array $mapping The mapping.
  1104. * @return array The updated mapping.
  1105. * @throws MappingException If something is wrong with the mapping.
  1106. */
  1107. protected function _validateAndCompleteAssociationMapping(array $mapping)
  1108. {
  1109. if ( ! isset($mapping['mappedBy'])) {
  1110. $mapping['mappedBy'] = null;
  1111. }
  1112. if ( ! isset($mapping['inversedBy'])) {
  1113. $mapping['inversedBy'] = null;
  1114. }
  1115. $mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
  1116. // unset optional indexBy attribute if its empty
  1117. if ( ! isset($mapping['indexBy']) || !$mapping['indexBy']) {
  1118. unset($mapping['indexBy']);
  1119. }
  1120. // If targetEntity is unqualified, assume it is in the same namespace as
  1121. // the sourceEntity.
  1122. $mapping['sourceEntity'] = $this->name;
  1123. if (isset($mapping['targetEntity'])) {
  1124. if (strlen($this->namespace) > 0 && strpos($mapping['targetEntity'], '\\') === false) {
  1125. $mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
  1126. }
  1127. $mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
  1128. }
  1129. if ( ($mapping['type'] & self::MANY_TO_ONE) > 0 &&
  1130. isset($mapping['orphanRemoval']) &&
  1131. $mapping['orphanRemoval'] == true) {
  1132. throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']);
  1133. }
  1134. // Complete id mapping
  1135. if (isset($mapping['id']) && $mapping['id'] === true) {
  1136. if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
  1137. throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']);
  1138. }
  1139. if ( ! in_array($mapping['fieldName'], $this->identifier)) {
  1140. if (count($mapping['joinColumns']) >= 2) {
  1141. throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
  1142. $mapping['targetEntity'], $this->name, $mapping['fieldName']
  1143. );
  1144. }
  1145. $this->identifier[] = $mapping['fieldName'];
  1146. $this->containsForeignIdentifier = true;
  1147. }
  1148. // Check for composite key
  1149. if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
  1150. $this->isIdentifierComposite = true;
  1151. }
  1152. }
  1153. // Mandatory attributes for both sides
  1154. // Mandatory: fieldName, targetEntity
  1155. if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
  1156. throw MappingException::missingFieldName($this->name);
  1157. }
  1158. if ( ! isset($mapping['targetEntity'])) {
  1159. throw MappingException::missingTargetEntity($mapping['fieldName']);
  1160. }
  1161. // Mandatory and optional attributes for either side
  1162. if ( ! $mapping['mappedBy']) {
  1163. if (isset($mapping['joinTable']) && $mapping['joinTable']) {
  1164. if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] === '`') {
  1165. $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
  1166. $mapping['joinTable']['quoted'] = true;
  1167. }
  1168. }
  1169. } else {
  1170. $mapping['isOwningSide'] = false;
  1171. }
  1172. if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) {
  1173. throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']);
  1174. }
  1175. // Fetch mode. Default fetch mode to LAZY, if not set.
  1176. if ( ! isset($mapping['fetch'])) {
  1177. $mapping['fetch'] = self::FETCH_LAZY;
  1178. }
  1179. // Cascades
  1180. $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
  1181. if (in_array('all', $cascades)) {
  1182. $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
  1183. }
  1184. if (count($cascades) !== count(array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach')))) {
  1185. throw MappingException::invalidCascadeOption(
  1186. array_diff($cascades, array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach'))),
  1187. $this->name,
  1188. $mapping['fieldName']
  1189. );
  1190. }
  1191. $mapping['cascade'] = $cascades;
  1192. $mapping['isCascadeRemove'] = in_array('remove', $cascades);
  1193. $mapping['isCascadePersist'] = in_array('persist', $cascades);
  1194. $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
  1195. $mapping['isCascadeMerge'] = in_array('merge', $cascades);
  1196. $mapping['isCascadeDetach'] = in_array('detach', $cascades);
  1197. return $mapping;
  1198. }
  1199. /**
  1200. * Validates & completes a one-to-one association mapping.
  1201. *
  1202. * @param array $mapping The mapping to validate & complete.
  1203. * @throws RuntimeException
  1204. * @throws MappingException
  1205. * @return array The validated & completed mapping.@override
  1206. */
  1207. protected function _validateAndCompleteOneToOneMapping(array $mapping)
  1208. {
  1209. $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
  1210. if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
  1211. $mapping['isOwningSide'] = true;
  1212. }
  1213. if ($mapping['isOwningSide']) {
  1214. if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
  1215. // Apply default join column
  1216. $mapping['joinColumns'] = array(array(
  1217. 'name' => $this->namingStrategy->joinColumnName($mapping['fieldName']),
  1218. 'referencedColumnName' => $this->namingStrategy->referenceColumnName()
  1219. ));
  1220. }
  1221. $uniqueContraintColumns = array();
  1222. foreach ($mapping['joinColumns'] as &$joinColumn) {
  1223. if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
  1224. if (count($mapping['joinColumns']) == 1) {
  1225. if ( ! isset($mapping['id']) || ! $mapping['id']) {
  1226. $joinColumn['unique'] = true;
  1227. }
  1228. } else {
  1229. $uniqueContraintColumns[] = $joinColumn['name'];
  1230. }
  1231. }
  1232. if (empty($joinColumn['name'])) {
  1233. $joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName']);
  1234. }
  1235. if (empty($joinColumn['referencedColumnName'])) {
  1236. $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
  1237. }
  1238. if ($joinColumn['name'][0] === '`') {
  1239. $joinColumn['name'] = trim($joinColumn['name'], '`');
  1240. $joinColumn['quoted'] = true;
  1241. }
  1242. if ($joinColumn['referencedColumnName'][0] === '`') {
  1243. $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`');
  1244. $joinColumn['quoted'] = true;
  1245. }
  1246. $mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
  1247. $mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
  1248. ? $joinColumn['fieldName'] : $joinColumn['name'];
  1249. }
  1250. if ($uniqueContraintColumns) {
  1251. if ( ! $this->table) {
  1252. throw new RuntimeException("ClassMetadataInfo::setTable() has to be called before defining a one to one relationship.");
  1253. }
  1254. $this->table['uniqueConstraints'][$mapping['fieldName']."_uniq"] = array(
  1255. 'columns' => $uniqueContraintColumns
  1256. );
  1257. }
  1258. $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
  1259. }
  1260. $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
  1261. $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
  1262. if ($mapping['orphanRemoval']) {
  1263. unset($mapping['unique']);
  1264. }
  1265. if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
  1266. throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']);
  1267. }
  1268. return $mapping;
  1269. }
  1270. /**
  1271. * Validates and completes the mapping.
  1272. *
  1273. * @param array $mapping The mapping to validate and complete.
  1274. * @throws MappingException
  1275. * @throws InvalidArgumentException
  1276. * @return array The validated and completed mapping.@override
  1277. */
  1278. protected function _validateAndCompleteOneToManyMapping(array $mapping)
  1279. {
  1280. $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
  1281. // OneToMany-side MUST be inverse (must have mappedBy)
  1282. if ( ! isset($mapping['mappedBy'])) {
  1283. throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
  1284. }
  1285. $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
  1286. $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
  1287. if (isset($mapping['orderBy'])) {
  1288. if ( ! is_array($mapping['orderBy'])) {
  1289. throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
  1290. }
  1291. }
  1292. return $mapping;
  1293. }
  1294. protected function _validateAndCompleteManyToManyMapping(array $mapping)
  1295. {
  1296. $mapping = $this->_validateAndCompleteAssociationMapping($mapping);
  1297. if ($mapping['isOwningSide']) {
  1298. // owning side MUST have a join table
  1299. if ( ! isset($mapping['joinTable']['name'])) {
  1300. $mapping['joinTable']['name'] = $this->namingStrategy->joinTableName($mapping['sourceEntity'], $mapping['targetEntity'], $mapping['fieldName']);
  1301. }
  1302. if ( ! isset($mapping['joinTable']['joinColumns'])) {
  1303. $mapping['joinTable']['joinColumns'] = array(array(
  1304. 'name' => $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity']),
  1305. 'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
  1306. 'onDelete' => 'CASCADE'));
  1307. }
  1308. if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
  1309. $mapping['joinTable']['inverseJoinColumns'] = array(array(
  1310. 'name' => $this->namingStrategy->joinKeyColumnName($mapping['targetEntity']),
  1311. 'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
  1312. 'onDelete' => 'CASCADE'));
  1313. }
  1314. $mapping['joinTableColumns'] = array();
  1315. foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
  1316. if (empty($joinColumn['name'])) {
  1317. $joinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $joinColumn['referencedColumnName']);
  1318. }
  1319. if (empty($joinColumn['referencedColumnName'])) {
  1320. $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
  1321. }
  1322. if ($joinColumn['name'][0] === '`') {
  1323. $joinColumn['name'] = trim($joinColumn['name'], '`');
  1324. $joinColumn['quoted'] = true;
  1325. }
  1326. if ($joinColumn['referencedColumnName'][0] === '`') {
  1327. $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`');
  1328. $joinColumn['quoted'] = true;
  1329. }
  1330. if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
  1331. $mapping['isOnDeleteCascade'] = true;
  1332. }
  1333. $mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
  1334. $mapping['joinTableColumns'][] = $joinColumn['name'];
  1335. }
  1336. foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
  1337. if (empty($inverseJoinColumn['name'])) {
  1338. $inverseJoinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $inverseJoinColumn['referencedColumnName']);
  1339. }
  1340. if (empty($inverseJoinColumn['referencedColumnName'])) {
  1341. $inverseJoinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
  1342. }
  1343. if ($inverseJoinColumn['name'][0] === '`') {
  1344. $inverseJoinColumn['name'] = trim($inverseJoinColumn['name'], '`');
  1345. $inverseJoinColumn['quoted'] = true;
  1346. }
  1347. if ($inverseJoinColumn['referencedColumnName'][0] === '`') {
  1348. $inverseJoinColumn['referencedColumnName'] = trim($inverseJoinColumn['referencedColumnName'], '`');
  1349. $inverseJoinColumn['quoted'] = true;
  1350. }
  1351. if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
  1352. $mapping['isOnDeleteCascade'] = true;
  1353. }
  1354. $mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
  1355. $mapping['joinTableColumns'][] = $inverseJoinColumn['name'];
  1356. }
  1357. }
  1358. $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
  1359. if (isset($mapping['orderBy'])) {
  1360. if ( ! is_array($mapping['orderBy'])) {
  1361. throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
  1362. }
  1363. }
  1364. return $mapping;
  1365. }
  1366. /**
  1367. * {@inheritDoc}
  1368. */
  1369. public function getIdentifierFieldNames()
  1370. {
  1371. return $this->identifier;
  1372. }
  1373. /**
  1374. * Gets the name of the single id field. Note that this only works on
  1375. * entity classes that have a single-field pk.
  1376. *
  1377. * @return string
  1378. * @throws MappingException If the class has a composite primary key.
  1379. */
  1380. public function getSingleIdentifierFieldName()
  1381. {
  1382. if ($this->isIdentifierComposite) {
  1383. throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name);
  1384. }
  1385. return $this->identifier[0];
  1386. }
  1387. /**
  1388. * Gets the column name of the single id column. Note that this only works on
  1389. * entity classes that have a single-field pk.
  1390. *
  1391. * @return string
  1392. * @throws MappingException If the class has a composite primary key.
  1393. */
  1394. public function getSingleIdentifierColumnName()
  1395. {
  1396. return $this->getColumnName($this->getSingleIdentifierFieldName());
  1397. }
  1398. /**
  1399. * INTERNAL:
  1400. * Sets the mapped identifier/primary key fields of this class.
  1401. * Mainly used by the ClassMetadataFactory to assign inherited identifiers.
  1402. *
  1403. * @param array $identifier
  1404. */
  1405. public function setIdentifier(array $identifier)
  1406. {
  1407. $this->identifier = $identifier;
  1408. $this->isIdentifierComposite = (count($this->identifier) > 1);
  1409. }
  1410. /**
  1411. * Gets the mapped identifier field of this class.
  1412. *
  1413. * @return array|string $identifier
  1414. */
  1415. public function getIdentifier()
  1416. {
  1417. return $this->identifier;
  1418. }
  1419. /**
  1420. * {@inheritDoc}
  1421. */
  1422. public function hasField($fieldName)
  1423. {
  1424. return isset($this->fieldMappings[$fieldName]);
  1425. }
  1426. /**
  1427. * Gets an array containing all the column names.
  1428. *
  1429. * @param array $fieldNames
  1430. * @return array
  1431. */
  1432. public function getColumnNames(array $fieldNames = null)
  1433. {
  1434. if ($fieldNames === null) {
  1435. return array_keys($this->fieldNames);
  1436. } else {
  1437. $columnNames = array();
  1438. foreach ($fieldNames as $fieldName) {
  1439. $columnNames[] = $this->getColumnName($fieldName);
  1440. }
  1441. return $columnNames;
  1442. }
  1443. }
  1444. /**
  1445. * Returns an array with all the identifier column names.
  1446. *
  1447. * @return array
  1448. */
  1449. public function getIdentifierColumnNames()
  1450. {
  1451. $columnNames = array();
  1452. foreach ($this->identifier as $idProperty) {
  1453. if (isset($this->fieldMappings[$idProperty])) {
  1454. $columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
  1455. continue;
  1456. }
  1457. // Association defined as Id field
  1458. $joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
  1459. $assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
  1460. $columnNames = array_merge($columnNames, $assocColumnNames);
  1461. }
  1462. return $columnNames;
  1463. }
  1464. /**
  1465. * Sets the type of Id generator to use for the mapped class.
  1466. */
  1467. public function setIdGeneratorType($generatorType)
  1468. {
  1469. $this->generatorType = $generatorType;
  1470. }
  1471. /**
  1472. * Checks whether the mapped class uses an Id generator.
  1473. *
  1474. * @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
  1475. */
  1476. public function usesIdGenerator()
  1477. {
  1478. return $this->generatorType != self::GENERATOR_TYPE_NONE;
  1479. }
  1480. /**
  1481. * @return boolean
  1482. */
  1483. public function isInheritanceTypeNone()
  1484. {
  1485. return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
  1486. }
  1487. /**
  1488. * Checks whether the mapped class uses the JOINED inheritance mapping strategy.
  1489. *
  1490. * @return boolean TRUE if the class participates in a JOINED inheritance mapping,
  1491. * FALSE otherwise.
  1492. */
  1493. public function isInheritanceTypeJoined()
  1494. {
  1495. return $this->inheritanceType == self::INHERITANCE_TYPE_JOINED;
  1496. }
  1497. /**
  1498. * Checks whether the mapped class uses the SINGLE_TABLE inheritance mapping strategy.
  1499. *
  1500. * @return boolean TRUE if the class participates in a SINGLE_TABLE inheritance mapping,
  1501. * FALSE otherwise.
  1502. */
  1503. public function isInheritanceTypeSingleTable()
  1504. {
  1505. return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_TABLE;
  1506. }
  1507. /**
  1508. * Checks whether the mapped class uses the TABLE_PER_CLASS inheritance mapping strategy.
  1509. *
  1510. * @return boolean TRUE if the class participates in a TABLE_PER_CLASS inheritance mapping,
  1511. * FALSE otherwise.
  1512. */
  1513. public function isInheritanceTypeTablePerClass()
  1514. {
  1515. return $this->inheritanceType == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
  1516. }
  1517. /**
  1518. * Checks whether the class uses an identity column for the Id generation.
  1519. *
  1520. * @return boolean TRUE if the class uses the IDENTITY generator, FALSE otherwise.
  1521. */
  1522. public function isIdGeneratorIdentity()
  1523. {
  1524. return $this->generatorType == self::GENERATOR_TYPE_IDENTITY;
  1525. }
  1526. /**
  1527. * Checks whether the class uses a sequence for id generation.
  1528. *
  1529. * @return boolean TRUE if the class uses the SEQUENCE generator, FALSE otherwise.
  1530. */
  1531. public function isIdGeneratorSequence()
  1532. {
  1533. return $this->generatorType == self::GENERATOR_TYPE_SEQUENCE;
  1534. }
  1535. /**
  1536. * Checks whether the class uses a table for id generation.
  1537. *
  1538. * @return boolean TRUE if the class uses the TABLE generator, FALSE otherwise.
  1539. */
  1540. public function isIdGeneratorTable()
  1541. {
  1542. return $this->generatorType == self::GENERATOR_TYPE_TABLE;
  1543. }
  1544. /**
  1545. * Checks whether the class has a natural identifier/pk (which means it does
  1546. * not use any Id generator.
  1547. *
  1548. * @return boolean
  1549. */
  1550. public function isIdentifierNatural()
  1551. {
  1552. return $this->generatorType == self::GENERATOR_TYPE_NONE;
  1553. }
  1554. /**
  1555. * Checks whether the class use a UUID for id generation
  1556. *
  1557. * @return boolean
  1558. */
  1559. public function isIdentifierUuid()
  1560. {
  1561. return $this->generatorType == self::GENERATOR_TYPE_UUID;
  1562. }
  1563. /**
  1564. * Gets the type of a field.
  1565. *
  1566. * @param string $fieldName
  1567. * @return \Doctrine\DBAL\Types\Type|string
  1568. */
  1569. public function getTypeOfField($fieldName)
  1570. {
  1571. return isset($this->fieldMappings[$fieldName]) ?
  1572. $this->fieldMappings[$fieldName]['type'] : null;
  1573. }
  1574. /**
  1575. * Gets the type of a column.
  1576. *
  1577. * @param string $columnName
  1578. * @return \Doctrine\DBAL\Types\Type
  1579. */
  1580. public function getTypeOfColumn($columnName)
  1581. {
  1582. return $this->getTypeOfField($this->getFieldName($columnName));
  1583. }
  1584. /**
  1585. * Gets the name of the primary table.
  1586. *
  1587. * @return string
  1588. */
  1589. public function getTableName()
  1590. {
  1591. return $this->table['name'];
  1592. }
  1593. /**
  1594. * Gets the table name to use for temporary identifier tables of this class.
  1595. *
  1596. * @return string
  1597. */
  1598. public function getTemporaryIdTableName()
  1599. {
  1600. // replace dots with underscores because PostgreSQL creates temporary tables in a special schema
  1601. return str_replace('.', '_', $this->getTableName() . '_id_tmp');
  1602. }
  1603. /**
  1604. * Sets the mapped subclasses of this class.
  1605. *
  1606. * @param array $subclasses The names of all mapped subclasses.
  1607. */
  1608. public function setSubclasses(array $subclasses)
  1609. {
  1610. foreach ($subclasses as $subclass) {
  1611. if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
  1612. $this->subClasses[] = $this->namespace . '\\' . $subclass;
  1613. } else {
  1614. $this->subClasses[] = $subclass;
  1615. }
  1616. }
  1617. }
  1618. /**
  1619. * Sets the parent class names.
  1620. * Assumes that the class names in the passed array are in the order:
  1621. * directParent -> directParentParent -> directParentParentParent ... -> root.
  1622. */
  1623. public function setParentClasses(array $classNames)
  1624. {
  1625. $this->parentClasses = $classNames;
  1626. if (count($classNames) > 0) {
  1627. $this->rootEntityName = array_pop($classNames);
  1628. }
  1629. }
  1630. /**
  1631. * Sets the inheritance type used by the class and it's subclasses.
  1632. *
  1633. * @param integer $type
  1634. * @throws MappingException
  1635. * @return void
  1636. */
  1637. public function setInheritanceType($type)
  1638. {
  1639. if ( ! $this->_isInheritanceType($type)) {
  1640. throw MappingException::invalidInheritanceType($this->name, $type);
  1641. }
  1642. $this->inheritanceType = $type;
  1643. }
  1644. /**
  1645. * Sets the association to override association mapping of property for an entity relationship.
  1646. *
  1647. * @param string $fieldName
  1648. * @param array $overrideMapping
  1649. * @throws MappingException
  1650. * @return void
  1651. */
  1652. public function setAssociationOverride($fieldName, array $overrideMapping)
  1653. {
  1654. if ( ! isset($this->associationMappings[$fieldName])) {
  1655. throw MappingException::invalidOverrideFieldName($this->name, $fieldName);
  1656. }
  1657. $mapping = $this->associationMappings[$fieldName];
  1658. if (isset($overrideMapping['joinColumns'])) {
  1659. $mapping['joinColumns'] = $overrideMapping['joinColumns'];
  1660. }
  1661. if (isset($overrideMapping['joinTable'])) {
  1662. $mapping['joinTable'] = $overrideMapping['joinTable'];
  1663. }
  1664. $mapping['joinColumnFieldNames'] = null;
  1665. $mapping['joinTableColumns'] = null;
  1666. $mapping['sourceToTargetKeyColumns'] = null;
  1667. $mapping['relationToSourceKeyColumns'] = null;
  1668. $mapping['relationToTargetKeyColumns'] = null;
  1669. switch ($mapping['type']) {
  1670. case self::ONE_TO_ONE:
  1671. $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
  1672. break;
  1673. case self::ONE_TO_MANY:
  1674. $mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
  1675. break;
  1676. case self::MANY_TO_ONE:
  1677. $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
  1678. break;
  1679. case self::MANY_TO_MANY:
  1680. $mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
  1681. break;
  1682. }
  1683. $this->associationMappings[$fieldName] = $mapping;
  1684. }
  1685. /**
  1686. * Sets the override for a mapped field.
  1687. *
  1688. * @param string $fieldName
  1689. * @param array $overrideMapping
  1690. * @throws MappingException
  1691. * @param array $overrideMapping
  1692. * @return void
  1693. */
  1694. public function setAttributeOverride($fieldName, array $overrideMapping)
  1695. {
  1696. if ( ! isset($this->fieldMappings[$fieldName])) {
  1697. throw MappingException::invalidOverrideFieldName($this->name, $fieldName);
  1698. }
  1699. $mapping = $this->fieldMappings[$fieldName];
  1700. if (isset($mapping['id'])) {
  1701. $overrideMapping['id'] = $mapping['id'];
  1702. }
  1703. if ( ! isset($overrideMapping['type']) || $overrideMapping['type'] === null) {
  1704. $overrideMapping['type'] = $mapping['type'];
  1705. }
  1706. if ( ! isset($overrideMapping['fieldName']) || $overrideMapping['fieldName'] === null) {
  1707. $overrideMapping['fieldName'] = $mapping['fieldName'];
  1708. }
  1709. if ($overrideMapping['type'] !== $mapping['type']) {
  1710. throw MappingException::invalidOverrideFieldType($this->name, $fieldName);
  1711. }
  1712. unset($this->fieldMappings[$fieldName]);
  1713. unset($this->fieldNames[$mapping['columnName']]);
  1714. unset($this->columnNames[$mapping['fieldName']]);
  1715. $this->_validateAndCompleteFieldMapping($overrideMapping);
  1716. $this->fieldMappings[$fieldName] = $overrideMapping;
  1717. }
  1718. /**
  1719. * Checks whether a mapped field is inherited from an entity superclass.
  1720. *
  1721. * @param string $fieldName
  1722. * @return bool TRUE if the field is inherited, FALSE otherwise.
  1723. */
  1724. public function isInheritedField($fieldName)
  1725. {
  1726. return isset($this->fieldMappings[$fieldName]['inherited']);
  1727. }
  1728. /**
  1729. * Check if this entity is the root in any entity-inheritance-hierachy.
  1730. *
  1731. * @return bool
  1732. */
  1733. public function isRootEntity()
  1734. {
  1735. return $this->name == $this->rootEntityName;
  1736. }
  1737. /**
  1738. * Checks whether a mapped association field is inherited from a superclass.
  1739. *
  1740. * @param string $fieldName
  1741. * @return boolean TRUE if the field is inherited, FALSE otherwise.
  1742. */
  1743. public function isInheritedAssociation($fieldName)
  1744. {
  1745. return isset($this->associationMappings[$fieldName]['inherited']);
  1746. }
  1747. /**
  1748. * Sets the name of the primary table the class is mapped to.
  1749. *
  1750. * @param string $tableName The table name.
  1751. * @deprecated Use {@link setPrimaryTable}.
  1752. */
  1753. public function setTableName($tableName)
  1754. {
  1755. $this->table['name'] = $tableName;
  1756. }
  1757. /**
  1758. * Sets the primary table definition. The provided array supports the
  1759. * following structure:
  1760. *
  1761. * name => <tableName> (optional, defaults to class name)
  1762. * indexes => array of indexes (optional)
  1763. * uniqueConstraints => array of constraints (optional)
  1764. *
  1765. * If a key is omitted, the current value is kept.
  1766. *
  1767. * @param array $table The table description.
  1768. */
  1769. public function setPrimaryTable(array $table)
  1770. {
  1771. if (isset($table['name'])) {
  1772. if ($table['name'][0] === '`') {
  1773. $table['name'] = trim($table['name'], '`');
  1774. $this->table['quoted'] = true;
  1775. }
  1776. $this->table['name'] = $table['name'];
  1777. }
  1778. if (isset($table['indexes'])) {
  1779. $this->table['indexes'] = $table['indexes'];
  1780. }
  1781. if (isset($table['uniqueConstraints'])) {
  1782. $this->table['uniqueConstraints'] = $table['uniqueConstraints'];
  1783. }
  1784. if (isset($table['options'])) {
  1785. $this->table['options'] = $table['options'];
  1786. }
  1787. }
  1788. /**
  1789. * Checks whether the given type identifies an inheritance type.
  1790. *
  1791. * @param integer $type
  1792. * @return boolean TRUE if the given type identifies an inheritance type, FALSe otherwise.
  1793. */
  1794. private function _isInheritanceType($type)
  1795. {
  1796. return $type == self::INHERITANCE_TYPE_NONE ||
  1797. $type == self::INHERITANCE_TYPE_SINGLE_TABLE ||
  1798. $type == self::INHERITANCE_TYPE_JOINED ||
  1799. $type == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
  1800. }
  1801. /**
  1802. * Adds a mapped field to the class.
  1803. *
  1804. * @param array $mapping The field mapping.
  1805. * @throws MappingException
  1806. * @return void
  1807. */
  1808. public function mapField(array $mapping)
  1809. {
  1810. $this->_validateAndCompleteFieldMapping($mapping);
  1811. if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationMappings[$mapping['fieldName']])) {
  1812. throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
  1813. }
  1814. $this->fieldMappings[$mapping['fieldName']] = $mapping;
  1815. }
  1816. /**
  1817. * INTERNAL:
  1818. * Adds an association mapping without completing/validating it.
  1819. * This is mainly used to add inherited association mappings to derived classes.
  1820. *
  1821. * @param array $mapping
  1822. * @throws MappingException
  1823. * @return void
  1824. */
  1825. public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
  1826. {
  1827. if (isset($this->associationMappings[$mapping['fieldName']])) {
  1828. throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']);
  1829. }
  1830. $this->associationMappings[$mapping['fieldName']] = $mapping;
  1831. }
  1832. /**
  1833. * INTERNAL:
  1834. * Adds a field mapping without completing/validating it.
  1835. * This is mainly used to add inherited field mappings to derived classes.
  1836. *
  1837. * @param array $fieldMapping
  1838. * @return void
  1839. */
  1840. public function addInheritedFieldMapping(array $fieldMapping)
  1841. {
  1842. $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
  1843. $this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
  1844. $this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
  1845. }
  1846. /**
  1847. * INTERNAL:
  1848. * Adds a named query to this class.
  1849. *
  1850. * @throws MappingException
  1851. * @param array $queryMapping
  1852. */
  1853. public function addNamedQuery(array $queryMapping)
  1854. {
  1855. if (!isset($queryMapping['name'])) {
  1856. throw MappingException::nameIsMandatoryForQueryMapping($this->name);
  1857. }
  1858. if (isset($this->namedQueries[$queryMapping['name']])) {
  1859. throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
  1860. }
  1861. if (!isset($queryMapping['query'])) {
  1862. throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
  1863. }
  1864. $name = $queryMapping['name'];
  1865. $query = $queryMapping['query'];
  1866. $dql = str_replace('__CLASS__', $this->name, $query);
  1867. $this->namedQueries[$name] = array(
  1868. 'name' => $name,
  1869. 'query' => $query,
  1870. 'dql' => $dql
  1871. );
  1872. }
  1873. /**
  1874. * INTERNAL:
  1875. * Adds a named native query to this class.
  1876. *
  1877. * @throws MappingException
  1878. * @param array $queryMapping
  1879. */
  1880. public function addNamedNativeQuery(array $queryMapping)
  1881. {
  1882. if (!isset($queryMapping['name'])) {
  1883. throw MappingException::nameIsMandatoryForQueryMapping($this->name);
  1884. }
  1885. if (isset($this->namedNativeQueries[$queryMapping['name']])) {
  1886. throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
  1887. }
  1888. if (!isset($queryMapping['query'])) {
  1889. throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
  1890. }
  1891. if (!isset($queryMapping['resultClass']) && !isset($queryMapping['resultSetMapping'])) {
  1892. throw MappingException::missingQueryMapping($this->name, $queryMapping['name']);
  1893. }
  1894. $queryMapping['isSelfClass'] = false;
  1895. if (isset($queryMapping['resultClass'])) {
  1896. if($queryMapping['resultClass'] === '__CLASS__') {
  1897. $queryMapping['isSelfClass'] = true;
  1898. $queryMapping['resultClass'] = $this->name;
  1899. } else if (strlen($this->namespace) > 0 && strpos($queryMapping['resultClass'], '\\') === false) {
  1900. $queryMapping['resultClass'] = $this->namespace . '\\' . $queryMapping['resultClass'];
  1901. }
  1902. $queryMapping['resultClass'] = ltrim($queryMapping['resultClass'], '\\');
  1903. }
  1904. $this->namedNativeQueries[$queryMapping['name']] = $queryMapping;
  1905. }
  1906. /**
  1907. * INTERNAL:
  1908. * Adds a sql result set mapping to this class.
  1909. *
  1910. * @throws MappingException
  1911. * @param array $resultMapping
  1912. */
  1913. public function addSqlResultSetMapping(array $resultMapping)
  1914. {
  1915. if (!isset($resultMapping['name'])) {
  1916. throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->name);
  1917. }
  1918. if (isset($this->sqlResultSetMappings[$resultMapping['name']])) {
  1919. throw MappingException::duplicateResultSetMapping($this->name, $resultMapping['name']);
  1920. }
  1921. if (isset($resultMapping['entities'])) {
  1922. foreach ($resultMapping['entities'] as $key => $entityResult) {
  1923. if (!isset($entityResult['entityClass'])) {
  1924. throw MappingException::missingResultSetMappingEntity($this->name, $resultMapping['name']);
  1925. }
  1926. $entityResult['isSelfClass'] = false;
  1927. if($entityResult['entityClass'] === '__CLASS__') {
  1928. $entityResult['isSelfClass'] = true;
  1929. $entityResult['entityClass'] = $this->name;
  1930. } else if (strlen($this->namespace) > 0 && strpos($entityResult['entityClass'], '\\') === false) {
  1931. $entityResult['entityClass'] = $this->namespace . '\\' . $entityResult['entityClass'];
  1932. }
  1933. $resultMapping['entities'][$key]['entityClass'] = ltrim($entityResult['entityClass'], '\\');
  1934. $resultMapping['entities'][$key]['isSelfClass'] = $entityResult['isSelfClass'];
  1935. if (isset($entityResult['fields'])) {
  1936. foreach ($entityResult['fields'] as $k => $field) {
  1937. if (!isset($field['name'])) {
  1938. throw MappingException::missingResultSetMappingFieldName($this->name, $resultMapping['name']);
  1939. }
  1940. if (!isset($field['column'])) {
  1941. $fieldName = $field['name'];
  1942. if(strpos($fieldName, '.')){
  1943. list(, $fieldName) = explode('.', $fieldName);
  1944. }
  1945. $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
  1946. }
  1947. }
  1948. }
  1949. }
  1950. }
  1951. $this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping;
  1952. }
  1953. /**
  1954. * Adds a one-to-one mapping.
  1955. *
  1956. * @param array $mapping The mapping.
  1957. */
  1958. public function mapOneToOne(array $mapping)
  1959. {
  1960. $mapping['type'] = self::ONE_TO_ONE;
  1961. $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
  1962. $this->_storeAssociationMapping($mapping);
  1963. }
  1964. /**
  1965. * Adds a one-to-many mapping.
  1966. *
  1967. * @param array $mapping The mapping.
  1968. */
  1969. public function mapOneToMany(array $mapping)
  1970. {
  1971. $mapping['type'] = self::ONE_TO_MANY;
  1972. $mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
  1973. $this->_storeAssociationMapping($mapping);
  1974. }
  1975. /**
  1976. * Adds a many-to-one mapping.
  1977. *
  1978. * @param array $mapping The mapping.
  1979. */
  1980. public function mapManyToOne(array $mapping)
  1981. {
  1982. $mapping['type'] = self::MANY_TO_ONE;
  1983. // A many-to-one mapping is essentially a one-one backreference
  1984. $mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
  1985. $this->_storeAssociationMapping($mapping);
  1986. }
  1987. /**
  1988. * Adds a many-to-many mapping.
  1989. *
  1990. * @param array $mapping The mapping.
  1991. */
  1992. public function mapManyToMany(array $mapping)
  1993. {
  1994. $mapping['type'] = self::MANY_TO_MANY;
  1995. $mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
  1996. $this->_storeAssociationMapping($mapping);
  1997. }
  1998. /**
  1999. * Stores the association mapping.
  2000. *
  2001. * @param array $assocMapping
  2002. * @throws MappingException
  2003. * @return void
  2004. */
  2005. protected function _storeAssociationMapping(array $assocMapping)
  2006. {
  2007. $sourceFieldName = $assocMapping['fieldName'];
  2008. if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
  2009. throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
  2010. }
  2011. $this->associationMappings[$sourceFieldName] = $assocMapping;
  2012. }
  2013. /**
  2014. * Registers a custom repository class for the entity class.
  2015. *
  2016. * @param string $repositoryClassName The class name of the custom mapper.
  2017. * @return void
  2018. */
  2019. public function setCustomRepositoryClass($repositoryClassName)
  2020. {
  2021. if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false
  2022. && strlen($this->namespace) > 0) {
  2023. $repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
  2024. }
  2025. $this->customRepositoryClassName = $repositoryClassName;
  2026. }
  2027. /**
  2028. * Dispatches the lifecycle event of the given entity to the registered
  2029. * lifecycle callbacks and lifecycle listeners.
  2030. *
  2031. * @param string $lifecycleEvent The lifecycle event.
  2032. * @param \Object $entity The Entity on which the event occured.
  2033. */
  2034. public function invokeLifecycleCallbacks($lifecycleEvent, $entity)
  2035. {
  2036. foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) {
  2037. $entity->$callback();
  2038. }
  2039. }
  2040. /**
  2041. * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
  2042. *
  2043. * @param string $lifecycleEvent
  2044. * @return boolean
  2045. */
  2046. public function hasLifecycleCallbacks($lifecycleEvent)
  2047. {
  2048. return isset($this->lifecycleCallbacks[$lifecycleEvent]);
  2049. }
  2050. /**
  2051. * Gets the registered lifecycle callbacks for an event.
  2052. *
  2053. * @param string $event
  2054. * @return array
  2055. */
  2056. public function getLifecycleCallbacks($event)
  2057. {
  2058. return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
  2059. }
  2060. /**
  2061. * Adds a lifecycle callback for entities of this class.
  2062. *
  2063. * @param string $callback
  2064. * @param string $event
  2065. */
  2066. public function addLifecycleCallback($callback, $event)
  2067. {
  2068. $this->lifecycleCallbacks[$event][] = $callback;
  2069. }
  2070. /**
  2071. * Sets the lifecycle callbacks for entities of this class.
  2072. * Any previously registered callbacks are overwritten.
  2073. *
  2074. * @param array $callbacks
  2075. */
  2076. public function setLifecycleCallbacks(array $callbacks)
  2077. {
  2078. $this->lifecycleCallbacks = $callbacks;
  2079. }
  2080. /**
  2081. * Sets the discriminator column definition.
  2082. *
  2083. * @param array $columnDef
  2084. *
  2085. * @param $columnDef
  2086. * @throws MappingException
  2087. * @return void
  2088. * @see getDiscriminatorColumn()
  2089. */
  2090. public function setDiscriminatorColumn($columnDef)
  2091. {
  2092. if ($columnDef !== null) {
  2093. if ( ! isset($columnDef['name'])) {
  2094. throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name);
  2095. }
  2096. if (isset($this->fieldNames[$columnDef['name']])) {
  2097. throw MappingException::duplicateColumnName($this->name, $columnDef['name']);
  2098. }
  2099. if ( ! isset($columnDef['fieldName'])) {
  2100. $columnDef['fieldName'] = $columnDef['name'];
  2101. }
  2102. if ( ! isset($columnDef['type'])) {
  2103. $columnDef['type'] = "string";
  2104. }
  2105. if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) {
  2106. throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
  2107. }
  2108. $this->discriminatorColumn = $columnDef;
  2109. }
  2110. }
  2111. /**
  2112. * Sets the discriminator values used by this class.
  2113. * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
  2114. *
  2115. * @param array $map
  2116. */
  2117. public function setDiscriminatorMap(array $map)
  2118. {
  2119. foreach ($map as $value => $className) {
  2120. $this->addDiscriminatorMapClass($value, $className);
  2121. }
  2122. }
  2123. /**
  2124. * Add one entry of the discriminator map with a new class and corresponding name.
  2125. *
  2126. * @param string $name
  2127. * @param string $className
  2128. * @throws MappingException
  2129. * @return void
  2130. */
  2131. public function addDiscriminatorMapClass($name, $className)
  2132. {
  2133. if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) {
  2134. $className = $this->namespace . '\\' . $className;
  2135. }
  2136. $className = ltrim($className, '\\');
  2137. $this->discriminatorMap[$name] = $className;
  2138. if ($this->name == $className) {
  2139. $this->discriminatorValue = $name;
  2140. } else {
  2141. if ( ! class_exists($className)) {
  2142. throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
  2143. }
  2144. if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) {
  2145. $this->subClasses[] = $className;
  2146. }
  2147. }
  2148. }
  2149. /**
  2150. * Checks whether the class has a named query with the given query name.
  2151. *
  2152. * @param string $queryName
  2153. * @return boolean
  2154. */
  2155. public function hasNamedQuery($queryName)
  2156. {
  2157. return isset($this->namedQueries[$queryName]);
  2158. }
  2159. /**
  2160. * Checks whether the class has a named native query with the given query name.
  2161. *
  2162. * @param string $queryName
  2163. * @return boolean
  2164. */
  2165. public function hasNamedNativeQuery($queryName)
  2166. {
  2167. return isset($this->namedNativeQueries[$queryName]);
  2168. }
  2169. /**
  2170. * Checks whether the class has a named native query with the given query name.
  2171. *
  2172. * @param string $name
  2173. * @return boolean
  2174. */
  2175. public function hasSqlResultSetMapping($name)
  2176. {
  2177. return isset($this->sqlResultSetMappings[$name]);
  2178. }
  2179. /**
  2180. * {@inheritDoc}
  2181. */
  2182. public function hasAssociation($fieldName)
  2183. {
  2184. return isset($this->associationMappings[$fieldName]);
  2185. }
  2186. /**
  2187. * {@inheritDoc}
  2188. */
  2189. public function isSingleValuedAssociation($fieldName)
  2190. {
  2191. return isset($this->associationMappings[$fieldName]) &&
  2192. ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
  2193. }
  2194. /**
  2195. * {@inheritDoc}
  2196. */
  2197. public function isCollectionValuedAssociation($fieldName)
  2198. {
  2199. return isset($this->associationMappings[$fieldName]) &&
  2200. ! ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
  2201. }
  2202. /**
  2203. * Is this an association that only has a single join column?
  2204. *
  2205. * @param string $fieldName
  2206. * @return bool
  2207. */
  2208. public function isAssociationWithSingleJoinColumn($fieldName)
  2209. {
  2210. return (
  2211. isset($this->associationMappings[$fieldName]) &&
  2212. isset($this->associationMappings[$fieldName]['joinColumns'][0]) &&
  2213. !isset($this->associationMappings[$fieldName]['joinColumns'][1])
  2214. );
  2215. }
  2216. /**
  2217. * Return the single association join column (if any).
  2218. *
  2219. * @param string $fieldName
  2220. * @throws MappingException
  2221. * @return string
  2222. */
  2223. public function getSingleAssociationJoinColumnName($fieldName)
  2224. {
  2225. if ( ! $this->isAssociationWithSingleJoinColumn($fieldName)) {
  2226. throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
  2227. }
  2228. return $this->associationMappings[$fieldName]['joinColumns'][0]['name'];
  2229. }
  2230. /**
  2231. * Return the single association referenced join column name (if any).
  2232. *
  2233. * @param string $fieldName
  2234. * @throws MappingException
  2235. * @return string
  2236. */
  2237. public function getSingleAssociationReferencedJoinColumnName($fieldName)
  2238. {
  2239. if ( ! $this->isAssociationWithSingleJoinColumn($fieldName)) {
  2240. throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
  2241. }
  2242. return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName'];
  2243. }
  2244. /**
  2245. * Used to retrieve a fieldname for either field or association from a given column,
  2246. *
  2247. * This method is used in foreign-key as primary-key contexts.
  2248. *
  2249. * @param string $columnName
  2250. * @throws MappingException
  2251. * @return string
  2252. */
  2253. public function getFieldForColumn($columnName)
  2254. {
  2255. if (isset($this->fieldNames[$columnName])) {
  2256. return $this->fieldNames[$columnName];
  2257. } else {
  2258. foreach ($this->associationMappings as $assocName => $mapping) {
  2259. if ($this->isAssociationWithSingleJoinColumn($assocName) &&
  2260. $this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
  2261. return $assocName;
  2262. }
  2263. }
  2264. throw MappingException::noFieldNameFoundForColumn($this->name, $columnName);
  2265. }
  2266. }
  2267. /**
  2268. * Sets the ID generator used to generate IDs for instances of this class.
  2269. *
  2270. * @param \Doctrine\ORM\Id\AbstractIdGenerator $generator
  2271. */
  2272. public function setIdGenerator($generator)
  2273. {
  2274. $this->idGenerator = $generator;
  2275. }
  2276. /**
  2277. * Sets definition
  2278. * @param array $definition
  2279. */
  2280. public function setCustomGeneratorDefinition(array $definition)
  2281. {
  2282. $this->customGeneratorDefinition = $definition;
  2283. }
  2284. /**
  2285. * Sets the definition of the sequence ID generator for this class.
  2286. *
  2287. * The definition must have the following structure:
  2288. * <code>
  2289. * array(
  2290. * 'sequenceName' => 'name',
  2291. * 'allocationSize' => 20,
  2292. * 'initialValue' => 1
  2293. * 'quoted' => 1
  2294. * )
  2295. * </code>
  2296. *
  2297. * @param array $definition
  2298. */
  2299. public function setSequenceGeneratorDefinition(array $definition)
  2300. {
  2301. if (isset($definition['name']) && $definition['name'] == '`') {
  2302. $definition['name'] = trim($definition['name'], '`');
  2303. $definition['quoted'] = true;
  2304. }
  2305. $this->sequenceGeneratorDefinition = $definition;
  2306. }
  2307. /**
  2308. * Sets the version field mapping used for versioning. Sets the default
  2309. * value to use depending on the column type.
  2310. *
  2311. * @param array $mapping The version field mapping array
  2312. * @throws MappingException
  2313. * @return void
  2314. */
  2315. public function setVersionMapping(array &$mapping)
  2316. {
  2317. $this->isVersioned = true;
  2318. $this->versionField = $mapping['fieldName'];
  2319. if ( ! isset($mapping['default'])) {
  2320. if (in_array($mapping['type'], array('integer', 'bigint', 'smallint'))) {
  2321. $mapping['default'] = 1;
  2322. } else if ($mapping['type'] == 'datetime') {
  2323. $mapping['default'] = 'CURRENT_TIMESTAMP';
  2324. } else {
  2325. throw MappingException::unsupportedOptimisticLockingType($this->name, $mapping['fieldName'], $mapping['type']);
  2326. }
  2327. }
  2328. }
  2329. /**
  2330. * Sets whether this class is to be versioned for optimistic locking.
  2331. *
  2332. * @param boolean $bool
  2333. */
  2334. public function setVersioned($bool)
  2335. {
  2336. $this->isVersioned = $bool;
  2337. }
  2338. /**
  2339. * Sets the name of the field that is to be used for versioning if this class is
  2340. * versioned for optimistic locking.
  2341. *
  2342. * @param string $versionField
  2343. */
  2344. public function setVersionField($versionField)
  2345. {
  2346. $this->versionField = $versionField;
  2347. }
  2348. /**
  2349. * Mark this class as read only, no change tracking is applied to it.
  2350. *
  2351. * @return void
  2352. */
  2353. public function markReadOnly()
  2354. {
  2355. $this->isReadOnly = true;
  2356. }
  2357. /**
  2358. * {@inheritDoc}
  2359. */
  2360. public function getFieldNames()
  2361. {
  2362. return array_keys($this->fieldMappings);
  2363. }
  2364. /**
  2365. * {@inheritDoc}
  2366. */
  2367. public function getAssociationNames()
  2368. {
  2369. return array_keys($this->associationMappings);
  2370. }
  2371. /**
  2372. * {@inheritDoc}
  2373. * @throws InvalidArgumentException
  2374. */
  2375. public function getAssociationTargetClass($assocName)
  2376. {
  2377. if ( ! isset($this->associationMappings[$assocName])) {
  2378. throw new InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
  2379. }
  2380. return $this->associationMappings[$assocName]['targetEntity'];
  2381. }
  2382. /**
  2383. * {@inheritDoc}
  2384. */
  2385. public function getName()
  2386. {
  2387. return $this->name;
  2388. }
  2389. /**
  2390. * Gets the (possibly quoted) identifier column names for safe use in an SQL statement.
  2391. *
  2392. * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
  2393. *
  2394. * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
  2395. * @return array
  2396. */
  2397. public function getQuotedIdentifierColumnNames($platform)
  2398. {
  2399. $quotedColumnNames = array();
  2400. foreach ($this->identifier as $idProperty) {
  2401. if (isset($this->fieldMappings[$idProperty])) {
  2402. $quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted'])
  2403. ? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName'])
  2404. : $this->fieldMappings[$idProperty]['columnName'];
  2405. continue;
  2406. }
  2407. // Association defined as Id field
  2408. $joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
  2409. $assocQuotedColumnNames = array_map(
  2410. function ($joinColumn) use ($platform) {
  2411. return isset($joinColumn['quoted'])
  2412. ? $platform->quoteIdentifier($joinColumn['name'])
  2413. : $joinColumn['name'];
  2414. },
  2415. $joinColumns
  2416. );
  2417. $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
  2418. }
  2419. return $quotedColumnNames;
  2420. }
  2421. /**
  2422. * Gets the (possibly quoted) column name of a mapped field for safe use in an SQL statement.
  2423. *
  2424. * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
  2425. *
  2426. * @param string $field
  2427. * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
  2428. * @return string
  2429. */
  2430. public function getQuotedColumnName($field, $platform)
  2431. {
  2432. return isset($this->fieldMappings[$field]['quoted'])
  2433. ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
  2434. : $this->fieldMappings[$field]['columnName'];
  2435. }
  2436. /**
  2437. * Gets the (possibly quoted) primary table name of this class for safe use in an SQL statement.
  2438. *
  2439. * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
  2440. *
  2441. * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
  2442. * @return string
  2443. */
  2444. public function getQuotedTableName($platform)
  2445. {
  2446. return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name'];
  2447. }
  2448. /**
  2449. * Gets the (possibly quoted) name of the join table.
  2450. *
  2451. * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
  2452. *
  2453. * @param array $assoc
  2454. * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
  2455. * @return string
  2456. */
  2457. public function getQuotedJoinTableName(array $assoc, $platform)
  2458. {
  2459. return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
  2460. }
  2461. /**
  2462. * {@inheritDoc}
  2463. */
  2464. public function isAssociationInverseSide($fieldName)
  2465. {
  2466. return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide'];
  2467. }
  2468. /**
  2469. * {@inheritDoc}
  2470. */
  2471. public function getAssociationMappedByTargetField($fieldName)
  2472. {
  2473. return $this->associationMappings[$fieldName]['mappedBy'];
  2474. }
  2475. /**
  2476. * @param string $targetClass
  2477. * @return array
  2478. */
  2479. public function getAssociationsByTargetClass($targetClass)
  2480. {
  2481. $relations = array();
  2482. foreach ($this->associationMappings as $mapping) {
  2483. if ($mapping['targetEntity'] == $targetClass) {
  2484. $relations[$mapping['fieldName']] = $mapping;
  2485. }
  2486. }
  2487. return $relations;
  2488. }
  2489. }