1: <?php
2:
3: /**
4: * The QDataRepeater is a generic html base object for creating an object that contains a list of items tied
5: * to the database. To specify how to draw the items, you can either create a template file, override the
6: * GetItemHtml method, override the GetItemInnerHtml and GetItemAttributes methods, or specify
7: * corresponding callbacks for those methods.
8: *
9: * The callbacks below can be specified as either a string, or an array. If a string, it should be the name of a
10: * public method in the parent form. If an array, it should be a PHP Callable array. If your callback is a method in
11: * a form, do NOT pass the form object in to the array, but rather just pass the name of the method as a string.
12: * (This is due to a problem PHP has with serializing recursive objects.) If its a method in a control, pass an array
13: * with the control and method name, i.e. [$objControl, 'RenderMethod']
14: *
15: * @package Controls
16: *
17: * @property-read integer $CurrentItemIndex The zero-based index of the item being drawn.
18: * @property string $TagName The tag name to be used as the main object
19: * @property string $ItemTagName The tag name to used for each item (if Template is not defined)
20: * @property string $Template A php template file that will be evaluated for each item. The template will have
21: * $_ITEM as the item in the DataSource array, $_CONTROL as this control, and $_FORM as
22: * the form object. If you provide a template, the callbacks will not be used.
23: * @property-write string $ItemHtmlCallback A Callable which will be called to get the html for each item.
24: * Parameters passed are the item from the DataSource array, and the index of the
25: * item being drawn. The callback should return the entire html for the item. If
26: * you provide this callback, the ItemAttributesCallback and ItemInnerHtmlCallback
27: * will not be used.
28: * @property-write string $ItemAttributesCallback A Callable which will be called to get the attributes for each item.
29: * Use this with the ItemInnerHtmlCallback and the ItemTagName. The callback
30: * will be passed the item and the index of the item. It should return key/value
31: * pairs which will be used as the attributes for the item's tag. Use only
32: * if you are not using a Template or the ItemHtmlCallback.
33: * @property-write string $ItemInnerHtmlCallback A Callable which will be called to get the inner html for each item.
34: * Use this with the ItemAttributesCallback and the ItemTagName. The callback
35: * will be passed the item and the index of the item. It should return the complete
36: * text to appear inside the open and close tags for the item. *
37: */
38: class QDataRepeater extends QPaginatedControl {
39: ///////////////////////////
40: // Private Member Variables
41: ///////////////////////////
42:
43: // APPEARANCE
44: /** @var string */
45: protected $strTemplate = null;
46: /** @var integer */
47: protected $intCurrentItemIndex = null;
48:
49: /** @var string */
50: protected $strTagName = 'div';
51: /** @var string */
52: protected $strItemTagName = 'div';
53:
54: /** @var Callable | string */
55: protected $itemHtmlCallback;
56: /** @var Callable | string */
57: protected $itemAttributesCallback;
58: /** @var Callable | string */
59: protected $itemInnerHtmlCallback;
60:
61:
62: //////////
63: // Methods
64: //////////
65: public function ParsePostData() {}
66:
67: /**
68: * Returns the html corresponding to a given item. You have many ways of rendering an item:
69: * - Specify a template that will get evaluated for each item. See EvaluateTemplate for more info.
70: * - Specify a HtmlCallback callable to be called for each item to get the html for the item.
71: * - Override this routine.
72: * - Specify the item's tag name, and then use the helper functions or callbacks to return just the
73: * attributes and/or inner html of the object.
74: *
75: * @param $objItem
76: * @return string
77: * @throws QCallerException
78: */
79: protected function GetItemHtml($objItem) {
80: if ($this->strTemplate) {
81: return $this->EvaluateTemplate($this->strTemplate);
82: } elseif ($this->itemHtmlCallback) {
83: if (is_string($this->itemHtmlCallback)) {
84: $strMethod = $this->itemHtmlCallback;
85: return $this->objForm->$strMethod($objItem, $this->intCurrentItemIndex);
86: } else {
87: return call_user_func($this->itemHtmlCallback, $objItem, $this->intCurrentItemIndex);
88: }
89: }
90:
91: if (!$this->strItemTagName) {
92: throw new QCallerException ("You must specify an item tag name before rendering the list.");
93: }
94:
95: $strToReturn = QHtml::RenderTag($this->strItemTagName, $this->GetItemAttributes($objItem), $this->GetItemInnerHtml($objItem));
96: return $strToReturn;
97: }
98:
99: /**
100: * Return the attributes that go in the item tag, as an array of key=>value pairs. Values will be escaped for you.
101: * If you define AttributesCallback, it will be used to determine
102: * the attributes.
103: *
104: * @param $objItem
105: * @return array
106: */
107: protected function GetItemAttributes ($objItem) {
108: if ($this->itemAttributesCallback) {
109: if (is_string($this->itemAttributesCallback)) {
110: $strMethod = $this->itemAttributesCallback;
111: return $this->objForm->$strMethod($objItem, $this->intCurrentItemIndex);
112: } else {
113: return call_user_func($this->itemAttributesCallback, $objItem, $this->intCurrentItemIndex);
114: }
115: }
116: return null;
117: }
118:
119: /**
120: * Returns the HTML between the item tags. Uses __toString on the object by default. Will use the
121: * InnerHtmlCallback if provided.
122: *
123: * @param $objItem
124: * @return mixed
125: */
126: protected function GetItemInnerHtml($objItem) {
127: if ($this->itemInnerHtmlCallback) {
128: if (is_string($this->itemInnerHtmlCallback)) {
129: $strMethod = $this->itemInnerHtmlCallback;
130: return $this->objForm->$strMethod($objItem, $this->intCurrentItemIndex);
131: } else {
132: return call_user_func($this->itemInnerHtmlCallback, $objItem, $this->intCurrentItemIndex);
133: }
134: }
135: return $objItem->__toString(); // default to rendering a database object
136: }
137:
138: /**
139: * Returns the HTML for the control.
140: * @return string
141: */
142: protected function GetControlHtml() {
143: $this->DataBind();
144:
145: // Iterate through everything
146: $this->intCurrentItemIndex = 0;
147: $strEvalledItems = '';
148: $strToReturn = '';
149: if ($this->objDataSource) {
150: global $_FORM;
151: global $_CONTROL;
152: global $_ITEM;
153:
154: $objCurrentControl = $_CONTROL;
155: $_CONTROL = $this;
156:
157: foreach ($this->objDataSource as $objObject) {
158: $_ITEM = $objObject;
159: $strEvalledItems .= $this->GetItemHtml($objObject);
160: $this->intCurrentItemIndex++;
161: }
162:
163: $_CONTROL = $objCurrentControl;
164: }
165:
166: $strToReturn = $this->RenderTag($this->strTagName,
167: null,
168: null,
169: $strEvalledItems);
170:
171: $this->objDataSource = null;
172: return $strToReturn;
173: }
174:
175: /////////////////////////
176: // Public Properties: GET
177: /////////////////////////
178: /**
179: * PHP magic method
180: *
181: * @param string $strName Name of the property
182: *
183: * @return int|mixed|string
184: * @throws Exception|QCallerException
185: */
186: public function __get($strName) {
187: switch ($strName) {
188: // APPEARANCE
189: case "Template": return $this->strTemplate;
190: case "CurrentItemIndex": return $this->intCurrentItemIndex;
191: case "TagName": return $this->strTagName;
192: case "ItemTagName": return $this->strItemTagName;
193:
194: default:
195: try {
196: return parent::__get($strName);
197: } catch (QCallerException $objExc) {
198: $objExc->IncrementOffset();
199: throw $objExc;
200: }
201: }
202: }
203:
204: /////////////////////////
205: // Public Properties: SET
206: /////////////////////////
207: /**
208: * PHP magic method
209: *
210: * @param string $strName Property name
211: * @param string $mixValue Property value
212: *
213: * @return mixed|void
214: * @throws Exception|QCallerException|QInvalidCastException
215: */
216: public function __set($strName, $mixValue) {
217: switch ($strName) {
218: // APPEARANCE
219: case "Template":
220: try {
221: $this->blnModified = true;
222: if ($mixValue) {
223: if (file_exists($strPath = $this->GetTemplatePath($mixValue))) {
224: $this->strTemplate = QType::Cast($strPath, QType::String);
225: } else {
226: throw new QCallerException('Could not find template file: ' . $mixValue);
227: }
228: } else {
229: $this->strTemplate = null;
230: }
231: break;
232: } catch (QInvalidCastException $objExc) {
233: $objExc->IncrementOffset();
234: throw $objExc;
235: }
236:
237: case "TagName":
238: try {
239: $this->blnModified = true;
240: $this->strTagName = QType::Cast($mixValue, QType::String);
241: break;
242: } catch (QInvalidCastException $objExc) {
243: $objExc->IncrementOffset();
244: throw $objExc;
245: }
246:
247: case 'ItemTagName':
248: try {
249: $this->blnModified = true;
250: $this->strItemTagName = QType::Cast($mixValue, QType::String);
251: break;
252: } catch (QInvalidCastException $objExc) {
253: $objExc->IncrementOffset();
254: throw $objExc;
255: }
256:
257: case 'ItemHtmlCallback':
258: $this->blnModified = true;
259: if (is_array($mixValue) && reset($mixValue) === $this->objForm) {
260: // Do not pass [$objForm, 'methodName']. Rather, just set to 'methodName', and the form will be searched for that method.
261: throw new QCallerException ('Do not pass the form object in a callable array. Instead, just pass the method name.');
262: }
263: $this->itemHtmlCallback = $mixValue;
264: break;
265:
266: case 'ItemAttributeCallback': // callback should return an array of key/value items
267: $this->blnModified = true;
268: if (is_array($mixValue) && reset($mixValue) === $this->objForm) {
269: // Do not pass [$objForm, 'methodName']. Rather, just set to 'methodName', and the form will be searched for that method.
270: throw new QCallerException ('Do not pass the form object in a callable array. Instead, just pass the method name.');
271: }
272: $this->itemAttributeCallback = $mixValue;
273: break;
274:
275: case 'ItemInnerHtmlCallback':
276: $this->blnModified = true;
277: if (is_array($mixValue) && reset($mixValue) === $this->objForm) {
278: // Do not pass [$objForm, 'methodName']. Rather, just set to 'methodName', and the form will be searched for that method.
279: throw new QCallerException ('Do not pass the form object in a callable array. Instead, just pass the method name.');
280: }
281: $this->itemInnerHtmlCallback = $mixValue;
282: break;
283:
284: default:
285: try {
286: parent::__set($strName, $mixValue);
287: } catch (QCallerException $objExc) {
288: $objExc->IncrementOffset();
289: throw $objExc;
290: }
291: break;
292: }
293: }
294: }