PageRenderTime 72ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/library/Adapto/Meta/Policy.php

http://github.com/egeniq/adapto
PHP | 2005 lines | 971 code | 226 blank | 808 comment | 201 complexity | bf59b0743a4a10dfd5124ae4b76b665e MD5 | raw file

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

  1. <?php
  2. /**
  3. * This file is part of the Adapto Toolkit.
  4. * Detailed copyright and licensing information can be found
  5. * in the doc/COPYRIGHT and doc/LICENSE files which should be
  6. * included in the distribution.
  7. *
  8. * @package adapto
  9. * @subpackage meta
  10. *
  11. * @copyright (c) 2004-2008 Peter C. Verhage
  12. * @license http://www.achievo.org/atk/licensing ATK Open Source License
  13. *
  14. */
  15. /**
  16. * The default meta policy.
  17. *
  18. * @author petercv
  19. *
  20. * @package adapto
  21. * @subpackage meta
  22. */
  23. class Adapto_Meta_Policy
  24. {
  25. /**
  26. * No default value.
  27. */
  28. const NO_DEFAULT_VALUE = '!@NO_DEFAULT_VALUE@!';
  29. /**
  30. * The entity which is being constructed by the policy.
  31. *
  32. * @var atkMetaEntity
  33. */
  34. protected $m_entity = null;
  35. /**
  36. * The meta grammar which is being used by the policy.
  37. *
  38. * @var atkMetaGrammar
  39. */
  40. protected $m_grammar = null;
  41. /**
  42. * The meta compiler which is being used by the policy.
  43. *
  44. * @var atkMetaCompiler
  45. */
  46. protected $m_compiler = null;
  47. /**
  48. * The meta handler which is begin used by the policy. A function name or
  49. * handler array (class/object and method name). If set to null we will check
  50. * if the metan entity contains a method called meta and will call this instead.
  51. *
  52. * @var mixed
  53. */
  54. protected $m_handler = null;
  55. /**
  56. * Table meta data.
  57. *
  58. * @var array
  59. */
  60. protected $m_metaData = null;
  61. /**
  62. * Entity database name.
  63. *
  64. * @var string
  65. */
  66. protected $m_entityDatabase = null;
  67. /**
  68. * Entity table name.
  69. *
  70. * @var string
  71. */
  72. protected $m_entityTable = null;
  73. /**
  74. * Entity sequence name.
  75. *
  76. * @var string
  77. */
  78. protected $m_entitySequence = null;
  79. /**
  80. * Entity flags.
  81. *
  82. * @var int
  83. */
  84. protected $m_entityFlags = null;
  85. /**
  86. * Entity descriptor.
  87. *
  88. * @var string
  89. */
  90. protected $m_entityDescriptor = null;
  91. /**
  92. * Entity (default) order.
  93. *
  94. * @var string
  95. */
  96. protected $m_entityOrder = null;
  97. /**
  98. * Entity index column.
  99. *
  100. * @var string
  101. */
  102. protected $m_entityIndex = null;
  103. /**
  104. * Entity filter.
  105. *
  106. * @var string
  107. */
  108. protected $m_entityFilter = null;
  109. /**
  110. * Entity security alias.
  111. *
  112. * @var string
  113. */
  114. protected $m_entitySecurityAlias = null;
  115. /**
  116. * Entity security map.
  117. *
  118. * @var string
  119. */
  120. protected $m_entitySecurityMap = null;
  121. /**
  122. * Included attributes.
  123. *
  124. * @var array|null
  125. */
  126. protected $m_includes = null;
  127. /**
  128. * Excluded attributes.
  129. *
  130. * @var array|null
  131. */
  132. protected $m_excludes = null;
  133. /**
  134. * Entity attributes.
  135. *
  136. * @var array
  137. */
  138. protected $m_attrs = array();
  139. /**
  140. * Returns an instance of the meta policy using the given class. If no class
  141. * is specified the default meta policy is used determined using the
  142. * $config_meta_policy variable.
  143. *
  144. * @param atkMetaEntity $entity policy entity
  145. * @param string $class full ATK policy class path
  146. *
  147. * @return Adapto_Meta_Policy meta policy
  148. */
  149. public static function create(atkMetaEntity $entity, $class=null)
  150. {
  151. if (!is_string($class) || strlen($class) == 0)
  152. {
  153. $class = Adapto_Config::getGlobal("meta_policy", "atk.meta.atkmetapolicy");
  154. }
  155. return Adapto_ClassLoader::create($class, $entity);
  156. }
  157. /**
  158. * Constructor.
  159. *
  160. * @param atkMetaEntity $entity policy entity
  161. */
  162. public function __construct(atkMetaEntity $entity)
  163. {
  164. $this->setEntity($entity);
  165. }
  166. /**
  167. * Returns the entity for this policy.
  168. *
  169. * @return atkEntity policy entity
  170. */
  171. public function getEntity()
  172. {
  173. return $this->m_entity;
  174. }
  175. /**
  176. * Sets the entity for this policy.
  177. *
  178. * @param atkEntity $entity policy entity
  179. */
  180. public function setEntity(atkMetaEntity $entity)
  181. {
  182. $this->m_entity = $entity;
  183. }
  184. /**
  185. * Returns the meta grammar.
  186. *
  187. * @return atkMetaGrammar the meta grammar
  188. */
  189. public function getGrammar()
  190. {
  191. return $this->m_grammar;
  192. }
  193. /**
  194. * Sets the meta grammar.
  195. *
  196. * @param atkMetaGrammar $grammar the meta grammar
  197. */
  198. public function setGrammar(atkMetaGrammar $grammar)
  199. {
  200. $this->m_grammar = $grammar;
  201. }
  202. /**
  203. * Returns the meta compiler.
  204. *
  205. * @return atkMetaCompiler the meta compiler
  206. */
  207. public function getCompiler()
  208. {
  209. return $this->m_compiler;
  210. }
  211. /**
  212. * Sets the meta compiler.
  213. *
  214. * @param atkMetaCompiler $compiler the meta compiler
  215. */
  216. public function setCompiler(atkMetaCompiler $compiler)
  217. {
  218. $this->m_compiler = $compiler;
  219. }
  220. /**
  221. * Returns the meta handler.
  222. *
  223. * @return mixed the meta handler
  224. */
  225. public function getHandler()
  226. {
  227. return $this->m_handler;
  228. }
  229. /**
  230. * Sets the meta handler.
  231. *
  232. * @param mixed $handler the meta compiler
  233. */
  234. public function setHandler($handler)
  235. {
  236. $this->m_handler = $handler;
  237. }
  238. /**
  239. * Returns the meta data for this policy's table.
  240. *
  241. * @return array meta data
  242. */
  243. public function getMetaData()
  244. {
  245. return $this->m_metaData;
  246. }
  247. /**
  248. * Sets the meta data for this policy's table.
  249. *
  250. * @param array $metaData meta data
  251. */
  252. protected function _setMetaData($metaData)
  253. {
  254. $this->m_metaData = $metaData;
  255. }
  256. /**
  257. * Returns the entity database.
  258. *
  259. * @return string database name
  260. */
  261. public function getEntityDatabase()
  262. {
  263. return $this->m_entityDatabase;
  264. }
  265. /**
  266. * Sets the entity database.
  267. *
  268. * Only for internal use, because it's too late to set this from inside the meta method.
  269. *
  270. * @param string $database database name
  271. */
  272. protected function _setEntityDatabase($database)
  273. {
  274. $this->m_entityDatabase = $database;
  275. }
  276. /**
  277. * Returns the entity table.
  278. *
  279. * @return string table name
  280. */
  281. public function getEntityTable()
  282. {
  283. return $this->m_entityTable;
  284. }
  285. /**
  286. * Sets the entity table name.
  287. *
  288. * Only for internal use, because it's too late to set this from inside the meta method.
  289. *
  290. * @param string $table table name
  291. */
  292. protected function _setEntityTable($table)
  293. {
  294. $this->m_entityTable = $table;
  295. }
  296. /**
  297. * Returns the entity sequence.
  298. *
  299. * @return string sequence name
  300. */
  301. public function getEntitySequence()
  302. {
  303. return $this->m_entitySequence;
  304. }
  305. /**
  306. * Sets the entity sequence name.
  307. *
  308. * @param string $sequence sequence name
  309. */
  310. public function setEntitySequence($sequence)
  311. {
  312. $this->m_entitySequence = $sequence;
  313. }
  314. /**
  315. * Returns the entity flags.
  316. *
  317. * @return int entity flags
  318. */
  319. public function getEntityFlags()
  320. {
  321. return $this->m_entityFlags;
  322. }
  323. /**
  324. * Sets the entity flags
  325. *
  326. * @param int $flags entity flags
  327. */
  328. public function setEntityFlags($flags)
  329. {
  330. $this->m_entityFlags = $flags;
  331. }
  332. /**
  333. * Returns the entity descriptor.
  334. *
  335. * @return string descriptor
  336. */
  337. public function getEntityDescriptor()
  338. {
  339. return $this->m_entityDescriptor;
  340. }
  341. /**
  342. * Sets the entity descriptor.
  343. *
  344. * @param string $descriptor descriptor
  345. */
  346. public function setEntityDescriptor($descriptor)
  347. {
  348. $this->m_entityDescriptor = $descriptor;
  349. }
  350. /**
  351. * Returns the (default) entity order.
  352. *
  353. * @return string entity order
  354. */
  355. public function getEntityOrder()
  356. {
  357. return $this->m_entityOrder;
  358. }
  359. /**
  360. * Sets the (default) entity order.
  361. *
  362. * @param string $order entity order
  363. */
  364. public function setEntityOrder($order)
  365. {
  366. $this->m_entityOrder = $order;
  367. }
  368. /**
  369. * Returns the index column.
  370. *
  371. * @return string index column
  372. */
  373. public function getEntityIndex()
  374. {
  375. return $this->m_entityIndex;
  376. }
  377. /**
  378. * Sets the entity index column.
  379. *
  380. * @param string $column index column
  381. */
  382. public function setEntityIndex($column)
  383. {
  384. $this->m_entityIndex = $column;
  385. }
  386. /**
  387. * Returns the entity filter.
  388. *
  389. * @return string filter
  390. */
  391. public function getEntityFilter()
  392. {
  393. return $this->m_entityFilter;
  394. }
  395. /**
  396. * Sets the entity filter.
  397. *
  398. * @param string $filter filter
  399. */
  400. public function setEntityFilter($filter)
  401. {
  402. $this->m_entityFilter = $filter;
  403. }
  404. /**
  405. * Returns the entity security alias.
  406. *
  407. * @return string security alias
  408. */
  409. public function getEntitySecurityAlias()
  410. {
  411. return $this->m_entitySecurityAlias;
  412. }
  413. /**
  414. * Sets the entity security alias.
  415. *
  416. * @param string $alias security alias
  417. */
  418. public function setEntitySecurityAlias($alias)
  419. {
  420. $this->m_entitySecurityAlias = $alias;
  421. }
  422. /**
  423. * Returns the additional entity security map
  424. *
  425. * @return array security map
  426. */
  427. public function getEntitySecurityMap()
  428. {
  429. return $this->m_entitySecurityMap;
  430. }
  431. /**
  432. * Sets the entity additional security map.
  433. *
  434. * @param array $map security map array
  435. */
  436. public function setEntitySecurityMap($map)
  437. {
  438. $this->m_entitySecurityMap = $map;
  439. }
  440. /**
  441. * Get attribute type and params for the given attribute/column.
  442. *
  443. * Returns an array which looks like the following:
  444. * array("type" => ..., "params" => array(...))
  445. *
  446. * @param string $name attribute/column name
  447. * @param array $meta column meta data
  448. *
  449. * @return array type and params
  450. */
  451. protected function _getTypeAndParams($name, $meta)
  452. {
  453. $type = NULL;
  454. $params = array();
  455. if (in_array($name, array("passw", "password")))
  456. {
  457. $type = "atk.attributes.atkpasswordattribute";
  458. $params = array(false, 0);
  459. }
  460. else if (in_array($name, array("email", "e-mail")))
  461. {
  462. $type = "atk.attributes.atkemailattribute";
  463. $params = array(false);
  464. }
  465. else if ($name == 'country')
  466. {
  467. $type = 'atk.attributes.atkcountryattribute';
  468. }
  469. else if ($name == 'timezone')
  470. {
  471. $type = 'atk.attributes.atktimezoneattribute';
  472. }
  473. else if ($name == 'created_at' || $name == 'created_on')
  474. {
  475. $type = 'atk.attributes.atkcreatestampattribute';
  476. }
  477. else if ($name == 'updated_at' || $name == 'updated_on')
  478. {
  479. $type = 'atk.attributes.atkupdatestampattribute';
  480. }
  481. else if ($name == 'created_by')
  482. {
  483. $type = 'atk.attributes.atkcreatedbyattribute';
  484. }
  485. else if ($name == 'updated_by')
  486. {
  487. $type = 'atk.attributes.atkupdatedbyattribute';
  488. }
  489. else if ($meta['gentype'] == 'number' && $meta['len'] == 1 &&
  490. (substr($name, 0, 3) == 'is_' || substr($name, 0, 4) == 'has_'))
  491. {
  492. $type = 'atk.attributes.atkboolattribute';
  493. }
  494. else
  495. {
  496. switch($meta['gentype'])
  497. {
  498. // string
  499. case "string":
  500. $type = "atk.attributes.atkattribute";
  501. break;
  502. // text
  503. case "text":
  504. $type = "atk.attributes.atktextattribute";
  505. break;
  506. // number
  507. case "number":
  508. case "decimal":
  509. $type = "atk.attributes.atknumberattribute";
  510. break;
  511. // date
  512. case "date":
  513. $type = "atk.attributes.atkdateattribute";
  514. break;
  515. // time
  516. case "time":
  517. $type = "atk.attributes.atktimeattribute";
  518. break;
  519. // datetime
  520. case "datetime":
  521. $type = "atk.attributes.atkdatetimeattribute";
  522. break;
  523. }
  524. }
  525. return array("type" => $type, "params" => $params);
  526. }
  527. /**
  528. * Returns the auto-detected flags for the given attribute.
  529. *
  530. * @param string $name attribute/column name
  531. * @param array $meta column meta data
  532. *
  533. * @return int flags
  534. */
  535. protected function _getFlags($name, $meta)
  536. {
  537. $flags =
  538. (hasFlag($meta['flags'], MF_PRIMARY) ? AF_PRIMARY : 0) |
  539. (hasFlag($meta['flags'], MF_UNIQUE) ? AF_UNIQUE : 0) |
  540. (hasFlag($meta['flags'], MF_NOT_NULL) ? AF_OBLIGATORY : 0) |
  541. (hasFlag($meta['flags'], MF_AUTO_INCREMENT|MF_PRIMARY) ? AF_AUTOKEY : 0) |
  542. ($meta['gentype'] == "text" ? AF_HIDE_LIST : 0);
  543. if (hasFlag($flags, AF_PRIMARY) && $meta['num'] == 0 &&
  544. in_array($name, array("id", $meta['table']."id", $meta['table']."_id")))
  545. $flags |= AF_AUTOKEY;
  546. if (in_array($name, array("passw", "password")))
  547. {
  548. $flags |= AF_HIDE_LIST;
  549. }
  550. return $flags;
  551. }
  552. /**
  553. * Get auto-detected order for the given attribute.
  554. *
  555. * @param string $name column/attribute name
  556. * @param array $meta column meta data
  557. *
  558. * @return int order
  559. */
  560. protected function _getOrder($name, $meta)
  561. {
  562. return ($meta['num'] + 1) * 100;
  563. }
  564. /**
  565. * Get auto-detected default value for the given attribute.
  566. *
  567. * @param string $name column/attribute name
  568. * @param array $meta column meta data
  569. *
  570. * @return mixed default value
  571. */
  572. protected function _getDefaultValue($name, $meta)
  573. {
  574. if (array_key_exists('default', $meta) && $meta['default'] == "NOW" && in_array($meta['gentype'], array('date', 'time', 'datetime')))
  575. {
  576. $stamp = getdate();
  577. $date = array('day' => $stamp['yday'], 'month' => $stamp['mon'], 'year' => $stamp['year']);
  578. $time = array('hours' => $stamp['hours'], 'minutes' => $stamp['minutes'], 'seconds' => $stamp['seconds']);
  579. return array_merge($meta['gentype'] == 'time' ? array() : $date, $meta['gentype'] == 'date' ? array() : $time);
  580. }
  581. else if (array_key_exists('default', $meta))
  582. {
  583. return $meta['default'];
  584. }
  585. else
  586. {
  587. return self::NO_DEFAULT_VALUE;
  588. }
  589. }
  590. /**
  591. * Calls a method of this object with the given parameters.
  592. *
  593. * @param string $method the method name
  594. * @param array $params the method parameters
  595. *
  596. * @return mixed result
  597. */
  598. protected function _call($method, $params)
  599. {
  600. return call_user_func_array(array($this, $method), $params);
  601. }
  602. /**
  603. * Import attribute of the given type, we do this as soon as attributes
  604. * are added to the metan entity or the type has been changed so that the
  605. * flags for the attribute are available.
  606. *
  607. * @param string $type attribute type
  608. */
  609. public function importAttribute($type)
  610. {
  611. if (strpos($type, '.') === false && atkexists("attribute", $this->getEntity()->getModule().'.'.$type))
  612. atkuse("attribute", $this->getEntity()->getModule().'.'.$type);
  613. elseif (strpos($type, '.') === false && atkexists("relation", $this->getEntity()->getModule().'.'.$type))
  614. atkuse("relation", $this->getEntity()->getModule().'.'.$type);
  615. elseif (atkexists("attribute", $type))
  616. atkuse("attribute", $type);
  617. elseif (atkexists("relation", $type))
  618. atkuse("relation", $type);
  619. else if (!
  620. throw new Exception("Cannot import attribute of type {$type}");
  621. }
  622. /**
  623. * Returns the attribute modifier for the given attributes. The modifier allows
  624. * you to add flags, set tabs etc. through a fluent interface.
  625. *
  626. * This method can also be called with multiple attribute string arguments.
  627. *
  628. * @param string|array $attrs attribute name(s)
  629. *
  630. * @return atkMetaAttributeModifier
  631. */
  632. public function get($attrs)
  633. {
  634. if (!is_array($attrs))
  635. $attrs = func_get_args();
  636. return Adapto_ClassLoader::create('atk.meta.atkmetaattributemodifier', $this, $attrs);
  637. }
  638. /**
  639. * Returns an attribute modifier for all attributes.The modifier allows
  640. * you to add flags, set tabs etc. through a fluent interface.
  641. *
  642. * @return atkMetaAttributeModifier
  643. */
  644. public function getAll()
  645. {
  646. return $this->get($this->getAttributeNames());
  647. }
  648. /**
  649. * Returns the currently set includes (if applicable).
  650. *
  651. * @return array includes list
  652. */
  653. public function getIncludes()
  654. {
  655. return $this->m_includes;
  656. }
  657. /**
  658. * Set includes. Implicitly sets the order!
  659. *
  660. * NOTE: Attributes manually added through the policy will always be
  661. * included unless they are explicitly removed using the remove
  662. * method!
  663. *
  664. * This method can also be called with multiple attribute string arguments.
  665. *
  666. * @param string|array $attrs attribute name(s)
  667. */
  668. public function setIncludes($attrs)
  669. {
  670. if (!is_array($attrs))
  671. $attrs = func_get_args();
  672. $this->m_includes = $attrs;
  673. $this->m_excludes = NULL;
  674. $this->setOrder($attrs);
  675. }
  676. /**
  677. * Returns the currently set excludes (if applicable).
  678. *
  679. * @return array excludes list
  680. */
  681. public function getExcludes()
  682. {
  683. return $this->m_excludes;
  684. }
  685. /**
  686. * Set excludes.
  687. *
  688. * NOTE: Attributes manually added through the policy will always be
  689. * included unless they are explicitly removed using the remove
  690. * method!
  691. *
  692. * This method can also be called with multiple attribute string arguments.
  693. *
  694. * @param string|array $attrs attribute name(s)
  695. */
  696. public function setExcludes($attrs)
  697. {
  698. if (!is_array($attrs))
  699. $attrs = func_get_args();
  700. $this->m_excludes = $attrs;
  701. $this->m_includes = NULL;
  702. }
  703. /**
  704. * Compares two attributes based on their order.
  705. *
  706. * @param array $a attribute
  707. * @param array $b attribute
  708. *
  709. * @return int order (a == b ? 0 : (a < b ? -1 : 1))
  710. */
  711. public static function cmpAttributes($a, $b)
  712. {
  713. if (!isset($a['order'], $b['order']) || $a['order'] == $b['order'])
  714. {
  715. return 0;
  716. }
  717. else if ($a['order'] < $b['order'])
  718. {
  719. return -1;
  720. }
  721. else
  722. {
  723. return 1;
  724. }
  725. }
  726. /**
  727. * Sort the attributes based on their order.
  728. */
  729. protected function sortAttributes()
  730. {
  731. uasort($this->m_attrs, array('Adapto_Meta_Policy', 'cmpAttributes'));
  732. }
  733. /**
  734. * Sets the attribute order. All attributes not mentioned will be moved to
  735. * the bottom using their current order.
  736. *
  737. * This method can also be called with multiple attribute string arguments.
  738. *
  739. * @param string|array $attrs attribute name(s)
  740. */
  741. public function setOrder($attrs)
  742. {
  743. if (func_num_args() > 1)
  744. $attrs = func_get_args();
  745. else if (!is_array($attrs))
  746. $attrs = array($attrs);
  747. $order = array_merge($attrs, array_diff(array_keys($this->m_attrs), $attrs));
  748. foreach ($order as $i => $key)
  749. $this->m_attrs[$key]['order'] = ($i + 1) * 100;
  750. $this->sortAttributes();
  751. }
  752. /**
  753. * Set the default value for the given attribute(s).
  754. *
  755. * This method can also be called with multiple attribute string arguments
  756. * as long as the last argument contains the default value.
  757. *
  758. * @param array|string $attrs list of attribute names or single attribute name
  759. * @param mixed $value default value
  760. */
  761. public function setDefaultValue($attrs, $value)
  762. {
  763. if (func_num_args() > 2)
  764. {
  765. $attrs = func_get_args();
  766. $tabs = array_pop($attrs);
  767. }
  768. else if (!is_array($attrs))
  769. $attrs = array($attrs);
  770. foreach ($attrs as $attr)
  771. if (array_key_exists($attr, $this->m_attrs))
  772. $this->m_attrs[$attr]["default"] = $value;
  773. }
  774. /**
  775. * Set flag(s) for the given attribute or list of attributes.
  776. *
  777. * This method can also be called with multiple attribute string arguments
  778. * as long as the last argument contains the flag(s).
  779. *
  780. * NOTE: this method will overwrite all currently set flags, including
  781. * automatically detected flags!
  782. *
  783. * @param array|string $attrs list of attribute names or single attribute name
  784. * @param int $flags flag(s)
  785. */
  786. public function setFlag($attrs, $flags)
  787. {
  788. $params = func_get_args();
  789. $this->_call("setFlags", $params);
  790. }
  791. /**
  792. * Set flag(s) for the given attribute or list of attributes.
  793. *
  794. * This method can also be called with multiple attribute string arguments
  795. * as long as the last argument contains the flag(s).
  796. *
  797. * NOTE: this method will overwrite all currently set flags, including
  798. * automatically detected flags!
  799. *
  800. * @param array|string $attrs list of attribute names or single attribute name
  801. * @param int $flags flag(s)
  802. */
  803. public function setFlags($attrs, $flags)
  804. {
  805. if (func_num_args() > 2)
  806. {
  807. $attrs = func_get_args();
  808. $flags = array_pop($attrs);
  809. }
  810. else if (!is_array($attrs))
  811. $attrs = array($attrs);
  812. foreach ($attrs as $attr)
  813. if (array_key_exists($attr, $this->m_attrs))
  814. $this->m_attrs[$attr]["flags"] = $flags;
  815. }
  816. /**
  817. * Add flag(s) for the given attribute or list of attributes.
  818. *
  819. * This method can also be called with multiple attribute string arguments
  820. * as long as the last argument contains the flag(s).
  821. *
  822. * @param array|string $attrs list of attribute names or single attribute name
  823. * @param int $flags flag(s)
  824. */
  825. public function addFlag($attrs, $flags)
  826. {
  827. $params = func_get_args();
  828. $this->_call("addFlags", $params);
  829. }
  830. /**
  831. * Add flag(s) for the given attribute or list of attributes.
  832. *
  833. * This method can also be called with multiple attribute string arguments
  834. * as long as the last argument contains the flag(s).
  835. *
  836. * @param array|string $attrs list of attribute names or single attribute name
  837. * @param int $flags flag(s)
  838. */
  839. public function addFlags($attrs, $flags)
  840. {
  841. if (func_num_args() > 2)
  842. {
  843. $attrs = func_get_args();
  844. $flags = array_pop($attrs);
  845. }
  846. else if (!is_array($attrs))
  847. $attrs = array($attrs);
  848. foreach ($attrs as $attr)
  849. if (array_key_exists($attr, $this->m_attrs))
  850. $this->m_attrs[$attr]["flags"] |= $flags;
  851. }
  852. /**
  853. * Add default flag(s) to all attributes, except the specifed attribute or list of attributes.
  854. *
  855. * This method can also be called with multiple attribute string arguments
  856. * as long as the last argument contains the flag(s).
  857. *
  858. * @param array|string $exclude_attrs list of attribute names or single attribute name to exclude
  859. * @param int $flags flag(s)
  860. */
  861. public function addDefaultFlags($exclude_attrs, $flags=0)
  862. {
  863. if ((func_num_args() == 1) || (func_num_args() > 2))
  864. {
  865. $exclude_attrs = func_get_args();
  866. $flags = array_pop($exclude_attrs);
  867. }
  868. else if (!is_array($exclude_attrs))
  869. $exclude_attrs = array($exclude_attrs);
  870. foreach (array_keys($this->m_attrs) as $key)
  871. {
  872. if (!in_array($key, $exclude_attrs))
  873. {
  874. $this->m_attrs[$key]["flags"] |= $flags;
  875. }
  876. }
  877. }
  878. /**
  879. * Remove flag(s) from the given attribute or list of attributes.
  880. *
  881. * This method can also be called with multiple attribute string arguments
  882. * as long as the last argument contains the flag(s).
  883. *
  884. * @param array|string $attrs list of attribute names or single attribute name
  885. * @param int $flags flag(s)
  886. */
  887. public function removeFlag($attrs, $flags)
  888. {
  889. $params = func_get_args();
  890. $this->_call("removeFlags", $params);
  891. }
  892. /**
  893. * Remove flag(s) from the given attribute or list of attributes.
  894. *
  895. * This method can also be called with multiple attribute string arguments
  896. * as long as the last argument contains the flag(s).
  897. *
  898. * @param array|string $attrs list of attribute names or single attribute name
  899. * @param int $flags flag(s)
  900. */
  901. public function removeFlags($attrs, $flags)
  902. {
  903. if (func_num_args() > 2)
  904. {
  905. $attrs = func_get_args();
  906. $flags = array_pop($attrs);
  907. }
  908. else if (!is_array($attrs))
  909. $attrs = array($attrs);
  910. foreach ($attrs as $attr)
  911. if (array_key_exists($attr, $this->m_attrs))
  912. $this->m_attrs[$attr]["flags"] = ($this->m_attrs[$attr]["flags"] | $flags) ^ $flags;
  913. }
  914. /**
  915. * Enable force insert for the given attribute or list of attributes.
  916. *
  917. * This method can also be called with multiple attribute string arguments.
  918. *
  919. * @param string|array $attrs attribute name(s)
  920. */
  921. public function addForceInsert($attrs)
  922. {
  923. if (!is_array($attrs))
  924. $attrs = func_get_args();
  925. foreach ($attrs as $attr)
  926. if (array_key_exists($attr, $this->m_attrs))
  927. $this->m_attrs[$attr]["forceInsert"] = true;
  928. }
  929. /**
  930. * Disable force insert for the given attribute or list of attributes.
  931. *
  932. * This method can also be called with multiple attribute string arguments.
  933. *
  934. * @param string|array $attrs attribute name(s)
  935. */
  936. public function removeForceInsert($attrs)
  937. {
  938. if (!is_array($attrs))
  939. $attrs = func_get_args();
  940. foreach ($attrs as $attr)
  941. if (array_key_exists($attr, $this->m_attrs))
  942. $this->m_attrs[$attr]["forceInsert"] = false;
  943. }
  944. /**
  945. * Enable force update for the given attribute or list of attributes.
  946. *
  947. * This method can also be called with multiple attribute string arguments.
  948. *
  949. * @param string|array $attrs attribute name(s)
  950. */
  951. public function addForceUpdate($attrs)
  952. {
  953. if (!is_array($attrs))
  954. $attrs = func_get_args();
  955. foreach ($attrs as $attr)
  956. if (array_key_exists($attr, $this->m_attrs))
  957. $this->m_attrs[$attr]["forceUpdate"] = true;
  958. }
  959. /**
  960. * Disable force update for the given attribute or list of attributes.
  961. *
  962. * This method can also be called with multiple attribute string arguments.
  963. *
  964. * @param string|array $attrs attribute name(s)
  965. */
  966. public function removeForceUpdate($attrs)
  967. {
  968. if (!is_array($attrs))
  969. $attrs = func_get_args();
  970. foreach ($attrs as $attr)
  971. if (array_key_exists($attr, $this->m_attrs))
  972. $this->m_attrs[$attr]["forceUpdate"] = false;
  973. }
  974. /**
  975. * Set the sections/tabs for the given attribute or list of attributes.
  976. *
  977. * This method can also be called with multiple attribute string arguments
  978. * as long as the last argument contains the section name(s).
  979. *
  980. * @param array|string $attrs list of attribute names or single attribute name
  981. * @param array|string $tabs tab name(s)
  982. */
  983. function setTab($attrs, $tabs)
  984. {
  985. $params = func_get_args();
  986. $this->_call("setTabs", $params);
  987. }
  988. /**
  989. * Set the sections/tabs for the given attribute or list of attributes.
  990. *
  991. * This method can also be called with multiple attribute string arguments
  992. * as long as the last argument contains the section name(s).
  993. *
  994. * @param array|string $attrs list of attribute names or single attribute name
  995. * @param array|string $tabs tab name(s)
  996. */
  997. public function setTabs($attrs, $tabs)
  998. {
  999. if (func_num_args() > 2)
  1000. {
  1001. $attrs = func_get_args();
  1002. $tabs = array_pop($attrs);
  1003. }
  1004. else if (!is_array($attrs))
  1005. $attrs = array($attrs);
  1006. foreach ($attrs as $attr)
  1007. if (array_key_exists($attr, $this->m_attrs))
  1008. $this->m_attrs[$attr]["tabs"] = $tabs;
  1009. }
  1010. /**
  1011. * Set the sections/tabs for the given attribute or list of attributes.
  1012. *
  1013. * This method can also be called with multiple attribute string arguments
  1014. * as long as the last argument contains the section name(s).
  1015. *
  1016. * @param array|string $attrs list of attribute names or single attribute name
  1017. * @param array|string $sections section name(s)
  1018. */
  1019. public function setSection($attrs, $sections)
  1020. {
  1021. $params = func_get_args();
  1022. $this->_call("setTabs", $params);
  1023. }
  1024. /**
  1025. * Set the sections/tabs for the given attribute or list of attributes.
  1026. *
  1027. * This method can also be called with multiple attribute string arguments
  1028. * as long as the last argument contains the section name(s).
  1029. *
  1030. * @param array|string $attrs list of attribute names or single attribute name
  1031. * @param array|string $sections section name(s)
  1032. */
  1033. public function setSections($attrs, $sections)
  1034. {
  1035. $params = func_get_args();
  1036. $this->_call("setTabs", $params);
  1037. }
  1038. /**
  1039. * Set the column for the given attribute or list of attributes.
  1040. *
  1041. * This method can also be called with multiple attribute string arguments
  1042. * as long as the last argument contains the section name(s).
  1043. *
  1044. * @param array|string $attrs list of attribute names or single attribute name
  1045. * @param array|string $column colum name
  1046. */
  1047. public function setColumn($attrs, $column)
  1048. {
  1049. if (func_num_args() > 2)
  1050. {
  1051. $attrs = func_get_args();
  1052. $column = array_pop($attrs);
  1053. }
  1054. else if (!is_array($attrs))
  1055. $attrs = array($attrs);
  1056. foreach ($attrs as $attr)
  1057. if (array_key_exists($attr, $this->m_attrs))
  1058. $this->m_attrs[$attr]["column"] = $column;
  1059. }
  1060. /**
  1061. * Sets the attribute type. All extra arguments after the two
  1062. * standard arguments will be threated as parameters for the
  1063. * attribute. If you need to pass arguments by reference you can
  1064. * better use the setTypeAndParams method.
  1065. *
  1066. * @param string|array $attr the attribute name or a list of attributes
  1067. * @param string $type full ATK attribute class (e.g. atk.attributes.atkboolattribute)
  1068. * @param mixed ... all other arguments will be threated as parameters
  1069. */
  1070. public function setType($attr, $type)
  1071. {
  1072. $params = func_get_args();
  1073. $params = array_slice($params, 2);
  1074. $this->setTypeAndParams($attr, $type, $params);
  1075. }
  1076. /**
  1077. * Sets the attribute type and parameters.
  1078. *
  1079. * @param string|array $attr the attribute name or a list of attributes
  1080. * @param string $type full ATK attribute class (e.g. atk.attributes.atkboolattribute)
  1081. * @param array $params parameters for the attribute (optional)
  1082. */
  1083. public function setTypeAndParams($attr, $type, $params=array())
  1084. {
  1085. $this->importAttribute($type);
  1086. $attrs = is_array($attr) ? $attr : array($attr);
  1087. foreach ($attrs as $attr)
  1088. {
  1089. $this->m_attrs[$attr]["type"] = $type;
  1090. $this->m_attrs[$attr]["params"] = $params;
  1091. }
  1092. }
  1093. /**
  1094. * Returns the current maximum order in the attribute list.
  1095. *
  1096. * @return int max order
  1097. */
  1098. protected function _getMaxOrder()
  1099. {
  1100. $max = 0;
  1101. foreach (array_keys($this->m_attrs) as $key)
  1102. {
  1103. if (isset($this->m_attrs[$key]["order"]) && $this->m_attrs[$key]["order"] > $max)
  1104. {
  1105. $max = $this->m_attrs[$key]["order"];
  1106. }
  1107. }
  1108. return $max;
  1109. }
  1110. /**
  1111. * Find destination entity for the given meta relation.
  1112. *
  1113. * @param string $accessor accessor name
  1114. * @param bool $toMany accessor name might be in plural form?
  1115. *
  1116. * @return string destination entity name for the given relation
  1117. */
  1118. protected function _findDestination($accessor, $toMany)
  1119. {
  1120. $module = getEntityModule($accessor);
  1121. if ($module == "")
  1122. $module = $this->m_entity->m_module;
  1123. $entity = getEntityType($accessor);
  1124. if ($module != "")
  1125. {
  1126. if (entityExists("$module.$entity"))
  1127. return "$module.$entity";
  1128. if ($toMany && entityExists("$module.".$this->getGrammar()->singularize($entity)))
  1129. return "$module.".$this->getGrammar()->singularize($entity);
  1130. if (!$toMany && entityExists("$module.".$this->getGrammar()->pluralize($entity)))
  1131. return "$module.".$this->getGrammar()->pluralize($entity);
  1132. if (entityExists("{$module}.{$module}_{$entity}"))
  1133. return "{$module}.{$module}_{$entity}";
  1134. if ($toMany && entityExists("{$module}.{$module}_".$this->getGrammar()->singularize($entity)))
  1135. return "{$module}.{$module}_".$this->getGrammar()->singularize($entity);
  1136. if (!$toMany && entityExists("{$module}.{$module}_".$this->getGrammar()->pluralize($entity)))
  1137. return "{$module}.{$module}_".$this->getGrammar()->pluralize($entity);
  1138. }
  1139. if (entityExists($entity))
  1140. return $entity;
  1141. if ($toMany && entityExists($this->getGrammar()->singularize($entity)))
  1142. return $this->getGrammar()->singularize($entity);
  1143. if (!$toMany && entityExists($this->getGrammar()->pluralize($entity)))
  1144. return $this->getGrammar()->pluralize($entity);
  1145. return NULL;
  1146. }
  1147. /**
  1148. * Returns a list of possible attribute name variants for relations
  1149. * which reference this entity or the given destination entity.
  1150. *
  1151. * @param string $destination destination entity
  1152. *
  1153. * @return array list of attribute variants
  1154. */
  1155. protected function _getDestinationAttributeVariants($destination=null)
  1156. {
  1157. $base = array();
  1158. // no destination given, self is assumed, we also add the table name
  1159. // and parent classes as base for the different variants
  1160. if ($destination == null)
  1161. {
  1162. $module = getEntityModule($this->getEntity()->atkEntityType());
  1163. $base[] = $this->getEntityTable();
  1164. $base[] = getEntityType($this->getEntity()->atkEntityType());
  1165. for ($class = get_class($this->getEntity()); stripos($class, 'metaentity') === false; $class = get_parent_class($class))
  1166. {
  1167. $base[] = strtolower($class);
  1168. }
  1169. $base = array_unique($base);
  1170. }
  1171. else
  1172. {
  1173. $module = getEntityModule($destination);
  1174. $base[] = getEntityType($destination);
  1175. }
  1176. if ($module != null)
  1177. {
  1178. // add variants for each base with the module as prefix or with the module
  1179. // prefix stripped out (if it was already part of base), we explicitly
  1180. // make a copy of base so that new entries don't mess up the loop
  1181. foreach (array_values($base) as $entry)
  1182. {
  1183. // entry already contains module prefix, strip it
  1184. if (substr($entry, 0, strlen($module) + 1) == $module.'_')
  1185. {
  1186. $base[] = substr($entry, strlen($module) + 1);
  1187. }
  1188. // entry doesn't contain prefix yet, add it
  1189. else
  1190. {
  1191. $base[] = $module."_".$entry;
  1192. }
  1193. }
  1194. }
  1195. $variants = array();
  1196. foreach ($base as $entry)
  1197. {
  1198. $variants[] = "{$entry}_id";
  1199. $variants[] = $this->getGrammar()->singularize($entry)."_id";
  1200. $variants[] = "{$entry}id";
  1201. $variants[] = $this->getGrammar()->singularize($entry)."id";
  1202. $variants[] = $entry;
  1203. $variants[] = $this->getGrammar()->singularize($entry);
  1204. }
  1205. $variants = array_values(array_unique($variants));
  1206. return $variants;
  1207. }
  1208. /**
  1209. * Find source attribute for a many-to-one relation that point to the
  1210. * given destination entity.
  1211. *
  1212. * @param string $destination destination entity type
  1213. *
  1214. * @return string source attribute name
  1215. */
  1216. protected function _findSourceAttribute($destination)
  1217. {
  1218. $module = getEntityModule($destination);
  1219. $type = getEntityType($destination);
  1220. $prefixes = $module == null ? array('') : array('', "{$module}_");
  1221. foreach ($prefixes as $leftPrefix)
  1222. {
  1223. foreach ($prefixes as $rightPrefix)
  1224. {
  1225. foreach (array_keys($this->m_attrs) as $name)
  1226. {
  1227. switch ($leftPrefix.$name)
  1228. {
  1229. case "{$rightPrefix}{$type}_id":
  1230. case "{$rightPrefix}{$type}id":
  1231. case $rightPrefix.$this->getGrammar()->singularize($type)."_id":
  1232. case $rightPrefix.$this->getGrammar()->singularize($type)."id":
  1233. case $rightPrefix.$type:
  1234. case $rightPrefix.$this->getGrammar()->singularize($type):
  1235. return $name;
  1236. }
  1237. }
  1238. }
  1239. }
  1240. return null;
  1241. }
  1242. /**
  1243. * One-to-many / many-to-many relation support. You can call the hasMany
  1244. * method to indicate that this entity has a one-to-many or a many-to-many
  1245. * relationship with another entity. The meta policy will then try to guess,
  1246. * amongst other things, which fields should be used for this relation.
  1247. *
  1248. * This method uses a smart name guessing scheme for the (optional
  1249. * intermediate) and destination entity. If you enter the plural form of
  1250. * the (singular) entity name it will still be able to find the entity.
  1251. * You can ommit the module name prefix if the destination entity resides
  1252. * in the same module as the source entity. Ofcourse you can also just use
  1253. * the real module/entity name combination.
  1254. *
  1255. * The options list may contain several parameters to make more complex
  1256. * relations work. The supported parameters are as follows:
  1257. *
  1258. * - dest(-ination) destination attribute name
  1259. * - filter destination filter
  1260. * - through intermediary entity name (for many-to-many relations)
  1261. * - local if ATK can't determine the key in the intermediary entity
  1262. * automatically, use local to tell it which key points to
  1263. * the source entity.
  1264. * - remote if ATK can't determine the key in the intermediary entity
  1265. * use remote to tell it which key points to the
  1266. * destination entity.
  1267. * - type type of many-to-many relation (shuttle, select,
  1268. * eshuttle, bool(ean) or list, defaults to shuttle)
  1269. * - cols/columns number of columns (many-to-many bool relations only)
  1270. * - rows number of rows (many-to-many list relations only)
  1271. * - name name for this relation (by default getEntityType($accessor))
  1272. *
  1273. * @param string $accessor accessor name (complete description is given above)
  1274. * @param string|array $templateOrOptions template or list of options (complete description is given above)
  1275. * @param array $options list op options (complete description is given above)
  1276. * @param int $flags the flags for the relation
  1277. *
  1278. * @return atkMetaAttributeModifier
  1279. */
  1280. public function hasMany($accessor, $templateOrOptions=array(), $options=array(), $flags=0)
  1281. {
  1282. $template = NULL;
  1283. if (is_array($templateOrOptions))
  1284. $options = $templateOrOptions;
  1285. else $template = $templateOrOptions;
  1286. if (isset($options['name']))
  1287. {
  1288. $name = $options['name'];
  1289. }
  1290. else
  1291. {
  1292. $name = getEntityType($accessor);
  1293. }
  1294. if (isset($options['source']))
  1295. {
  1296. $options['local'] = $options['source'];
  1297. }
  1298. if (isset($options['class']))
  1299. {
  1300. $type = $options['class'];
  1301. }
  1302. $destination = $this->_findDestination($accessor, true);
  1303. if (empty($destination))
  1304. {
  1305. throw new Exception("Cannot find destination for ".$this->getEntity()->atkEntityType()."::hasMany({$accessor}, ...)");
  1306. }
  1307. if (isset($options['through']))
  1308. {
  1309. if (!isset($type))
  1310. {
  1311. switch (@$options['type'])
  1312. {
  1313. case 'bool':
  1314. case 'boolean':
  1315. $type = "atk.meta.relations.atkmetamanyboolrelation";
  1316. break;
  1317. case 'list':
  1318. $type = "atk.meta.relations.atkmetamanytomanylistrelation";
  1319. break;
  1320. case 'select':
  1321. $type = "atk.meta.relations.atkmetamanytomanyselectrelation";
  1322. break;
  1323. case 'eshuttle':
  1324. case 'extendableshuttle':
  1325. $type = "atk.meta.relations.atkmetaextendableshuttlerelation";
  1326. break;
  1327. case 'shuttle':
  1328. default:
  1329. $type = "atk.meta.relations.atkmetashuttlerelation";
  1330. }
  1331. }
  1332. $through = $this->_findDestination($options['through'], true);
  1333. if (empty($through))
  1334. {
  1335. throw new Exception("Cannot find intermediate entity for ".$this->getEntity()->atkEntityType()."::hasMany({$accessor}, array(through => {$options['through']}, ...))");
  1336. }
  1337. if (!isset($options['local']))
  1338. {
  1339. $options['localVariants'] = $this->_getDestinationAttributeVariants();
  1340. }
  1341. if (!isset($options['remote']))
  1342. {
  1343. $remoteVariants = $this->_getDestinationAttributeVariants($destination);
  1344. if (isset($options['name']))
  1345. $remoteVariants = array_merge($remoteVariants, $this->_getDestinationAttributeVariants($options['name']));
  1346. $options['remoteVariants'] = $remoteVariants;
  1347. }
  1348. $params = array($destination, $through, $template, $options);
  1349. }
  1350. else
  1351. {
  1352. if (!isset($type))
  1353. {
  1354. $type = "atk.meta.relations.atkmetaonetomanyrelation";
  1355. }
  1356. $variants = $this->_getDestinationAttributeVariants();
  1357. $options['variants'] = $variants;
  1358. $params = array($destination, $template, $options);
  1359. }
  1360. $flags = AF_HIDE_LIST|AF_HIDE_ADD|$flags;
  1361. $tabs = NULL;
  1362. $order = $this->_getMaxOrder() + 100 ;
  1363. return $this->add($name, $type, $params, $flags, $tabs, $order);
  1364. }
  1365. /**
  1366. * Many-to-one / one-to-one relation support. You can call the hasOne method
  1367. * to indicate that this entity has a many-to-one or a one-to-one relation with
  1368. * another entity. The meta policy will then try to guess, amongst other
  1369. * things, which fields should be used for this relation.
  1370. *
  1371. * To determine if a many-to-one or a one-to-one relation should be used
  1372. * the system will check if the source entity contains an attribute for
  1373. * storing the relation. If so the system will use a many-to-one relation,
  1374. * else a one-to-one relation will be used.
  1375. *
  1376. * This method uses a smart name guessing scheme for the destination entity.
  1377. * If you enter the singular form of the (plural) entity name it will still
  1378. * be able to find the entity. You can ommit the module name prefix if the
  1379. * destination entity resides in the same module as the source entity. Ofcourse
  1380. * you can also just use the real module/entity name combination.
  1381. *
  1382. * The options list may contain several parameters to make more complex
  1383. * relations work. The supported parameters are as follows:
  1384. *
  1385. * - source source attribute name (should only be used for
  1386. * many-to-one relations and will act as an indicator
  1387. * for whatever this is a many-to-one relation or not)
  1388. * - dest(-ination) destination attribute name (should only be used for
  1389. * one-to-one relations and will act as an indicator
  1390. * for whatever this is a one-to-one relation or not)
  1391. * - filter destination filter
  1392. * - large boolean indicating if there will be lots and lots of
  1393. * records in case of a many-to-one relation, same as
  1394. * the AF_LARGE flag (defaults to false)
  1395. *
  1396. * @param string $accessor accessor name (complete description is given above)
  1397. * @param string|array $templateOrOptions template or list of options (complete description is given above)
  1398. * @param array $options list op options (complete description is given above)
  1399. * @param int $flags the flags for the relation
  1400. *
  1401. * @return atkMetaAttributeModifier
  1402. */
  1403. public function hasOne($accessor, $templateOrOptions=array(), $options=array(), $flags=0)
  1404. {
  1405. $template = NULL;
  1406. if (is_array($templateOrOptions))
  1407. $options = $templateOrOptions;
  1408. else $template = $templateOrOptions;
  1409. // look-up destination entity
  1410. $destination = $this->_findDestination($accessor, false);
  1411. if (empty($destination))
  1412. {
  1413. throw new Exception("Cannot find destination for ".$this->getEntity()->atkEntityType()."::hasOne($accessor, ...)");
  1414. }
  1415. // explicit source given
  1416. if (array_key_exists("source", $options))
  1417. {
  1418. // in case of multi referential key "source" is array
  1419. if (is_array($options["source"]))
  1420. {
  1421. $attr = $options["source"][0]; // we use the first key as name of attribute
  1422. }
  1423. else
  1424. {
  1425. $attr = $options["source"];
  1426. }
  1427. }
  1428. // no source and no destination given, still try to find a source attribute just to be sure
  1429. // note that findSourceAttribute probably returns null for one-to-one relations
  1430. else if (!array_key_exists("dest", $options) && !array_key_exists("destination", $options))
  1431. {
  1432. $attr = $this->_findSourceAttribute($destination);
  1433. }
  1434. // one-to-one relation, lookup possible destination attribute variants
  1435. if ($attr == null && !array_key_exists("dest", $options) && !array_key_exists("destination", $options))
  1436. {
  1437. $options['variants'] = $this->_getDestinationAttributeVariants();
  1438. }
  1439. $name = $attr != NULL ? $attr : getEntityType($accessor);
  1440. $type = "atk.meta.relations.atkmeta".($attr != NULL ? 'many' : 'one')."toonerelation";
  1441. $params = array($destination, $template, $options);
  1442. $flags = ($attr != NULL ? $this->m_attrs[$attr]["flags"] : 0) | (array_key_exists("large", $options) && $options["large"] ? AF_LARGE : 0) | $flags;
  1443. $tabs = $attr != NULL ? $this->m_attrs[$attr]["tabs"] : NULL;
  1444. $order = $attr != NULL ? $this->m_attrs[$attr]["order"] : $this->_getMaxOrder() + 100;
  1445. return $this->add($name, $type, $params, $flags, $tabs, $order);
  1446. }
  1447. /**
  1448. * Add / replace (custom) attribute.
  1449. *
  1450. * @param string|array $name attribute name or list of attributes
  1451. * @param string $type attribute type
  1452. * @param array $params attribute parameters, excluding flags (optional)
  1453. * @param int $flags attribute flags (optional)
  1454. * @param string|array $sections sections/tabs to display the attribute on
  1455. * @param int $order order of the attribute
  1456. * @param mixed $default default value
  1457. *
  1458. * @return atkMetaAttributeModifier
  1459. */
  1460. public function add($name, $type='atkattribute', $params=array(), $flags=0, $sections=NULL, $order=NULL, $default=self::NO_DEFAULT_VALUE)
  1461. {
  1462. $this->importAttribute($type);
  1463. $names = is_array($name) ? $name : array($name);
  1464. foreach ($names as $name)
  1465. {
  1466. if ($order === NULL && isset($this->m_attrs[$name]))
  1467. {
  1468. $order = $this->m_attrs[$name]['order'];
  1469. }
  1470. else if ($order === NULL)
  1471. {
  1472. $order = $this->_getMaxOrder() + 100;
  1473. }
  1474. $this->m_attrs[$name] =
  1475. array(
  1476. "type" => $type,
  1477. "params" => $params,
  1478. "flags" => $flags,
  1479. "tabs" => $sections,
  1480. "column" => null,
  1481. "order" => $order
  1482. );
  1483. if ($default != self::NO_DEFAULT_VALUE)
  1484. {
  1485. $this->m_attrs[$name]['default'] = $default;
  1486. }
  1487. }
  1488. $this->sortAttributes();
  1489. return Adapto_ClassLoader::create('atk.meta.atkmetaattributemodifier', $this, $names);
  1490. }
  1491. /**
  1492. * Add fieldset.
  1493. *
  1494. * To include an attribute label use [attribute.label] inside your
  1495. * template. To include an attribute edit/display field use
  1496. * [attribute.field] inside your template.
  1497. *
  1498. * @param string $name name
  1499. * @param string $template template string
  1500. * @param int $flags attribute flags
  1501. * @param string|array $sections sections/tabs to display the attribute on
  1502. * @param int $order order of the attribute
  1503. *
  1504. * @return atkMetaAttributeModifier
  1505. */
  1506. public function addFieldSet($name, $template, $flags=0, $sections=NULL, $order=NULL)
  1507. {
  1508. return $this->add($name, 'atk.attributes.atkfieldset', array($template), $flags, $sections, $order);
  1509. }
  1510. /**
  1511. * Remove attribute.
  1512. *
  1513. * @param string|array $name attribute name
  1514. */
  1515. public function remove($name)
  1516. {
  1517. $names = is_array($name) ? $name : func_get_args();
  1518. foreach ($names as $name)
  1519. {
  1520. unset($this->m_attrs[$name]);
  1521. }
  1522. }
  1523. /**
  1524. * Does the given attribute exist?
  1525. *
  1526. * @param string $name attribute name
  1527. */
  1528. public function exists($name)
  1529. {
  1530. return isset($this->m_attrs[$name]);
  1531. }
  1532. /**
  1533. * Returns a reference to the attributes array.
  1534. *
  1535. * Be very careful when using this array, modifying it might void your warranty!
  1536. *
  1537. * @return array reference to the attributes array
  1538. */
  1539. public function &getAttributes()
  1540. {
  1541. return $this->m_attrs;
  1542. }
  1543. /**
  1544. * Returns the attribute names.
  1545. *
  1546. * @return array string attribute names
  1547. */
  1548. public function getAttributeNames()
  1549. {
  1550. return array_keys($this->m_attrs);
  1551. }
  1552. /**
  1553. * Translate using the entity's module and type.
  1554. *
  1555. * @param mixed $string string or array of strings containing the name(s) of the string to return
  1556. * when an array of strings is passed, the second will be the fallback if
  1557. * the first one isn't found, and so forth
  1558. * @param String $module module in which the language file should be looked for,
  1559. * defaults to core module with fallback to ATK
  1560. * @param String $language ISO 639-1 language code, defaults to config variable
  1561. * @param String $firstFallback the first module to check as part of the fallback
  1562. * @param boolean $entityDefaultText if true, then it doesn't return a default text
  1563. * when it can't find a translation
  1564. * @return String the string from the languagefile
  1565. */
  1566. public function text($string, $module=NULL, $language='', $firstFallback="", $entityDefaultText=false)
  1567. {
  1568. return $this->getEntity()->text($string, $module, $language, $firstFallback, $entityDefaultText);
  1569. }
  1570. /**
  1571. * Utility method to bit-or two integers.
  1572. *
  1573. * @param int $a integer a
  1574. * @param int $b integer b
  1575. *
  1576. * @return int result of bit-or
  1577. */
  1578. public static function bitOr($a, $b)
  1579. {
  1580. return $a|$b;
  1581. }
  1582. /**
  1583. * Detect entity table name.
  1584. *
  1585. * @return string table name
  1586. */
  1587. protected function _detectEntityTable()
  1588. {
  1589. $module = $this->getEntity()->getModule();
  1590. $base = array();
  1591. $base[] = $this->getEntity()->getType();
  1592. $base[] = $module."_".$this->getEntity()->getType();
  1593. for ($class = get_class($this->getEntity()); stripos($class, 'metaentity') === false; $class = get_parent_class($class))
  1594. {
  1595. $base[] = strtolower($class);
  1596. $base[] = $module."_".strtolower($class);
  1597. }
  1598. $db = atkGetDb($this->getEntityDatabase());
  1599. foreach ($base as $entry)
  1600. {
  1601. if ($db->tableExists($entry))
  1602. {
  1603. return $entry;
  1604. }
  1605. else if ($db->tableExists($this->getGrammar()->singularize($entry)))
  1606. {
  1607. return $this->getGrammar()->singularize($entry);
  1608. }
  1609. else if ($db->tableExists($this->getGrammar()->pluralize($entry)))
  1610. {
  1611. return $this->getGrammar()->pluralize($entry);
  1612. }
  1613. }
  1614. return null;
  1615. }
  1616. /**
  1617. * Detect entity sequence name.
  1618. *
  1619. * @return string sequence name
  1620. */
  1621. protected function _detectEnt

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