1: <?php
2: /**
3: * Object joint handler class.
4: *
5: * You may not change or alter any portion of this comment or credits
6: * of supporting developers from this source code or any supporting source code
7: * which is considered copyrighted (c) material of the original comment or credit authors.
8: * This program is distributed in the hope that it will be useful,
9: * but WITHOUT ANY WARRANTY; without even the implied warranty of
10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11: *
12: * @copyright (c) 2000-2016 XOOPS Project (www.xoops.org)
13: * @license GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14: * @package kernel
15: * @subpackage model
16: * @since 2.3.0
17: * @author Taiwen Jiang <phppp@users.sourceforge.net>
18: */
19: defined('XOOPS_ROOT_PATH') || exit('Restricted access');
20:
21: /**
22: * Object joint handler class.
23: *
24: * @author Taiwen Jiang <phppp@users.sourceforge.net>
25: *
26: * {@link XoopsModelAbstract}
27: */
28:
29: /**
30: * Usage of methods provided by XoopsModelJoint:
31: *
32: * Step #1: set linked table and adjoint fields through XoopsPersistableObjectHandler:
33: * $handler->table_link = $handler->db->prefix("the_linked_table"); // full name of the linked table that is used for the query
34: * $handler->field_link = "the_linked_field"; // name of field in linked table that will be used to link the linked table with current table
35: * $handler->field_object = "the_object_field"; // name of field in current table that will be used to link the linked table with current table; linked field name will be used if the field name is not set
36: * Step #2: fetch data
37: */
38: class XoopsModelJoint extends XoopsModelAbstract
39: {
40: /**
41: * Validate information for the link
42: *
43: * @access private
44: */
45: public function validateLinks()
46: {
47: if (empty($this->handler->table_link) || empty($this->handler->field_link)) {
48: trigger_error('The linked table is not set yet.', E_USER_WARNING);
49:
50: return null;
51: }
52: if (empty($this->handler->field_object)) {
53: $this->handler->field_object = $this->handler->field_link;
54: }
55:
56: return true;
57: }
58:
59: /**
60: * get a list of objects matching a condition joint with another related object
61: *
62: * @param CriteriaElement|CriteriaCompo $criteria
63: * @param array $fields variables to fetch
64: * @param bool $asObject flag indicating as object, otherwise as array
65: * @param string $field_link field of linked object for JOIN; deprecated, for backward compatibility
66: * @param string $field_object field of current object for JOIN; deprecated, for backward compatibility
67: * @return array of objects <a href='psi_element://XoopsObject'>XoopsObject</a>
68: * @internal param CriteriaElement $object <a href='psi_element://CriteriaElement'>CriteriaElement</a> to match to match
69: */
70: public function &getByLink(CriteriaElement $criteria = null, $fields = null, $asObject = true, $field_link = null, $field_object = null)
71: {
72: if (!empty($field_link)) {
73: $this->handler->field_link = $field_link;
74: }
75: if (!empty($field_object)) {
76: $this->handler->field_object = $field_object;
77: }
78: if (!$this->validateLinks()) {
79: return null;
80: }
81:
82: if (!empty($fields) && \is_array($fields)) {
83: if (!in_array('o.' . $this->handler->keyName, $fields)) {
84: $fields[] = 'o.' . $this->handler->keyName;
85: }
86: $select = implode(',', $fields);
87: } else {
88: $select = 'o.*, l.*';
89: }
90: $limit = null;
91: $start = null;
92: // $field_object = empty($field_object) ? $field_link : $field_object;
93: $sql = " SELECT {$select}" . " FROM {$this->handler->table} AS o" . " LEFT JOIN {$this->handler->table_link} AS l ON o.{$this->handler->field_object} = l.{$this->handler->field_link}";
94: if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
95: $sql .= ' ' . $criteria->renderWhere();
96: if ($sort = $criteria->getSort()) {
97: $sql .= " ORDER BY {$sort} " . $criteria->getOrder();
98: $orderSet = true;
99: }
100: $limit = $criteria->getLimit();
101: $start = $criteria->getStart();
102: }
103: if (empty($orderSet)) {
104: $sql .= " ORDER BY o.{$this->handler->keyName} DESC";
105: }
106: $result = $this->handler->db->query($sql, $limit, $start);
107: if (!$this->handler->db->isResultSet($result)) {
108: throw new \RuntimeException(
109: \sprintf(_DB_QUERY_ERROR, $sql) . $this->handler->db->error(), E_USER_ERROR
110: );
111: }
112: $ret = array();
113: if ($asObject) {
114: while (false !== ($myrow = $this->handler->db->fetchArray($result))) {
115: $object = $this->handler->create(false);
116: $object->assignVars($myrow);
117: $ret[$myrow[$this->handler->keyName]] = $object;
118: unset($object);
119: }
120: } else {
121: $object = $this->handler->create(false);
122: while (false !== ($myrow = $this->handler->db->fetchArray($result))) {
123: $object->assignVars($myrow);
124: $ret[$myrow[$this->handler->keyName]] = $object->getValues(array_keys($myrow));
125: }
126: unset($object);
127: }
128:
129: return $ret;
130: }
131:
132: /**
133: * Count of objects matching a condition
134: *
135: * @param CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement} to match
136: * @return int|false count of objects
137: */
138: public function getCountByLink(CriteriaElement $criteria = null)
139: {
140: if (!$this->validateLinks()) {
141: return null;
142: }
143:
144: $sql = " SELECT COUNT(DISTINCT o.{$this->handler->keyName}) AS count" . " FROM {$this->handler->table} AS o" . " LEFT JOIN {$this->handler->table_link} AS l ON o.{$this->handler->field_object} = l.{$this->handler->field_link}";
145: if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
146: $sql .= ' ' . $criteria->renderWhere();
147: }
148: $result = $this->handler->db->query($sql);
149: if (!$this->handler->db->isResultSet($result)) {
150: return false;
151: }
152: $myrow = $this->handler->db->fetchArray($result);
153:
154: return (int)$myrow['count'];
155: }
156:
157: /**
158: * array of count of objects matching a condition of, groupby linked object keyname
159: *
160: * @param CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement} to match
161: * @return int|false|array|null count of objects
162: */
163: public function getCountsByLink(CriteriaElement $criteria = null)
164: {
165: if (!$this->validateLinks()) {
166: return null;
167: }
168: $sql = " SELECT l.{$this->handler->field_link}, COUNT(*)" . " FROM {$this->handler->table} AS o" . " LEFT JOIN {$this->handler->table_link} AS l ON o.{$this->handler->field_object} = l.{$this->handler->field_link}";
169: if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
170: $sql .= ' ' . $criteria->renderWhere();
171: }
172: $sql .= " GROUP BY l.{$this->handler->field_link}";
173: $result = $this->handler->db->query($sql);
174: if (!$this->handler->db->isResultSet($result)) {
175: return false;
176: }
177: $ret = array();
178: while (false !== (list($id, $count) = $this->handler->db->fetchRow($result))) {
179: $ret[$id] = $count;
180: }
181:
182: return $ret;
183: }
184:
185: /**
186: * update objects matching a condition against linked objects
187: *
188: * @param array $data array of key => value
189: * @param CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement} to match
190: * @return int|null count of objects
191: */
192: public function updateByLink($data, CriteriaElement $criteria = null)
193: {
194: if (!$this->validateLinks()) {
195: return null;
196: }
197: $set = array();
198: foreach ($data as $key => $val) {
199: $set[] = "o.{$key}=" . $this->handler->db->quoteString($val);
200: }
201: $sql = " UPDATE {$this->handler->table} AS o" . ' SET ' . implode(', ', $set) . " LEFT JOIN {$this->handler->table_link} AS l ON o.{$this->handler->field_object} = l.{$this->handler->field_link}";
202: if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
203: $sql .= ' ' . $criteria->renderWhere();
204: }
205:
206: return $this->handler->db->query($sql);
207: }
208:
209: /**
210: * Delete objects matching a condition against linked objects
211: *
212: * @param CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement} to match
213: * @return int|null count of objects
214: */
215: public function deleteByLink(CriteriaElement $criteria = null)
216: {
217: if (!$this->validateLinks()) {
218: return null;
219: }
220: $sql = "DELETE FROM {$this->handler->table} AS o " . " LEFT JOIN {$this->handler->table_link} AS l ON o.{$this->handler->field_object} = l.{$this->handler->field_link}";
221: if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
222: $sql .= ' ' . $criteria->renderWhere();
223: }
224:
225: return $this->handler->db->query($sql);
226: }
227: }
228: