00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 class TranslateBehavior extends ModelBehavior {
00038
00039
00040
00041 var $runtime = array();
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 function setup(&$model, $config = array()) {
00056 $db =& ConnectionManager::getDataSource($model->useDbConfig);
00057 if (!$db->connected) {
00058 trigger_error('Datasource '.$model->useDbConfig.' for TranslateBehavior of model '.$model->alias.' is not connected', E_USER_ERROR);
00059 return false;
00060 }
00061
00062 $this->settings[$model->alias] = array();
00063 $this->runtime[$model->alias] = array('fields' => array());
00064 $this->translateModel($model);
00065 return $this->bindTranslation($model, $config, false);
00066 }
00067
00068
00069
00070 function cleanup(&$model) {
00071 $this->unbindTranslation($model);
00072 unset($this->settings[$model->alias]);
00073 unset($this->runtime[$model->alias]);
00074 }
00075
00076
00077
00078 function beforeFind(&$model, $query) {
00079 $locale = $this->_getLocale($model);
00080 if (empty($locale)) {
00081 return $query;
00082 }
00083 $db =& ConnectionManager::getDataSource($model->useDbConfig);
00084 $tablePrefix = $db->config['prefix'];
00085 $RuntimeModel =& $this->translateModel($model);
00086
00087 if (is_string($query['fields']) && 'COUNT(*) AS '.$db->name('count') == $query['fields']) {
00088 $query['fields'] = 'COUNT(DISTINCT('.$db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count';
00089 $query['joins'][] = array(
00090 'type' => 'INNER',
00091 'alias' => $RuntimeModel->alias,
00092 'table' => $db->name($tablePrefix . $RuntimeModel->useTable),
00093 'conditions' => array(
00094 $model->alias.'.id' => $db->identifier($RuntimeModel->alias.'.foreign_key'),
00095 $RuntimeModel->alias.'.model' => $model->name,
00096 $RuntimeModel->alias.'.locale' => $locale
00097 )
00098 );
00099 return $query;
00100 }
00101 $autoFields = false;
00102
00103 if (empty($query['fields'])) {
00104 $query['fields'] = array($model->alias.'.*');
00105
00106 foreach (array('hasOne', 'belongsTo') as $type) {
00107 foreach ($model->{$type} as $key => $value) {
00108
00109 if (empty($value['fields'])) {
00110 $query['fields'][] = $key.'.*';
00111 } else {
00112 foreach ($value['fields'] as $field) {
00113 $query['fields'][] = $key.'.'.$field;
00114 }
00115 }
00116 }
00117 }
00118 $autoFields = true;
00119 }
00120 $fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
00121 $addFields = array();
00122 if (is_array($query['fields'])) {
00123 foreach ($fields as $key => $value) {
00124 $field = ife(is_numeric($key), $value, $key);
00125
00126 if (in_array($model->alias.'.*', $query['fields']) || $autoFields || in_array($model->alias.'.'.$field, $query['fields']) || in_array($field, $query['fields'])) {
00127 $addFields[] = $field;
00128 }
00129 }
00130 }
00131
00132 if ($addFields) {
00133 foreach ($addFields as $field) {
00134 foreach (array($field, $model->alias.'.'.$field) as $_field) {
00135 $key = array_search($_field, $query['fields']);
00136
00137 if ($key !== false) {
00138 unset($query['fields'][$key]);
00139 }
00140 }
00141
00142 if (is_array($locale)) {
00143 foreach ($locale as $_locale) {
00144 $query['fields'][] = 'I18n__'.$field.'__'.$_locale.'.content';
00145 $query['joins'][] = array(
00146 'type' => 'LEFT',
00147 'alias' => 'I18n__'.$field.'__'.$_locale,
00148 'table' => $db->name($tablePrefix . $RuntimeModel->useTable),
00149 'conditions' => array(
00150 $model->alias.'.id' => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"),
00151 'I18n__'.$field.'__'.$_locale.'.model' => $model->name,
00152 'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $field,
00153 'I18n__'.$field.'__'.$_locale.'.locale' => $_locale
00154 )
00155 );
00156 }
00157 } else {
00158 $query['fields'][] = 'I18n__'.$field.'.content';
00159 $query['joins'][] = array(
00160 'type' => 'LEFT',
00161 'alias' => 'I18n__'.$field,
00162 'table' => $db->name($tablePrefix . $RuntimeModel->useTable),
00163 'conditions' => array(
00164 $model->alias.'.id' => $db->identifier("I18n__{$field}.foreign_key"),
00165 'I18n__'.$field.'.model' => $model->name,
00166 'I18n__'.$field.'.'.$RuntimeModel->displayField => $field
00167 )
00168 );
00169
00170 if (is_string($query['conditions'])) {
00171 $query['conditions'] = $db->conditions($query['conditions'], true, false, $model) . ' AND '.$db->name('I18n__'.$field.'.locale').' = \''.$locale.'\'';
00172 } else {
00173 $query['conditions'][$db->name("I18n__{$field}.locale")] = $locale;
00174 }
00175 }
00176 }
00177 }
00178 if (is_array($query['fields'])) {
00179 $query['fields'] = array_merge($query['fields']);
00180 }
00181 $this->runtime[$model->alias]['beforeFind'] = $addFields;
00182 return $query;
00183 }
00184
00185
00186
00187 function afterFind(&$model, $results, $primary) {
00188 $this->runtime[$model->alias]['fields'] = array();
00189 $locale = $this->_getLocale($model);
00190
00191 if (empty($locale) || empty($results) || empty($this->runtime[$model->alias]['beforeFind'])) {
00192 return $results;
00193 }
00194 $beforeFind = $this->runtime[$model->alias]['beforeFind'];
00195
00196 foreach ($results as $key => $row) {
00197 $results[$key][$model->alias]['locale'] = ife(is_array($locale), @$locale[0], $locale);
00198
00199 foreach ($beforeFind as $field) {
00200 if (is_array($locale)) {
00201 foreach ($locale as $_locale) {
00202 if (!isset($results[$key][$model->alias][$field]) && !empty($results[$key]['I18n__'.$field.'__'.$_locale]['content'])) {
00203 $results[$key][$model->alias][$field] = $results[$key]['I18n__'.$field.'__'.$_locale]['content'];
00204 }
00205 unset($results[$key]['I18n__'.$field.'__'.$_locale]);
00206 }
00207
00208 if (!isset($results[$key][$model->alias][$field])) {
00209 $results[$key][$model->alias][$field] = '';
00210 }
00211 } else {
00212 $value = ife(empty($results[$key]['I18n__'.$field]['content']), '', $results[$key]['I18n__'.$field]['content']);
00213 $results[$key][$model->alias][$field] = $value;
00214 unset($results[$key]['I18n__'.$field]);
00215 }
00216 }
00217 }
00218 return $results;
00219 }
00220
00221
00222
00223 function beforeValidate(&$model) {
00224 $locale = $this->_getLocale($model);
00225 if (empty($locale)) {
00226 return true;
00227 }
00228 $fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
00229 $tempData = array();
00230
00231 foreach ($fields as $key => $value) {
00232 $field = ife(is_numeric($key), $value, $key);
00233
00234 if (isset($model->data[$model->alias][$field])) {
00235 $tempData[$field] = $model->data[$model->alias][$field];
00236 if (is_array($model->data[$model->alias][$field])) {
00237 if (is_string($locale) && !empty($model->data[$model->alias][$field][$locale])) {
00238 $model->data[$model->alias][$field] = $model->data[$model->alias][$field][$locale];
00239 } else {
00240 $values = array_values($model->data[$model->alias][$field]);
00241 $model->data[$model->alias][$field] = $values[0];
00242 }
00243 }
00244 }
00245 }
00246 $this->runtime[$model->alias]['beforeSave'] = $tempData;
00247 return true;
00248 }
00249
00250
00251
00252 function afterSave(&$model, $created) {
00253 if (!isset($this->runtime[$model->alias]['beforeSave'])) {
00254 return true;
00255 }
00256 $locale = $this->_getLocale($model);
00257 $tempData = $this->runtime[$model->alias]['beforeSave'];
00258 unset($this->runtime[$model->alias]['beforeSave']);
00259 $conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
00260 $RuntimeModel =& $this->translateModel($model);
00261
00262 foreach ($tempData as $field => $value) {
00263 unset($conditions['content']);
00264 $conditions['field'] = $field;
00265 if (is_array($value)) {
00266 $conditions['locale'] = array_keys($value);
00267 } else {
00268 $conditions['locale'] = $locale;
00269 if (is_array($locale)) {
00270 $value = array($locale[0] => $value);
00271 } else {
00272 $value = array($locale => $value);
00273 }
00274 }
00275 $translations = $RuntimeModel->find('list', array('conditions' => $conditions, 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id')));
00276 foreach ($value as $_locale => $_value) {
00277 $RuntimeModel->create();
00278 $conditions['locale'] = $_locale;
00279 $conditions['content'] = $_value;
00280 if (array_key_exists($_locale, $translations)) {
00281 $RuntimeModel->save(array($RuntimeModel->alias => array_merge($conditions, array('id' => $translations[$_locale]))));
00282 } else {
00283 $RuntimeModel->save(array($RuntimeModel->alias => $conditions));
00284 }
00285 }
00286 }
00287 }
00288
00289
00290
00291 function afterDelete(&$model) {
00292 $RuntimeModel =& $this->translateModel($model);
00293 $conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
00294 $RuntimeModel->deleteAll($conditions);
00295 }
00296
00297
00298
00299
00300
00301 function _getLocale(&$model) {
00302 if (!isset($model->locale) || is_null($model->locale)) {
00303 if (!class_exists('I18n')) {
00304 App::import('Core', 'i18n');
00305 }
00306 $I18n =& I18n::getInstance();
00307 $model->locale = $I18n->l10n->locale;
00308 }
00309 return $model->locale;
00310 }
00311
00312
00313
00314
00315
00316 function &translateModel(&$model) {
00317 if (!isset($this->runtime[$model->alias]['model'])) {
00318 if (!isset($model->translateModel) || empty($model->translateModel)) {
00319 $className = 'I18nModel';
00320 } else {
00321 $className = $model->translateModel;
00322 }
00323
00324 if (PHP5) {
00325 $this->runtime[$model->alias]['model'] = ClassRegistry::init($className, 'Model');
00326 } else {
00327 $this->runtime[$model->alias]['model'] =& ClassRegistry::init($className, 'Model');
00328 }
00329 }
00330 $useTable = 'i18n';
00331
00332 if (!empty($model->translateTable)) {
00333 $useTable = $model->translateTable;
00334 }
00335 if ($useTable !== $this->runtime[$model->alias]['model']->useTable) {
00336 $this->runtime[$model->alias]['model']->setSource($model->translateTable);
00337 }
00338 return $this->runtime[$model->alias]['model'];
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349 function bindTranslation(&$model, $fields, $reset = true) {
00350 if (is_string($fields)) {
00351 $fields = array($fields);
00352 }
00353 $associations = array();
00354 $RuntimeModel =& $this->translateModel($model);
00355 $default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key');
00356
00357 foreach ($fields as $key => $value) {
00358 if (is_numeric($key)) {
00359 $field = $value;
00360 $association = null;
00361 } else {
00362 $field = $key;
00363 $association = $value;
00364 }
00365
00366 if (array_key_exists($field, $this->settings[$model->alias])) {
00367 unset($this->settings[$model->alias][$field]);
00368
00369 } elseif (in_array($field, $this->settings[$model->alias])) {
00370 $this->settings[$model->alias] = array_merge(array_diff_assoc($this->settings[$model->alias], array($field)));
00371 }
00372
00373 if (array_key_exists($field, $this->runtime[$model->alias]['fields'])) {
00374 unset($this->runtime[$model->alias]['fields'][$field]);
00375
00376 } elseif (in_array($field, $this->runtime[$model->alias]['fields'])) {
00377 $this->runtime[$model->alias]['fields'] = array_merge(array_diff_assoc($this->runtime[$model->alias]['fields'], array($field)));
00378 }
00379
00380 if (is_null($association)) {
00381 if ($reset) {
00382 $this->runtime[$model->alias]['fields'][] = $field;
00383 } else {
00384 $this->settings[$model->alias][] = $field;
00385 }
00386 } else {
00387
00388 if ($reset) {
00389 $this->runtime[$model->alias]['fields'][$field] = $association;
00390 } else {
00391 $this->settings[$model->alias][$field] = $association;
00392 }
00393
00394 foreach (array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany') as $type) {
00395 if (isset($model->{$type}[$association]) || isset($model->__backAssociation[$type][$association])) {
00396 trigger_error('Association '.$association.' is already binded to model '.$model->alias, E_USER_ERROR);
00397 return false;
00398 }
00399 }
00400 $associations[$association] = array_merge($default, array('conditions' => array(
00401 'model' => $model->alias,
00402 $RuntimeModel->displayField => $field
00403 )));
00404 }
00405 }
00406
00407 if (!empty($associations)) {
00408 $model->bindModel(array('hasMany' => $associations), $reset);
00409 }
00410 return true;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420 function unbindTranslation(&$model, $fields = null) {
00421 if (empty($fields)) {
00422 return $this->unbindTranslation($model, $this->settings[$model->alias]);
00423 }
00424
00425 if (is_string($fields)) {
00426 $fields = array($fields);
00427 }
00428 $RuntimeModel =& $this->translateModel($model);
00429 $default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key');
00430 $associations = array();
00431
00432 foreach ($fields as $key => $value) {
00433 if (is_numeric($key)) {
00434 $field = $value;
00435 $association = null;
00436 } else {
00437 $field = $key;
00438 $association = $value;
00439 }
00440
00441 if (array_key_exists($field, $this->settings[$model->alias])) {
00442 unset($this->settings[$model->alias][$field]);
00443
00444 } elseif (in_array($field, $this->settings[$model->alias])) {
00445 $this->settings[$model->alias] = array_merge(array_diff_assoc($this->settings[$model->alias], array($field)));
00446 }
00447
00448 if (array_key_exists($field, $this->runtime[$model->alias]['fields'])) {
00449 unset($this->runtime[$model->alias]['fields'][$field]);
00450
00451 } elseif (in_array($field, $this->runtime[$model->alias]['fields'])) {
00452 $this->runtime[$model->alias]['fields'] = array_merge(array_diff_assoc($this->runtime[$model->alias]['fields'], array($field)));
00453 }
00454
00455 if (!is_null($association) && (isset($model->hasMany[$association]) || isset($model->__backAssociation['hasMany'][$association]))) {
00456 $associations[] = $association;
00457 }
00458 }
00459
00460 if (!empty($associations)) {
00461 $model->unbindModel(array('hasMany' => $associations), false);
00462 }
00463 return true;
00464 }
00465 }
00466 if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
00467
00468
00469
00470
00471 class I18nModel extends AppModel {
00472 var $name = 'I18nModel';
00473 var $useTable = 'i18n';
00474 var $displayField = 'field';
00475 }
00476 }
00477 ?>