/
GxController.php
200 lines (181 loc) · 7.62 KB
/
GxController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<?php
/**
* GxController class file.
*
* @author Rodrigo Coelho <rodrigo@giix.org>
* @link http://giix.org/
* @copyright Copyright © 2010-2011 Rodrigo Coelho
* @license http://giix.org/license/ New BSD License
*/
/**
* GxController is the base class for the generated controllers.
*
* @author Rodrigo Coelho <rodrigo@giix.org>
* @package giix.components
*/
abstract class GxController extends Controller {
/**
* @var string The layout for the controller view.
*/
public $layout = '//layouts/column2';
/**
* @var array Context menu items. This property will be assigned to {@link CMenu::items}.
*/
public $menu = array();
/**
* @var array The breadcrumbs of the current page. The value of this property will
* be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
* for more details on how to specify this property.
*/
public $breadcrumbs = array();
/**
* Returns the data model based on the primary key or another attribute.
* This method is designed to work with the values passed via GET.
* If the data model is not found or there's a malformed key, an
* HTTP exception will be raised.
* #MethodTracker
* This method is based on the gii generated method controller::loadModel, from version 1.1.7 (r3135). Changes:
* <ul>
* <li>Support to composite PK.</li>
* <li>Support to use any attribute (column) name besides the PK.</li>
* <li>Support to multiple attributes.</li>
* <li>Automatically detects the PK column names.</li>
* </ul>
* @param mixed $key The key or keys of the model to be loaded.
* If the key is a string or an integer, the method will use the tables' PK if
* the PK has a single column. If the table has a composite PK and the key
* has a separator (see below), the method will detect it and use it.
* <pre>
* $key = '12-27'; // PK values with separator for tables with composite PK.
* </pre>
* If $key is an array, it can be indexed by integers or by attribute (column)
* names, as for {@link CActiveRecord::findByAttributes}.
* If the array doesn't have attribute names, as below, the method will use
* the table composite PK.
* <pre>
* $key = array(
* 12,
* 27,
* ...,
* );
* </pre>
* If the array is indexed by attribute names, as below, the method will use
* the attribute names to search for and load the model.
* <pre>
* $key = array(
* 'model_id' => 44,
* ...,
* );
* </pre>
* Warning: each attribute used should have an index on the database and the set of
* attributes used should identify only one item on the database (the attributes being
* ideally part of or multiple unique keys).
* @param string $modelClass The model class name.
* @return GxActiveRecord The loaded model.
* @see GxActiveRecord::pkSeparator
* @throws CHttpException if there's an invalid request (with code 400) or if the model is not found (with code 404).
*/
public function loadModel($key, $modelClass) {
// Get the static model.
$staticModel = GxActiveRecord::model($modelClass);
if (is_array($key)) {
// The key is an array.
// Check if there are column names indexing the values in the array.
reset($key);
if (key($key) === 0) {
// There are no attribute names.
// Check if there are multiple PK values. If there's only one, start again using only the value.
if (count($key) === 1)
return $this->loadModel($key[0], $modelClass);
// Now we will use the composite PK.
// Check if the table has composite PK.
$tablePk = $staticModel->getTableSchema()->primaryKey;
if (!is_array($tablePk))
throw new CHttpException(400, Yii::t('giix.messages', 'Your request is invalid.'));
// Check if there are the correct number of keys.
if (count($key) !== count($tablePk))
throw new CHttpException(400, Yii::t('giix.messages', 'Your request is invalid.'));
// Get an array of PK values indexed by the column names.
$pk = $staticModel->fillPkColumnNames($key);
// Then load the model.
$model = $staticModel->findByPk($pk);
} else {
// There are attribute names.
// Then we load the model now.
$model = $staticModel->findByAttributes($key);
}
} else {
// The key is not an array.
// Check if the table has composite PK.
$tablePk = $staticModel->getTableSchema()->primaryKey;
if (is_array($tablePk)) {
// The table has a composite PK.
// The key must be a string to have a PK separator.
if (!is_string($key))
throw new CHttpException(400, Yii::t('giix.messages', 'Your request is invalid.'));
// There must be a PK separator in the key.
if (stripos($key, $staticModel->pkSeparator) === false)
throw new CHttpException(400, Yii::t('giix.messages', 'Your request is invalid.'));
// Generate an array, splitting by the separator.
$keyValues = explode($staticModel->pkSeparator, $key);
// Start again using the array.
return $this->loadModel($keyValues, $modelClass);
} else {
// The table has a single PK.
// Then we load the model now.
$model = $staticModel->findByPk($key);
}
}
// Check if we have a model.
if ($model === null)
throw new CHttpException(404, Yii::t('giix.messages', 'The requested page does not exist.'));
return $model;
}
/**
* Performs the AJAX validation.
* #MethodTracker
* This method is based on the gii generated method controller::performAjaxValidation, from version 1.1.7 (r3135). Changes:
* <ul>
* <li>Supports multiple models.</li>
* </ul>
* @param CModel|array $model The model or array of models to be validated.
* @param string $form The name of the form. Optional.
*/
protected function performAjaxValidation($model, $form = null) {
if (Yii::app()->getRequest()->getIsAjaxRequest() && (($form === null) || ($_POST['ajax'] == $form))) {
echo GxActiveForm::validate($model);
Yii::app()->end();
}
}
/**
* Finds the related primary keys specified in the form POST.
* Only for HAS_MANY and MANY_MANY relations.
* @param array $form The post data.
* @param array $relations A list of model relations in the format returned by {@link CActiveRecord::relations}.
* @param string $uncheckValue Since Yii 1.1.7, htmlOptions (in {@link CHtml::activeCheckBoxList})
* has an option named 'uncheckValue'. If you set it to different values than the default value (''), you will
* need to set the appropriate value to this argument. This method can't be used when 'uncheckValue' is null.
* @return array An array where the keys are the relation names (string) and the values are arrays with the related model primary keys (int|string) or composite primary keys (array with pk name (string) => pk value (int|string)).
* Example of returned data:
* <pre>
* array(
* 'categories' => array(1, 4),
* 'tags' => array(array('id1' => 3, 'id2' => 7), array('id1' => 2, 'id2' => 0)) // composite pks
* )
* </pre>
* An empty array is returned in case there is no related pk data from the post.
* This data comes directly from the form POST data.
* @see GxHtml::activeCheckBoxList
* @throws InvalidArgumentException If uncheckValue is null.
*/
protected function getRelatedData($form, $relations, $uncheckValue = '') {
if ($uncheckValue === null)
throw new InvalidArgumentException(Yii::t('giix.messages', 'giix cannot handle automatically the POST data if "uncheckValue" is null.'));
$relatedPk = array();
foreach ($relations as $relationName => $relationData) {
if (isset($form[$relationName]) && (($relationData[0] == GxActiveRecord::HAS_MANY) || ($relationData[0] == GxActiveRecord::MANY_MANY)))
$relatedPk[$relationName] = $form[$relationName] === $uncheckValue ? null : $form[$relationName];
}
return $relatedPk;
}
}