HCE Project DC service web UI  0.2
Hierarchical Cluster Engine DC service web UI
 All Classes Namespaces Files Functions Variables Pages
TbEditableField.php
Go to the documentation of this file.
1 <?php
11 Yii::import('booster.widgets.TbEditable');
12 
19 {
23  public $model = null;
27  public $attribute = null;
28 
34  private $staticModel = null;
35 
40  public function init()
41  {
42  if (!$this->model) {
43  throw new CException('Parameter "model" should be provided for TbEditableField');
44  }
45 
46  if (!$this->attribute) {
47  throw new CException('Parameter "attribute" should be provided for TbEditableField');
48  }
49 
50  $originalModel = $this->model;
51  $originalAttribute = $this->attribute;
52  $originalText = strlen($this->text) ? $this->text : CHtml::value($this->model, $this->attribute);
53 
54  //if apply set manually to false --> just render text, no js plugin applied
55  if($this->apply === false) {
56  $this->text = $originalText;
57  } else {
58  $this->apply = true;
59  }
60 
61  //try to resolve related model (if attribute contains '.')
62  $resolved = $this->resolveModels($this->model, $this->attribute);
63  $this->model = $resolved['model'];
64  $this->attribute = $resolved['attribute'];
65  $this->staticModel = $resolved['staticModel'];
67  $isMongo = $resolved['isMongo'];
68  $isFormModel = $this->model instanceOf CFormModel;
69 
70  //if real (related) model not exists --> just print text
71  if(!$this->model) {
72  $this->apply = false;
73  $this->text = $originalText;
74  }
75 
76 
77  //for security reason only safe attributes can be editable (e.g. defined in rules of model)
78  //just print text (see 'run' method)
79  if (!$staticModel->isAttributeSafe($this->attribute)) {
80  $this->apply = false;
81  $this->text = $originalText;
82  }
83 
84  /*
85  try to detect type from metadata if not set
86  */
87  if ($this->type === null) {
88  $this->type = 'text';
89  if (!$isMongo && !$isFormModel && array_key_exists($this->attribute, $staticModel->tableSchema->columns)) {
90  $dbType = $staticModel->tableSchema->columns[$this->attribute]->dbType;
91  if($dbType == 'date') {
92  $this->type = 'date';
93  }
94  if($dbType == 'datetime') {
95  $this->type = 'datetime';
96  }
97  if(stripos($dbType, 'text') !== false) {
98  $this->type = 'textarea';
99  }
100  }
101  }
102 
103  //name
104  if(empty($this->name)) {
105  $this->name = $isMongo ? $originalAttribute : $this->attribute;
106  }
107 
108  //pk (for mongo takes pk from parent!)
109  $pkModel = $isMongo ? $originalModel : $this->model;
110  if(!$isFormModel) {
111  if($pkModel && !$pkModel->isNewRecord) {
112  $this->pk = $pkModel->primaryKey;
113  }
114  } else {
115  //formModel does not have pk, so set `send` option to `always` (send without pk)
116  if(empty($this->send) && empty($this->options['send'])) {
117  $this->send = 'always';
118  }
119  }
120 
121  parent::init();
122 
123  /*
124  If text not defined, generate it from model attribute for types except lists ('select', 'checklist' etc)
125  For lists keep it empty to apply autotext.
126  $this->_prepareToAutotext calculated in parent class TbEditable.php
127  */
128  if (!strlen($this->text) && !$this->_prepareToAutotext) {
129  $this->text = $originalText;
130  }
131 
132  //set value directly for autotext generation
133  if($this->model && $this->_prepareToAutotext) {
134  $this->value = CHtml::value($this->model, $this->attribute);
135  }
136 
137  //generate title from attribute label
138  if ($this->title === null) {
139  $titles = array(
140  'Select' => array('select', 'date'),
141  'Check' => array('checklist')
142  );
143  $title = Yii::t('TbEditableField.editable', 'Enter');
144  foreach($titles as $t => $types) {
145  if(in_array($this->type, $types)) {
146  $title = Yii::t('TbEditableField.editable', $t);
147  }
148  }
149  $this->title = $title . ' ' . $staticModel->getAttributeLabel($this->attribute);
150  } else {
151  $this->title = strtr($this->title, array('{label}' => $staticModel->getAttributeLabel($this->attribute)));
152  }
153 
154  //scenario
155  if($pkModel && !isset($this->params['scenario'])) {
156  $this->params['scenario'] = $pkModel->getScenario();
157  }
158  }
159 
160  public function getSelector()
161  {
162  return str_replace('\\', '_', get_class($this->staticModel)).'_'.parent::getSelector();
163  }
164 
165 
173  public static function isMongo($model)
174  {
175  return in_array('EMongoEmbeddedDocument', class_parents($model, false));
176  }
177 
187  public static function resolveModels($model, $attribute)
188  {
189  //attribute contains dot: related model, trying to resolve
190  $explode = explode('.', $attribute);
191  $len = count($explode);
192 
193  $isMongo = self::isMongo($model);
194 
195  if($len > 1) {
196  $attribute = $explode[$len-1];
197  //try to resolve model instance
198  $resolved = true;
199  for($i = 0; $i < $len-1; $i++) {
200  $name = $explode[$i];
201  if($model->$name instanceof CModel) {
202  $model = $model->$name;
203  } else {
204  //related model not exist! Render text only.
205  //$this->apply = false;
206  $resolved = false;
207  //$this->text = $originalText;
208  break;
209  }
210  }
211 
212  if($resolved) {
214  } else { //related model not resolved: maybe not exists
215  $relationName = $explode[$len-2];
216  if($model instanceof CActiveRecord) {
217  $className = $model->getActiveRelation($relationName)->className;
218  } elseif($isMongo) {
219  $embedded = $model->embeddedDocuments();
220  if(isset($embedded[$relationName])) {
221  $className = $embedded[$relationName];
222  } else {
223  throw new CException('Embedded relation not found');
224  }
225  } else {
226  throw new CException('Unsupported model class '.$relationName);
227  }
228  $staticModel = new $className();
229  $model = null;
230  }
231  } else {
232  $staticModel = $model;
233  }
234 
235  return array(
236  'model' => $model,
237  'staticModel' => $staticModel,
238  'attribute' => $attribute,
239  'isMongo' => $isMongo
240  );
241  }
242 }