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