1: <?php
2:
3: /**
4: * A checkbox column that specifically is for inclusion in a QDataGrid object. The two work together to hand off
5: * important events and functionality.
6: *
7: * The default functionality of this class shows the name of the column in the header, and uses the primary key of
8: * a database object as the checkbox id. It also
9: * stores the information on which boxes are checked in the session variable so that they can be easily recalled and do
10: * not clutter the form state. You can override additional functions below if you would like to store the checkbox state
11: * with the items themselves, or somewhere else.
12: *
13: * If you turn on the CheckAll box in the header, you must subclass this column, and at a minimum implement the GetAllIds() function
14: * so that it knows the full set of ids to record as checked.
15: *
16: * This column keeps track of what is checked and not checked in real time using ajax, rather than using POST methods.
17: * The primary reason is that what is visible in the table will generally not be the complete set of data available from
18: * the database if the datagrid is using a paginator.
19: *
20: * @package Controls
21: */
22:
23: class QDataGrid_CheckBoxColumn extends QHtmlTableCheckBoxColumn {
24: /** @var bool Record the state of the AllChecked checkbox in the header. */
25: protected $blnAllChecked;
26: protected $blnShowCheckAll = false; // Default to false so that we have default functionality that does not require subclassing.
27:
28: /**
29: * Return the array of item ids that are checked. Default stores the ids in the session. Override if you are storing
30: * them elsewhere.
31: *
32: * @return array
33: */
34: public function GetCheckedItemIds() {
35: $strFormId = $this->ParentTable->Form->FormId;
36: $strTableId = $this->ParentTable->ControlId;
37:
38: if (!empty($_SESSION['checkedItems'][$strFormId][$strTableId][$this->strId])) {
39: return array_keys($_SESSION['checkedItems'][$strFormId][$strTableId][$this->strId]);
40: }
41: else {
42: return array();
43: }
44: }
45:
46: /**
47: * Clear all the checked items. Default stores the ids in the session. Override if you are storing
48: * them elsewhere.
49: */
50: public function ClearCheckedItems() {
51: if ($this->ParentTable) {
52: $strFormId = $this->ParentTable->Form->FormId;
53: $strTableId = $this->ParentTable->ControlId;
54: unset($_SESSION['checkedItems'][$strFormId][$strTableId][$this->strId]);
55: }
56: }
57:
58: /**
59: * A checkbox in the column was clicked. The parent datagrid routes checkbox clicks to this function. Not for
60: * general consumption.
61: *
62: * We are detecting every click, rather than using ParsePostData, because in a multi-user environment,
63: * post data can be stale. Also, post data only tells us what is turned on, not what is turned off, and
64: * so we would need to query the database to see what is missing from the post data to know what should be
65: * turned off. This could be tricky, as the list of visible items might have changed.
66: *
67: * Known issue: If you do the following things, the check all box is not checked:
68: * - Click check all, then uncheck one item, then recheck that item. To fix would require querying the entire
69: * list every time one item is checked. Not important enough to slow things down like that.
70: * - Click check all, then refresh the page. This is actually by design, because in a multi-user environment,
71: * if you refresh the page, you may get new items in the list which the previous check all click would not have
72: * checked.
73: *
74: * @param $strParameter
75: */
76: public function Click($strParameter) {
77: $blnChecked = QType::Cast($strParameter['checked'], QType::Boolean);
78:
79: $idItems = explode('_', $strParameter['id']);
80: $strItemId = end($idItems);
81:
82: if ($strItemId == 'all') {
83: $this->CheckAll($blnChecked);
84: $this->blnAllChecked = $blnChecked;
85: }
86: else {
87: $this->SetItemCheckedState($strItemId, $blnChecked);
88: if (!$blnChecked) {
89: $this->blnAllChecked = false;
90: }
91: // since we are in a datagrid, we would have to query all the data to know whether checking one item
92: // leaves the control in a state where all the items are checked. This is a lot of work to save the
93: // user one extra click.
94: }
95: }
96:
97:
98:
99: /** QHtmlTableCheckboxColumn Overrides */
100:
101: /**
102: * The overrides below implement the needed functionality for the QHtmlTableCheckBoxColumn superclass.
103: * You shouldn't need to change them. They eventually call into GetItemId, which you will need to override
104: * to return the item id of the given line item.
105: */
106:
107: /**
108: * Return the id attribute of the checkbox tag. Must be unique to the form. This will use the column id, which
109: * should be unique, and add the item id to the end to generate the object id.
110: *
111: * @param mixed|null $item
112: * @return null|string
113: */
114: protected function GetCheckboxId ($item) {
115: return $this->Id . '_' . $this->_GetItemId($item); // id here must be unique to the form
116: }
117:
118: /**
119: * Return the value attribute of the checkbox tag. Values are required in html for checkboxes.
120: *
121: * @param mixed|null $item
122: * @return string
123: */
124: protected function GetCheckboxValue($item) {
125: return ''; // Since we are not using post to submit information, we don't need a value.
126: }
127:
128: /**
129: * Return true to draw the checkbox corresponding to this item as checked, and false for unchecked.
130: * @param mixed|null $item
131: * @return bool
132: */
133: protected function IsChecked($item) {
134: if (is_null($item)) {
135: return $this->blnAllChecked;
136: }
137: else {
138: return $this->GetItemCheckedState($item);
139: }
140: }
141:
142: public function GetCheckboxParams ($item) {
143: $params = parent::GetCheckboxParams($item);
144: $params['data-col'] = $this->strId;
145:
146: if (!$item) {
147: // the check all box
148: // sets the currently visible checkboxes appropriately
149: $params['onclick'] = sprintf('$j("#%s input:checkbox[data-col=%s]").prop("checked", this.checked)', $this->ParentTable->ControlId, $this->strId);
150: }
151: return $params;
152: }
153:
154: /** End QHtmlTableCheckboxColumn Overrides */
155:
156: /**
157: * Returns the checked state of the item. Default stores the ids in the session. Override if you are storing
158: * them elsewhere.
159: *
160: * @param $item
161: * @return bool
162: */
163: protected function GetItemCheckedState ($item) {
164: $strFormId = $this->ParentTable->Form->FormId;
165: $strTableId = $this->ParentTable->ControlId;
166: $id = $this->GetItemId($item);
167: $blnChecked = !empty($_SESSION['checkedItems'][$strFormId][$strTableId][$this->strId][$id]);
168: return $blnChecked;
169: }
170:
171:
172: /**
173: * Saves the checked state of the item to be recalled later. Default stores the ids in the session. Override if you are storing
174: * them elsewhere.
175: *
176: * @param $itemId
177: * @param $blnChecked
178: */
179: protected function SetItemCheckedState ($itemId, $blnChecked) {
180: $strFormId = $this->ParentTable->Form->FormId;
181: $strTableId = $this->ParentTable->ControlId;
182: if ($blnChecked) {
183: $_SESSION['checkedItems'][$strFormId][$strTableId][$this->strId][$itemId] = true;
184: }
185: else {
186: unset($_SESSION['checkedItems'][$strFormId][$strTableId][$this->strId][$itemId]);
187: }
188: }
189:
190: /**
191: * Checks or unchecks all the items. This will check or uncheck each individual item. Override to use a mechanism
192: * to check them all at once.
193: *
194: * @param $blnChecked True to check all, false to uncheck all
195: */
196: protected function CheckAll($blnChecked) {
197: $ids = $this->GetAllIds();
198:
199: if ($ids === null) {
200: throw new Exception('You must create a subclass and implement GetAllIds() when showing the Check All box.');
201: }
202:
203: if ($ids) foreach ($ids as $id) {
204: $this->SetItemCheckedState($id, $blnChecked);
205: }
206: }
207:
208: /**
209: * Internal helper to eventually get the item id.
210: *
211: * @param mixed|null $item
212: * @return string
213: */
214: private function _GetItemId($item) {
215: if ($item) {
216: return $this->GetItemId($item);
217: } else {
218: return 'all';
219: }
220: }
221:
222: /**
223: * Override this to return an array of all the ids of the objects in the table, including ids that are not
224: * currently visible on the page being shown. If you create your own CheckAll function, or if you are not showing
225: * the CheckAll box in the header you do not need to implement this.
226: *
227: * If you want to return an empty set, return an empty array.
228: *
229: * @return array|null
230: */
231: protected function GetAllIds() {
232: return null;
233: }
234:
235: /**
236: * Returns the unique id of the given item. This id will be used to generate the id in the tag
237: * of the checkbox, but will not directly correspond to the id. The given item id only needs to be unique within your
238: * list of items.
239: *
240: * The default will assume this is a database object and use the primary key as the id. Override if you want something else.
241: *
242: * @param mixed $item
243: * @return string
244: */
245: protected function GetItemId($item) {
246: if (is_object($item)) {
247: return $item->PrimaryKey();
248: }
249: }
250:
251: }
252:
253: