PageRenderTime 60ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/source/core/thirdparty/autoCrud/relationship.inc.php

https://bitbucket.org/detroitpro/taphp
PHP | 433 lines | 210 code | 77 blank | 146 comment | 29 complexity | 551ef40be88ef026adddfa283955bd83 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, GPL-3.0
  1. <?php
  2. /**
  3. * AutoCRUD_Relationship Class File
  4. *
  5. * This file holds the AutoCRUD_Relationship class, used for joins
  6. *
  7. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  8. * @package autocrud
  9. */
  10. /**
  11. * AutoCRUD_Relationship Class
  12. *
  13. * This class is used to handle the joins and relationships between tables
  14. *
  15. * @package autocrud
  16. */
  17. Class AutoCRUD_Relationship {
  18. // Private vars:
  19. /**#@+
  20. * @access private
  21. */
  22. var $_owner_obj;
  23. var $_other_obj;
  24. var $_owner_field;
  25. var $_other_field;
  26. var $_type;
  27. var $_reverse_type;
  28. /**#@-*/
  29. /**
  30. * Used to pass in the owner CRUD object and the CRUD object of the other table
  31. *
  32. * @access public
  33. * @param AutoCRUD_CRUD $owner the owner CRUD object
  34. * @param AutoCRUD_CRUD $other the CRUD object of the other table
  35. */
  36. function AutoCRUD_Relationship(&$owner, &$other) {
  37. if (strtolower(get_class($owner)) != 'autocrud_crud') {
  38. return false;
  39. }
  40. if (strtolower(get_class($other)) != 'autocrud_crud') {
  41. return $this->halt ('invalid-object', 'Invalid object passed to relationship');
  42. }
  43. $this->_owner_obj =& $owner;
  44. $this->_other_obj =& $other;
  45. return true;
  46. }
  47. /**
  48. * Used to get related records of a result set
  49. *
  50. * @access public
  51. * @param array $results the result set (an array of records)
  52. * @return array the result set with related records
  53. */
  54. function doJoin($results) {
  55. if ($this->_type == 'one-to-one') {
  56. $results = $this->_joinOne2One($results);
  57. } elseif ($this->_type == 'child-parent') {
  58. $results = $this->_joinChildParent($results);
  59. } else {
  60. $results = $this->_joinOne2Many($results);
  61. }
  62. return $results;
  63. }
  64. /**
  65. * Used to get related records of a result set in a Many-to-Many relationship
  66. *
  67. * @access public
  68. * @param array $results the result set (an array of records)
  69. * @param string $table the name of the other table
  70. * @return array the result set with related records
  71. */
  72. function joinMany2Many($results, $table) {
  73. // Get relationship
  74. $other_rel = $this->_other_obj->getRelationship($table);
  75. if (autocrud_is_error($other_rel)) { return $this->halt('no-relationship'); }
  76. // Get other object and other fields
  77. $other_obj =& $other_rel->getOther();
  78. $owner_field = $other_rel->getOwnerField();
  79. $other_field = $other_rel->getOtherField();
  80. $ids_list = array();
  81. $newresults = array();
  82. $keys = array();
  83. // Get ID's from results
  84. foreach ($results as $key => $row) {
  85. // Get ID
  86. $id = $row[$this->_owner_field];
  87. $ids_list[] = $id;
  88. // Copy to a new array, and add it under its own ID
  89. $newresults[$id] = $row;
  90. // Save key (in case a specific key was being used)
  91. $keys[] = $key;
  92. }
  93. $results = $newresults;
  94. $ids_list = array_unique($ids_list);
  95. $ids_list = implode("', '", $ids_list);
  96. // Get records from in between table
  97. $this->_other_obj->where = "`" . $this->_other_field . "` IN ('" . $ids_list . "')";
  98. $between = $this->_other_obj->select();
  99. // Collect ID's from in between table
  100. $ids_list = array();
  101. foreach ($between as $row) {
  102. // Get ID
  103. $id = $row[$table];
  104. $ids_list[] = $id;
  105. }
  106. $ids_list = array_unique($ids_list);
  107. $ids_list = implode("', '", $ids_list);
  108. // Get records from other table
  109. $crud =& $this->_other_obj->getParent();
  110. $other_obj->where = "`" . $other_field . "` IN ('" . $ids_list . "')";
  111. $other = $other_obj->select($other_field);
  112. // Match up results with other records
  113. $name = $other_obj->getName();
  114. foreach ($between as $row) {
  115. $id_owner = $row[$this->_other_field];
  116. $id_other = $row[$owner_field];
  117. // Owner exists?
  118. if (!isset($results[$id_owner])) { continue; }
  119. // Other exists?
  120. if (!isset($other[$id_other])) { continue; }
  121. $owner_row =& $results[$id_owner];
  122. $other_row =& $other[$id_other];
  123. // Make sure owner table array property exists
  124. if (!isset($owner_row[$name])) { $owner_row[$name] = array(); }
  125. // Add other row to owner
  126. $owner_row[$name][] = $other_row;
  127. }
  128. // Return keys
  129. $newresults = array();
  130. $i = 0;
  131. foreach ($results as $row) {
  132. $key = $keys[$i];
  133. $newresults[$key] = $row;
  134. $i++;
  135. }
  136. $results = $newresults;
  137. return $results;
  138. }
  139. /**
  140. * Used to add a relationship on the other CRUD object type (in reverse)
  141. *
  142. * @access public
  143. */
  144. function createReverseRelationship() {
  145. // Create relationship on other object
  146. $this->_other_obj->addRelationship(&$this->_owner_obj, $this->_other_field, $this->_owner_field, $this->_reverse_type);
  147. }
  148. /**
  149. * Returns the owner CRUD object
  150. * @access public
  151. * @return AutoCRUD_CRUD
  152. */
  153. function &getOwner() { return $this->_owner_obj; }
  154. /**
  155. * Returns the other CRUD object
  156. * @access public
  157. * @return AutoCRUD_CRUD
  158. */
  159. function &getOther() { return $this->_other_obj; }
  160. /**
  161. * Used to set the fields used in the relationship
  162. *
  163. * @access public
  164. * @param string $owner name of the owner field
  165. * @param string $other name of the other field
  166. */
  167. function setFields($owner, $other) {
  168. $this->_owner_field = $owner;
  169. $this->_other_field = $other;
  170. return true;
  171. }
  172. /**
  173. * Returns the field of the owner table
  174. * @access public
  175. * @return string
  176. */
  177. function getOwnerField() { return $this->_owner_field; }
  178. /**
  179. * Returns the field of the other table
  180. * @access public
  181. * @return string
  182. */
  183. function getOtherField() { return $this->_other_field; }
  184. /**
  185. * Used to set the type of relationship
  186. *
  187. * @access public
  188. * @param string $type the type of relationship, valid types are one-to-one,
  189. * many-to-one, one-to-many, many-to-many and child-parent
  190. * @return mixed true on success, error object on failure
  191. */
  192. function setType($type) {
  193. // Check type of relationship:
  194. // - one-to-one: both tables only have one record, e.g. a article table with an author in the author table (and each article has only one author).
  195. // - many-to-one: the first table ($this->table) has many records which link to one record in the second table, e.g. comments table and a article table.
  196. // - one-to-many: the first table ($this->table) has one records which links to many records in the second table, basically the many-to-one relationship turned around
  197. // - many-to-many: the first table ($this->table) has many records which links to many records in the second table. This type of relationship must use a third table for the relation ship, for example a users table and groups table needs a membership table which links both tables.
  198. // - child-parent: this relation only concerns one category and is used when rows can have sub-rows. Field 1 refers to the 'parent' field and field 2 to the primary key field (the parent identifier anyway)
  199. $types = array('one-to-one', 'many-to-one', 'one-to-many', 'many-to-many', 'child-parent');
  200. if (in_array($type, $types) == false) {
  201. return $this->halt ('invalid-type', 'Invalid relationship type passed');
  202. }
  203. // Detect reverse type
  204. if ($type == 'many-to-one') {
  205. $reverse_type = 'one-to-many';
  206. } elseif ($type == 'one-to-many') {
  207. $reverse_type = 'many-to-one';
  208. } else {
  209. $reverse_type = $type;
  210. }
  211. // Many-to-one is really a one-to-one relationship (for this table, for the other table it's one-to-many)
  212. if ($type == 'many-to-one') { $type = 'one-to-one'; }
  213. // Set type and reverse type
  214. $this->_type = $type;
  215. $this->_reverse_type = $reverse_type;
  216. }
  217. /**
  218. * Returns the relationship type
  219. * @access public
  220. * @return string
  221. */
  222. function getType() {
  223. return $this->_type;
  224. }
  225. /**
  226. * Returns the reverse relationship type (e.g. many-to-one when the relationship type is one-to-many)
  227. * @access public
  228. * @return string
  229. */
  230. function getReverseType() {
  231. return $this->_reverse_type;
  232. }
  233. //================================================================================
  234. // Private functions start here
  235. //================================================================================
  236. /**#@+
  237. * @access private
  238. */
  239. function halt($code, $msg='') {
  240. return $this->_owner_obj->halt($code, $msg);
  241. }
  242. function _joinChildParent($results) {
  243. // Get ID's from results
  244. $ids_list = array();
  245. $newresults = array();
  246. $keys = array();
  247. foreach ($results as $key => $row) {
  248. $id = $row[$this->_other_field];
  249. $ids_list[] = $id;
  250. $ids_list[] = $row[$this->_other_field];
  251. $newresults[$id] = $row;
  252. $keys[] = $key;
  253. }
  254. $results = $newresults;
  255. $ids_list = array_unique($ids_list);
  256. $ids_list = implode("', '", $ids_list);
  257. // Get rows from other table
  258. $this->_other_obj->where = $this->_owner_field . " IN ('" . $ids_list . "') OR " . $this->_other_field . " IN ('" . $ids_list . "')";
  259. $other = $this->_other_obj->select($this->_other_field);
  260. // Match every row from other with correct parent
  261. foreach ($other as $row) {
  262. $parent = $row[$this->_owner_field];
  263. if (isset($results[$parent]) == false) { continue; }
  264. if (isset($results[$parent]['children']) == false) {
  265. $results[$parent]['children'] = array();
  266. }
  267. $results[$parent]['children'][] = $row;
  268. }
  269. // Find parents and return keys
  270. $newresults = array();
  271. $i = 0;
  272. foreach ($results as $row) {
  273. $parent = $row[$this->_owner_field];
  274. // Try and find parent
  275. if (isset($other[$parent]) == true) {
  276. $row[$this->_owner_field] = $other[$parent];
  277. }
  278. // Return original key
  279. $key = $keys[$i];
  280. $newresults[$key] = $row;
  281. $i++;
  282. }
  283. $results = $newresults;
  284. return $results;
  285. }
  286. function _joinOne2Many ($results) {
  287. $ids_list = array();
  288. $newresults = array();
  289. $keys = array();
  290. // Get ID's from results
  291. foreach ($results as $key => $row) {
  292. // Get ID
  293. $id = $row[$this->_owner_field];
  294. $ids_list[] = $id;
  295. // Copy to a new array, and add it under its own ID
  296. $newresults[$id] = $row;
  297. // Save key (in case a specific key was being used)
  298. $keys[] = $key;
  299. }
  300. $results = $newresults;
  301. $ids_list = array_unique($ids_list);
  302. $ids_list = implode("', '", $ids_list);
  303. // Get rows from other table
  304. $this->_other_obj->where = "`" . $this->_other_field . "` IN ('" . $ids_list . "')";
  305. $other = $this->_other_obj->select();
  306. // Match other results with results
  307. $name = $this->_other_obj->getName();
  308. foreach ($other as $row) {
  309. $id = $row[$this->_other_field];
  310. // Make sure that array for other rows exist on owner
  311. if (isset($results[$id][$name]) == false OR !is_array($results[$id][$name])) {
  312. $results[$id][$name] = array();
  313. }
  314. // Add row to owner
  315. $results[$id][$name][] = $row;
  316. }
  317. // Return keys
  318. $newresults = array();
  319. $i = 0;
  320. foreach ($results as $row) {
  321. $key = $keys[$i];
  322. $newresults[$key] = $row;
  323. $i++;
  324. }
  325. $results = $newresults;
  326. return $results;
  327. }
  328. function _joinOne2One ($results) {
  329. // Get ID's from results
  330. $ids_list = array();
  331. foreach ($results as $row) {
  332. $ids_list[] = $row[$this->_owner_field];
  333. }
  334. $ids_list = array_unique($ids_list);
  335. $ids_list = implode("', '", $ids_list);
  336. // Now select rows from other table
  337. $this->_other_obj->where = "`" . $this->_other_field . "` IN ('" . $ids_list . "')";
  338. $other = $this->_other_obj->select($this->_other_field);
  339. // Now match each result up
  340. $newresults = array();
  341. foreach ($results as $key => $row) {
  342. // Get id of row
  343. $id = $row[$this->_owner_field];
  344. // Does other row exist?
  345. if (isset($other[$id])) {
  346. // Copy other row
  347. $row[$this->_owner_field] = $other[$id];
  348. }
  349. $newresults[$key] = $row;
  350. }
  351. $results = $newresults;
  352. return $results;
  353. }
  354. /**#@-*/
  355. }
  356. ?>