PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/relations/class.atkrelation.inc

https://github.com/ibuildingsnl/ATK
PHP | 393 lines | 275 code | 17 blank | 101 comment | 5 complexity | 859d5a80d8b2716426e7fa572d61b242 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, LGPL-3.0
  1. <?php
  2. /**
  3. * This file is part of the Achievo ATK distribution.
  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 atk
  9. * @subpackage relations
  10. *
  11. * @copyright (c)2000-2004 Ivo Jansch
  12. * @license http://www.achievo.org/atk/licensing ATK Open Source License
  13. *
  14. * @version $Revision: 6320 $
  15. * $Id$
  16. */
  17. /**
  18. * The atkRelation class defines a relation to another node.
  19. *
  20. * @author Ivo Jansch <ivo@achievo.org>
  21. * @package atk
  22. * @subpackage relations
  23. * @abstract
  24. *
  25. */
  26. class atkRelation extends atkAttribute
  27. {
  28. /**
  29. * @var String Destination node.
  30. */
  31. var $m_destination;
  32. /**
  33. * @var atkNode Destination instance.
  34. */
  35. var $m_destInstance="";
  36. /**
  37. * @var String Filter for destination records.
  38. */
  39. var $m_destinationFilter="";
  40. /**
  41. * Descriptor template for destination node.
  42. * @var String
  43. */
  44. var $m_descTemplate = NULL;
  45. /**
  46. * Descriptor handler.
  47. * @var Object
  48. */
  49. var $m_descHandler = NULL;
  50. /**
  51. * Constructor
  52. * @param String $name The name of the relation.
  53. * @param String $destination The destination node (in module.name notation)
  54. * @param int $flags Flags for the relation
  55. */
  56. function atkRelation($name, $destination, $flags=0)
  57. {
  58. $this->atkAttribute($name, $flags);
  59. $this->m_destination = $destination;
  60. }
  61. /**
  62. * Returns the destination filter.
  63. * @return String The destination filter.
  64. */
  65. function getDestinationFilter()
  66. {
  67. return $this->m_destinationFilter;
  68. }
  69. /**
  70. * Sets the destination filter.
  71. * @param String $filter The destination filter.
  72. */
  73. function setDestinationFilter($filter)
  74. {
  75. $this->m_destinationFilter = $this->_cleanupDestinationFilter($filter);
  76. }
  77. /**
  78. * Remove redundant (more than 1 subsequently) spaces from the filter string.
  79. *
  80. * This prevents the filter from rapidly becoming too long to be passed in the URL if
  81. * enters are used in code to make the filter readable.
  82. *
  83. * @param string $filter
  84. * @return string
  85. */
  86. function _cleanupDestinationFilter($filter)
  87. {
  88. $result = '';
  89. $filter_length = strlen($filter);
  90. $quotes = array("'",'"','`');
  91. $quoteStack = array();
  92. $lastChar = '';
  93. for ($i = 0; $i < $filter_length; $i++)
  94. {
  95. $currentChar = $filter[$i];
  96. if(in_array($currentChar,$quotes))
  97. {
  98. if(sizeof($quoteStack) > 0 && $currentChar == $quoteStack[sizeof($quoteStack) - 1])
  99. {
  100. array_pop($quoteStack);
  101. }
  102. else
  103. {
  104. array_push($quoteStack,$currentChar);
  105. }
  106. }
  107. // not between quotes
  108. if(!($currentChar === ' ' && $lastChar === ' ' && sizeof($quoteStack) == 0))
  109. {
  110. if($currentChar != "\n") $result .= $currentChar;
  111. }
  112. $lastChar = $currentChar;
  113. }
  114. return $result;
  115. }
  116. /**
  117. * Adds a filter value to the destination filter.
  118. * @param String $filter Filter to be added to the destination filter.
  119. */
  120. function addDestinationFilter($filter)
  121. {
  122. $filter = $this->_cleanupDestinationFilter($filter);
  123. if($this->m_destinationFilter != "")
  124. $this->m_destinationFilter = "({$this->m_destinationFilter}) AND ({$filter})";
  125. else
  126. $this->m_destinationFilter = $filter;
  127. return $this;
  128. }
  129. /**
  130. * Get descriptor handler.
  131. * @return Object descriptor handler
  132. */
  133. function &getDescriptorHandler()
  134. {
  135. return $this->m_descHandler;
  136. }
  137. /**
  138. * Set descriptor handler.
  139. * @param Object $handler The descriptor handler.
  140. */
  141. function setDescriptorHandler(&$handler)
  142. {
  143. $this->m_descHandler = &$handler;
  144. }
  145. /**
  146. * Returns the descriptor template for the destination node.
  147. * @return String The descriptor Template
  148. */
  149. function getDescriptorTemplate()
  150. {
  151. return $this->m_descTemplate;
  152. }
  153. /**
  154. * Sets the descriptor template for the destination node.
  155. * @param String $template The descriptor template.
  156. */
  157. function setDescriptorTemplate($template)
  158. {
  159. $this->m_descTemplate = $template;
  160. }
  161. /**
  162. * Descriptor handler. Forwards description handler calls
  163. * to the real description handler.
  164. *
  165. * @param array $record The record
  166. * @param atkNode $node The atknode object
  167. * @return String with the descriptor
  168. */
  169. function descriptor($record, &$node)
  170. {
  171. $method = $this->m_name."_descriptor";
  172. if (method_exists($this->m_descHandler, $method))
  173. return $this->m_descHandler->$method($record, $node);
  174. else return $this->m_descHandler->descriptor($record, $node);
  175. }
  176. /**
  177. * Create the instance of the destination.
  178. *
  179. * If succesful, the instance is stored in the m_destInstance member variable.
  180. *
  181. * @return boolean true if succesful, false if something went wrong.
  182. */
  183. function createDestination()
  184. {
  185. if (!is_object($this->m_destInstance))
  186. {
  187. $cache_id = $this->m_owner.".".$this->m_name;
  188. $this->m_destInstance = &getNode($this->m_destination, true, $cache_id);
  189. // Validate if destination was created succesfully
  190. if (!is_object($this->m_destInstance))
  191. {
  192. atkerror("Relation with unknown nodetype '".$this->m_destination."' (in node '".$this->m_owner."')");
  193. $this->m_destInstance = NULL;
  194. return false;
  195. }
  196. if ($this->hasFlag(AF_NO_FILTER))
  197. $this->m_destInstance->m_flags |= NF_NO_FILTER;
  198. foreach (array_keys($this->m_destInstance->m_attribList) as $key)
  199. {
  200. $attribute = &$this->m_destInstance->m_attribList[$key];
  201. if (is_subclass_of($attribute, "atkrelation") && is_object($this->m_ownerInstance) && $attribute->m_destination == $this->m_ownerInstance->atkNodeType())
  202. {
  203. $attribute->m_destInstance = &$this->m_ownerInstance;
  204. if (count($attribute->m_tabs) == 1 && $attribute->m_tabs[0] == "default")
  205. {
  206. $attribute->setTabs($this->m_tabs);
  207. }
  208. }
  209. }
  210. if (!empty($this->m_descHandler))
  211. $this->m_destInstance->setDescriptorHandler($this);
  212. if (!empty($this->m_descTemplate))
  213. $this->m_destInstance->setDescriptorTemplate($this->m_descTemplate);
  214. }
  215. return true;
  216. }
  217. /**
  218. * Return a displayable string for a record.
  219. * @param array $record The record that contains the information to display.
  220. * @return String a displayable string for this value.
  221. */
  222. function display($record)
  223. {
  224. return $record[$this->fieldName()];
  225. }
  226. /**
  227. * Validation method. Empty implementation. Derived classes may override
  228. * this function.
  229. * @abstract
  230. *
  231. * @param array $record The record that holds the value for this
  232. * attribute. If an error occurs, the error will
  233. * be stored in the 'atkerror' field of the record.
  234. * @param String $mode The mode for which should be validated ("add" or
  235. * "update")
  236. */
  237. function validate(&$record, $mode)
  238. {
  239. }
  240. /**
  241. * Check if the relation is empty
  242. * @param array $record The record to check
  243. * @return boolean true if a destination record is present. False if not.
  244. */
  245. function isEmpty($record)
  246. {
  247. if ($this->createDestination() && isset($record[$this->fieldName()][$this->m_destInstance->primaryKeyField()]))
  248. {
  249. return empty($record[$this->fieldName()][$this->m_destInstance->primaryKeyField()]);
  250. }
  251. else if ($this->createDestination() && isset($record[$this->fieldName()]))
  252. {
  253. return empty($record[$this->fieldName()]);
  254. }
  255. return true; // always empty if error.
  256. }
  257. /**
  258. * Retrieve the searchmodes supported by the relation.
  259. * @return array A list of supported searchmodes.
  260. */
  261. function getSearchModes()
  262. {
  263. // exact match and substring search should be supported by any database.
  264. // (the LIKE function is ANSI standard SQL, and both substring and wildcard
  265. // searches can be implemented using LIKE)
  266. // Possible values
  267. //"regexp","exact","substring", "wildcard","greaterthan","greaterthanequal","lessthan","lessthanequal"
  268. return array("exact");
  269. }
  270. /**
  271. * Get the searchmode for nested/child attributes.
  272. *
  273. * @param string|array $searchmode searchmode
  274. * @param string $childname the child attribute's name
  275. * @return string|array the child searchmode
  276. */
  277. protected function getChildSearchMode($searchmode, $childname)
  278. {
  279. if (is_array($searchmode) && isset($searchmode[$childname]))
  280. return $searchmode[$childname];
  281. return $searchmode;
  282. }
  283. /**
  284. * Since most relations do not store anything in a field, the default
  285. * fieldtype for relations is "". Exceptions (like the many2oone relation,
  286. * which stores a foreign key) can implement their own dbFieldType().
  287. * @abstract
  288. * @return String
  289. */
  290. function dbFieldType()
  291. {
  292. return "";
  293. }
  294. /**
  295. * Returns the condition (SQL) that should be used when we want to join a relation's
  296. * owner node with the parent node.
  297. *
  298. * @param atkQuery $query The query object
  299. * @param string $tablename The tablename
  300. * @param string $fieldalias
  301. * @return String SQL string for joining the owner with the destination.
  302. * Defaults to false.
  303. */
  304. function getJoinCondition(&$query, $tablename="",$fieldalias="")
  305. {
  306. return false;
  307. }
  308. /**
  309. * Returns an instance of the node that the relation points to.
  310. * @return atkNode The node that this relation points to, or
  311. * NULL if the destination is not valid.
  312. */
  313. function &getDestination()
  314. {
  315. if ($this->createDestination())
  316. {
  317. return $this->m_destInstance;
  318. }
  319. return NULL;
  320. }
  321. /**
  322. * Attempts to get a translated label which can be used when composing an "add" link
  323. *
  324. * @return String Localised "add" label
  325. */
  326. function getAddLabel()
  327. {
  328. // Try to get a translation for link_fieldname_add (or if not found, a translation for link_destination_add)
  329. $keys = array("link_" . $this->fieldName() . "_add", "link_" . getNodeType($this->m_destination) . "_add");
  330. $label = atktext($keys, getNodeModule($this->m_destination), "", "", "", true);
  331. // If translation not found, then use a concatenation of translations of the destination and the word "add" as default
  332. if ($label=="")
  333. $label = atktext(getNodeType($this->m_destination), getNodeModule($this->m_destination)) . " " . strtolower(atktext("add", "atk"));
  334. // Return the translation
  335. return $label;
  336. }
  337. /**
  338. * Parses the destination filter
  339. *
  340. * @param string $destFilter filter to parse
  341. * @param array $record the current record
  342. * @return $filter string filter.
  343. */
  344. function parseFilter($destFilter,$record)
  345. {
  346. if($destFilter!="")
  347. {
  348. atkimport("atk.utils.atkstringparser");
  349. $parser = new atkStringParser($destFilter);
  350. return $parser->parse($record);
  351. }
  352. return "";
  353. }
  354. }
  355. ?>