PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/app/plugins/Db/libraries/Atomik/Model/Builder.php

https://bitbucket.org/fbertagnin/fbwork4
PHP | 625 lines | 295 code | 66 blank | 264 comment | 32 complexity | b7c8e85b9a569f0b0cfc6d0d09f0fae8 MD5 | raw file
  1. <?php
  2. /**
  3. * Atomik Framework
  4. * Copyright (c) 2008-2009 Maxime Bouroumeau-Fuseau
  5. *
  6. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  7. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  8. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  9. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  10. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  11. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  12. * THE SOFTWARE.
  13. *
  14. * @package Atomik
  15. * @subpackage Model
  16. * @author Maxime Bouroumeau-Fuseau
  17. * @copyright 2008-2009 (c) Maxime Bouroumeau-Fuseau
  18. * @license http://www.opensource.org/licenses/mit-license.php
  19. * @link http://www.atomikframework.com
  20. */
  21. /** Atomik_Options */
  22. require_once 'Atomik/Options.php';
  23. /** Atomik_Model_Manager */
  24. require_once 'Atomik/Model/Manager.php';
  25. /** Atomik_Model_Field_Abstract */
  26. require_once 'Atomik/Model/Field/Abstract.php';
  27. /** Atomik_Model_Builder_Reference */
  28. require_once 'Atomik/Model/Builder/Reference.php';
  29. /** Atomik_Model_Builder_Link */
  30. require_once 'Atomik/Model/Builder/Link.php';
  31. /** Atomik_Model_Behaviour_Broker */
  32. require_once 'Atomik/Model/Behaviour/Broker.php';
  33. /**
  34. * A model builder can be used to programatically build models
  35. *
  36. * @package Atomik
  37. * @subpackage Model
  38. */
  39. class Atomik_Model_Builder extends Atomik_Options
  40. {
  41. /**
  42. * @var string
  43. */
  44. public $name;
  45. /**
  46. * @var string
  47. */
  48. public $className;
  49. /**
  50. * @var string
  51. */
  52. public $tableName;
  53. /**
  54. * @var Atomik_Model_Manager
  55. */
  56. protected $_manager;
  57. /**
  58. * @var Atomik_Model_Builder
  59. */
  60. protected $_parentModelBuilder;
  61. /**
  62. * @var string
  63. */
  64. protected $_inheritanceType;
  65. /**
  66. * @var array
  67. */
  68. protected $_fields = array();
  69. /**
  70. * @var bool
  71. */
  72. protected $_autoPrimaryKey = true;
  73. /**
  74. * @var Atomik_Model_Field_Abstract
  75. */
  76. protected $_primaryKeyField;
  77. /**
  78. * @var array
  79. */
  80. protected $_references = array();
  81. /**
  82. * @var Atomik_Model_Behaviour_Broker
  83. */
  84. protected $_behaviourBroker = array();
  85. /**
  86. * @var array
  87. */
  88. protected $_links = array();
  89. /**
  90. * Constructor
  91. *
  92. * @param string $name
  93. * @param array $metadata
  94. */
  95. public function __construct($name, $className = null, $tableName = null)
  96. {
  97. $this->name = $name;
  98. $this->className = $className;
  99. $this->tableName = $tableName === null ? $name : $tableName;
  100. $this->_behaviourBroker = new Atomik_Model_Behaviour_Broker($this);
  101. $this->setPrimaryKeyField();
  102. }
  103. /**
  104. * Sets the manager associated to this builder
  105. *
  106. * @param Atomik_Model_Manager $manager
  107. */
  108. public function setManager(Atomik_Model_Manager $manager = null)
  109. {
  110. if ($manager === null) {
  111. $manager = Atomik_Model_Manager::getDefault();
  112. }
  113. $this->_manager = $manager;
  114. }
  115. /**
  116. * Returns the associated model manager
  117. *
  118. * @return Atomik_Model_Manager
  119. */
  120. public function getManager()
  121. {
  122. if ($this->_manager === null) {
  123. $this->setManager();
  124. }
  125. return $this->_manager;
  126. }
  127. /**
  128. * Sets the parent model
  129. *
  130. * @param string|Atomik_Model_Builder $parentModel
  131. */
  132. public function setParentModel($parentModel)
  133. {
  134. $parent = Atomik_Model_Builder_Factory::get($parentModel);
  135. $type = $parent->getOption('inheritance', 'abstract');
  136. switch($type) {
  137. case 'none':
  138. return;
  139. case 'abstract':
  140. $this->_fields = array_merge($parent->getFields(), $this->_fields);
  141. $this->_options = array_merge($parent->getOptions(), $this->_options);
  142. foreach ($parent->getBehaviourBroker()->getBehaviours() as $behaviour) {
  143. $this->_behaviourBroker->addBehaviour(clone $behaviour);
  144. }
  145. foreach ($parent->getReferences() as $ref) {
  146. $this->addReference(clone $ref);
  147. }
  148. foreach ($parent->getLinks() as $link) {
  149. $this->addLink(clone $link);
  150. }
  151. break;
  152. case 'reference':
  153. $ref = new Atomik_Model_Builder_Reference('parent', Atomik_Model_Builder_Reference::HAS_PARENT);
  154. $ref->target = $parent;
  155. $ref->targetField = $parent->getPrimaryKeyField()->name;
  156. $ref->sourceField = $ref->target . '_' . $ref->targetField;
  157. $this->addReference($ref);
  158. break;
  159. }
  160. $this->_parentModelBuilder = $parent;
  161. $this->_inheritanceType = $type;
  162. }
  163. /**
  164. * Checks if it as a parent
  165. *
  166. * @return bool
  167. */
  168. public function hasParentModel()
  169. {
  170. return $this->_parentModelBuilder !== null;
  171. }
  172. /**
  173. * Returns the parent model builder or null
  174. *
  175. * @return Atomik_Model_Builder
  176. */
  177. public function getParentModel()
  178. {
  179. return $this->_parentModelBuilder;
  180. }
  181. /**
  182. * Returns the type of inheritance used
  183. *
  184. * @return string
  185. */
  186. public function getInheritanceType()
  187. {
  188. return $this->_inheritanceType;
  189. }
  190. /**
  191. * Resets all the fields
  192. *
  193. * @param array $fields
  194. */
  195. public function setFields($fields = array())
  196. {
  197. $this->_fields = array();
  198. foreach ($fields as $field) {
  199. $this->addField($field);
  200. }
  201. }
  202. /**
  203. * Adds a new field
  204. *
  205. * @param Atomik_Model_Field_Abstract $field
  206. */
  207. public function addField(Atomik_Model_Field_Abstract $field)
  208. {
  209. $this->_fields[$field->name] = $field;
  210. if ($field->getOption('primary-key', false)) {
  211. $this->setPrimaryKeyField($field);
  212. }
  213. }
  214. /**
  215. * Checks if a field exists
  216. *
  217. * @param string $name
  218. * @return bool
  219. */
  220. public function hasField($name)
  221. {
  222. return isset($this->_fields[(string) $name]);
  223. }
  224. /**
  225. * Returns a field object
  226. *
  227. * @param string $name
  228. * @return Atomik_Model_Field_Abstract|bool False if the field does not exist
  229. */
  230. public function getField($name)
  231. {
  232. if (!isset($this->_fields[$name])) {
  233. return false;
  234. }
  235. return $this->_fields[$name];
  236. }
  237. /**
  238. * Returns the field with the specifiec option
  239. *
  240. * @param string $option
  241. * @return Atomik_Model_Field_Abstract
  242. */
  243. public function getFieldWithOption($option)
  244. {
  245. foreach ($this->_fields as $field) {
  246. if ($field->hasOption($option)) {
  247. return $field;
  248. }
  249. }
  250. return null;
  251. }
  252. /**
  253. * Returns all fields
  254. *
  255. * @return array
  256. */
  257. public function getFields()
  258. {
  259. return $this->_fields;
  260. }
  261. /**
  262. * Sets the primary key field
  263. *
  264. * If $field is null, will use or create a field named id
  265. *
  266. * @param Atomik_Model_Field_Abstract $field
  267. */
  268. public function setPrimaryKeyField(Atomik_Model_Field_Abstract $field = null)
  269. {
  270. $removeAutoKey = true;
  271. if ($field === null) {
  272. if ($this->_primaryKeyField !== null) {
  273. // primary key already defined
  274. return;
  275. }
  276. // checks if there is a field named id
  277. if (($field = $this->getField('id')) === false) {
  278. require_once 'Atomik/Model/Field.php';
  279. $field = new Atomik_Model_Field('id', 'int', array('form-ignore' => true));
  280. $this->addField($field);
  281. $this->_autoPrimaryKey = true;
  282. $removeAutoKey = false;
  283. }
  284. }
  285. if ($removeAutoKey && $this->_autoPrimaryKey) {
  286. unset($this->_fields['id']);
  287. $this->_autoPrimaryKey = false;
  288. }
  289. $this->_primaryKeyField = $field;
  290. }
  291. /**
  292. * Returns the field used as the primary key.
  293. *
  294. * @return Atomik_Model_Field_Abstract
  295. */
  296. public function getPrimaryKeyField()
  297. {
  298. if ($this->_primaryKeyField === null) {
  299. $this->setPrimaryKeyField();
  300. }
  301. return $this->_primaryKeyField;
  302. }
  303. /**
  304. * Checks if a field is the primary key
  305. *
  306. * @param Atomik_Model_Field_Abstract $field
  307. * @return bool
  308. */
  309. public function isFieldThePrimaryKey(Atomik_Model_Field_Abstract $field)
  310. {
  311. return $this->_primaryKeyField == $field;
  312. }
  313. /**
  314. * Resets all the references
  315. *
  316. * @param array $references
  317. */
  318. public function setReferences($references = array())
  319. {
  320. $this->_references = array();
  321. foreach ($references as $reference) {
  322. $this->addReference($reference);
  323. }
  324. }
  325. /**
  326. * Adds a new reference
  327. *
  328. * @param Atomik_Model_Builder_Reference $reference
  329. */
  330. public function addReference(Atomik_Model_Builder_Reference $reference)
  331. {
  332. if (!$this->hasField($reference->sourceField)) {
  333. $this->addField(new Atomik_Model_Field($reference->sourceField, 'int'));
  334. }
  335. $this->_references[$reference->name] = $reference;
  336. }
  337. /**
  338. * Checks if a reference exists
  339. *
  340. * @param string $name
  341. * @return bool
  342. */
  343. public function hasReference($name)
  344. {
  345. return isset($this->_references[$name]);
  346. }
  347. /**
  348. * Returns a reference object
  349. *
  350. * @param string $name
  351. * @return Atomik_Model_Builder_Reference|bool False if not found
  352. */
  353. public function getReference($name)
  354. {
  355. if (!isset($this->_references[$name])) {
  356. return false;
  357. }
  358. return $this->_references[$name];
  359. }
  360. /**
  361. * Returns a reference from the source field
  362. *
  363. * @param Atomik_Model_Field_Abstract $field
  364. * @return Atomik_Model_Builder_Reference
  365. */
  366. public function getReferenceFromSourceField(Atomik_Model_Field_Abstract $field)
  367. {
  368. foreach ($this->_references as $reference) {
  369. if ($reference->sourceField == $field->name) {
  370. return $reference;
  371. }
  372. }
  373. }
  374. /**
  375. * Returns all references or only the one associated to a model
  376. *
  377. * @param string $modelName
  378. * @param string $type Reference type
  379. * @return array
  380. */
  381. public function getReferences($targetModel = null, $type = null)
  382. {
  383. if ($targetModel === null) {
  384. return $this->_references;
  385. }
  386. $references = array();
  387. foreach ($this->_references as $reference) {
  388. if ($reference->isTarget($targetModel) && ($type === null || $reference->type == $type)) {
  389. $references[] = $reference;
  390. }
  391. }
  392. return $references;
  393. }
  394. /**
  395. * Checks if a field is part of a reference
  396. *
  397. * @param Atomik_Model_Field_Abstract $field
  398. * @return bool
  399. */
  400. public function isFieldPartOfReference(Atomik_Model_Field_Abstract $field)
  401. {
  402. foreach ($this->_references as $reference) {
  403. if ($reference->sourceField == $field->name) {
  404. return true;
  405. }
  406. }
  407. return false;
  408. }
  409. /**
  410. * Checks if the specified model is related to this one
  411. *
  412. * @param Atomik_Model_Builder $builder
  413. * @return bool
  414. */
  415. public function isModelRelated(Atomik_Model_Builder $builder)
  416. {
  417. foreach ($this->_references as $reference) {
  418. if ($reference->isTarget($builder)) {
  419. return true;
  420. }
  421. }
  422. return false;
  423. }
  424. /**
  425. * Checks if the specified model is a child of this one
  426. *
  427. * @param Atomik_Model_Builder $builder
  428. * @return bool
  429. */
  430. public function isChildModel(Atomik_Model_Builder $builder)
  431. {
  432. foreach ($this->_references as $reference) {
  433. if ($reference->isTarget($builder) && $reference->type != Atomik_Model_Builder_Reference::HAS_PARENT) {
  434. return true;
  435. }
  436. }
  437. return false;
  438. }
  439. /**
  440. * Checks if the specified model is the parent of this one
  441. *
  442. * @param Atomik_Model_Builder $builder
  443. * @return bool
  444. */
  445. public function isParentModel(Atomik_Model_Builder $builder)
  446. {
  447. foreach ($this->_references as $reference) {
  448. if ($reference->isTarget($builder) && $reference->type == Atomik_Model_Builder_Reference::HAS_PARENT) {
  449. return true;
  450. }
  451. }
  452. return false;
  453. }
  454. /**
  455. * Returns the behaviour broker
  456. *
  457. * @return Atomik_Model_Behaviour_Broker
  458. */
  459. public function getBehaviourBroker()
  460. {
  461. return $this->_behaviourBroker;
  462. }
  463. /**
  464. * Resets all links
  465. *
  466. * @param array $links
  467. */
  468. public function setLinks($links)
  469. {
  470. $this->_links = array();
  471. foreach ($links as $link) {
  472. $this->addLink($link);
  473. }
  474. }
  475. /**
  476. * Adds a new link
  477. *
  478. * @param Atomik_Model_Builder_Link $link
  479. */
  480. public function addLink(Atomik_Model_Builder_Link $link)
  481. {
  482. $this->_links[$link->name] = $link;
  483. }
  484. /**
  485. * Checks if this builder as the specified link
  486. *
  487. * @param string $name
  488. */
  489. public function hasLink($name)
  490. {
  491. return isset($this->_links[$name]);
  492. }
  493. /**
  494. * Returns the link with the specified name
  495. *
  496. * @param string $name
  497. */
  498. public function getLink($name)
  499. {
  500. if (!isset($this->_links[$name])) {
  501. return null;
  502. }
  503. return $this->_links[$name];
  504. }
  505. /**
  506. * Returns all links
  507. *
  508. * @return array
  509. */
  510. public function getLinks()
  511. {
  512. return $this->_links;
  513. }
  514. /**
  515. * Creates a model instance
  516. *
  517. * @see Atomik_Model::__construct()
  518. * @param array $values
  519. * @param bool $new
  520. * @return Atomik_Model
  521. */
  522. public function createInstance($values = array(), $new = true)
  523. {
  524. $className = $this->className;
  525. if ($className === null) {
  526. /** Atomik_Model */
  527. require_once 'Atomik/Model.php';
  528. $className = 'Atomik_Model';
  529. }
  530. $dataToFilter = array_intersect_key($values, $this->_fields);
  531. $data = array_diff_key($values, $this->_fields);
  532. foreach ($dataToFilter as $key => $value) {
  533. $data[$key] = $this->_fields[$key]->filterInput($value);
  534. }
  535. $this->_behaviourBroker->notifyBeforeCreateInstance($this, $data, $new);
  536. $instance = new $className($data, $new, $this);
  537. $this->_behaviourBroker->notifyAfterCreateInstance($this, $instance);
  538. return $instance;
  539. }
  540. /**
  541. * Returns a form for this builder
  542. *
  543. * @return Atomik_Model_Form
  544. */
  545. public function getForm()
  546. {
  547. require_once 'Atomik/Model/Form.php';
  548. return new Atomik_Model_Form($this);
  549. }
  550. /**
  551. * Returns the builder name
  552. *
  553. * @return string
  554. */
  555. public function __toString()
  556. {
  557. return $this->name;
  558. }
  559. }