mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Merge branch '2.0' into 2.1
Conflicts: lib/Cake/Model/BehaviorCollection.php lib/Cake/basics.php
This commit is contained in:
commit
0e56d742b8
14 changed files with 206 additions and 105 deletions
|
@ -333,7 +333,7 @@ class PaginatorComponent extends Component {
|
|||
$options['order'] = array($options['sort'] => $direction);
|
||||
}
|
||||
|
||||
if (!empty($whitelist)) {
|
||||
if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
|
||||
$field = key($options['order']);
|
||||
if (!in_array($field, $whitelist)) {
|
||||
$options['order'] = null;
|
||||
|
|
|
@ -312,7 +312,7 @@ class Configure {
|
|||
$keys = array_keys($values);
|
||||
foreach ($keys as $key) {
|
||||
if (($c = self::read($key)) && is_array($values[$key]) && is_array($c)) {
|
||||
$values[$key] = array_merge_recursive($c, $values[$key]);
|
||||
$values[$key] = Set::merge($c, $values[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,20 @@ class TranslateBehavior extends ModelBehavior {
|
|||
*/
|
||||
public $runtime = array();
|
||||
|
||||
/**
|
||||
* Stores the joinTable object for generating joins.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
var $_joinTable;
|
||||
|
||||
/**
|
||||
* Stores the runtime model for generating joins.
|
||||
*
|
||||
* @var Model
|
||||
*/
|
||||
var $_runtimeModel;
|
||||
|
||||
/**
|
||||
* Callback
|
||||
*
|
||||
|
@ -94,6 +108,7 @@ class TranslateBehavior extends ModelBehavior {
|
|||
}
|
||||
$db = $model->getDataSource();
|
||||
$RuntimeModel = $this->translateModel($model);
|
||||
|
||||
if (!empty($RuntimeModel->tablePrefix)) {
|
||||
$tablePrefix = $RuntimeModel->tablePrefix;
|
||||
} else {
|
||||
|
@ -104,8 +119,11 @@ class TranslateBehavior extends ModelBehavior {
|
|||
$joinTable->table = $RuntimeModel->table;
|
||||
$joinTable->schemaName = $RuntimeModel->getDataSource()->getSchemaName();
|
||||
|
||||
$this->_joinTable = $joinTable;
|
||||
$this->_runtimeModel = $RuntimeModel;
|
||||
|
||||
if (is_string($query['fields']) && 'COUNT(*) AS ' . $db->name('count') == $query['fields']) {
|
||||
$query['fields'] = 'COUNT(DISTINCT(' . $db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count';
|
||||
$query['fields'] = 'COUNT(DISTINCT('.$db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count';
|
||||
$query['joins'][] = array(
|
||||
'type' => 'INNER',
|
||||
'alias' => $RuntimeModel->alias,
|
||||
|
@ -116,6 +134,11 @@ class TranslateBehavior extends ModelBehavior {
|
|||
$RuntimeModel->alias.'.locale' => $locale
|
||||
)
|
||||
);
|
||||
$conditionFields = $this->_checkConditions($model, $query);
|
||||
foreach ($conditionFields as $field) {
|
||||
$query = $this->_addJoin($model, $query, $field, $field, $locale);
|
||||
}
|
||||
unset($this->_joinTable, $this->_runtimeModel);
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -145,45 +168,93 @@ class TranslateBehavior extends ModelBehavior {
|
|||
unset($query['fields'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($locale)) {
|
||||
foreach ($locale as $_locale) {
|
||||
$model->virtualFields['i18n_' . $field . '_' . $_locale] = 'I18n__' . $field . '__' . $_locale . '.content';
|
||||
if (!empty($query['fields'])) {
|
||||
$query['fields'][] = 'i18n_' . $field . '_' . $_locale;
|
||||
}
|
||||
$query['joins'][] = array(
|
||||
'type' => 'LEFT',
|
||||
'alias' => 'I18n__' . $field . '__' . $_locale,
|
||||
'table' => $joinTable,
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"),
|
||||
'I18n__' . $field . '__' . $_locale . '.model' => $model->name,
|
||||
'I18n__' . $field . '__' . $_locale . '.' . $RuntimeModel->displayField => $aliasField,
|
||||
'I18n__' . $field . '__' . $_locale . '.locale' => $_locale
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$model->virtualFields['i18n_' . $field] = 'I18n__' . $field . '.content';
|
||||
if (!empty($query['fields'])) {
|
||||
$query['fields'][] = 'i18n_' . $field;
|
||||
}
|
||||
$query['joins'][] = array(
|
||||
'type' => 'INNER',
|
||||
'alias' => 'I18n__' . $field,
|
||||
'table' => $joinTable,
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"),
|
||||
'I18n__' . $field . '.model' => $model->name,
|
||||
'I18n__' . $field . '.' . $RuntimeModel->displayField => $aliasField,
|
||||
'I18n__' . $field . '.locale' => $locale
|
||||
)
|
||||
);
|
||||
}
|
||||
$query = $this->_addJoin($model, $query, $field, $aliasField, $locale);
|
||||
}
|
||||
}
|
||||
$this->runtime[$model->alias]['beforeFind'] = $addFields;
|
||||
unset($this->_joinTable, $this->_runtimeModel);
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a query's conditions for translated fields.
|
||||
* Return an array of translated fields found in the conditions.
|
||||
*
|
||||
* @param Model $model The model being read.
|
||||
* @param array $query The query array.
|
||||
* @return array The list of translated fields that are in the conditions.
|
||||
*/
|
||||
protected function _checkConditions(Model $model, $query) {
|
||||
$conditionFields = array();
|
||||
if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions'])) ) {
|
||||
return $conditionFields;
|
||||
}
|
||||
foreach ($query['conditions'] as $col => $val) {
|
||||
foreach ($this->settings[$model->alias] as $field => $assoc) {
|
||||
if (is_numeric($field)) {
|
||||
$field = $assoc;
|
||||
}
|
||||
if (strpos($col, $field) !== false) {
|
||||
$conditionFields[] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $conditionFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a join for translated fields and possibly a field.
|
||||
*
|
||||
* @param Model $model The model being worked on.
|
||||
* @param object $joinTable The jointable object.
|
||||
* @param array $query The query array to append a join to.
|
||||
* @param string $field The field name being joined.
|
||||
* @param string $aliasField The aliased field name being joined.
|
||||
* @param mixed $locale The locale(s) having joins added.
|
||||
* @param boolean $addField Whether or not to add a field.
|
||||
* @return array The modfied query
|
||||
*/
|
||||
protected function _addJoin(Model $model, $query, $field, $aliasField, $locale, $addField = false) {
|
||||
$db = ConnectionManager::getDataSource($model->useDbConfig);
|
||||
|
||||
$RuntimeModel = $this->_runtimeModel;
|
||||
$joinTable = $this->_joinTable;
|
||||
|
||||
if (is_array($locale)) {
|
||||
foreach ($locale as $_locale) {
|
||||
$model->virtualFields['i18n_' . $field . '_' . $_locale] = 'I18n__' . $field . '__' . $_locale . '.content';
|
||||
if (!empty($query['fields']) && is_array($query['fields'])) {
|
||||
$query['fields'][] = 'i18n_'.$field.'_'.$_locale;
|
||||
}
|
||||
$query['joins'][] = array(
|
||||
'type' => 'LEFT',
|
||||
'alias' => 'I18n__'.$field.'__'.$_locale,
|
||||
'table' => $joinTable,
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"),
|
||||
'I18n__'.$field.'__'.$_locale.'.model' => $model->name,
|
||||
'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $aliasField,
|
||||
'I18n__'.$field.'__'.$_locale.'.locale' => $_locale
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$model->virtualFields['i18n_' . $field] = 'I18n__' . $field . '.content';
|
||||
if (!empty($query['fields']) && is_array($query['fields'])) {
|
||||
$query['fields'][] = 'i18n_'.$field;
|
||||
}
|
||||
$query['joins'][] = array(
|
||||
'type' => 'INNER',
|
||||
'alias' => 'I18n__'.$field,
|
||||
'table' => $joinTable,
|
||||
'conditions' => array(
|
||||
$model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"),
|
||||
'I18n__'.$field.'.model' => $model->name,
|
||||
'I18n__'.$field.'.'.$RuntimeModel->displayField => $aliasField,
|
||||
'I18n__'.$field.'.locale' => $locale
|
||||
)
|
||||
);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,9 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener {
|
|||
$alias = $behavior;
|
||||
$behavior = $config['className'];
|
||||
}
|
||||
$configDisabled = isset($config['enabled']) && $config['enabled'] === false;
|
||||
unset($config['enabled'], $config['className']);
|
||||
|
||||
list($plugin, $name) = pluginSplit($behavior, true);
|
||||
if (!isset($alias)) {
|
||||
$alias = $name;
|
||||
|
@ -166,8 +169,7 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
$enable = isset($config['enabled']) ? $config['enabled'] : true;
|
||||
if ($enable) {
|
||||
if (!in_array($alias, $this->_enabled) && !$configDisabled) {
|
||||
$this->enable($alias);
|
||||
} else {
|
||||
$this->disable($alias);
|
||||
|
|
|
@ -182,7 +182,7 @@ class Sqlserver extends DboSource {
|
|||
} else {
|
||||
$tables = array();
|
||||
|
||||
while ($line = $result->fetch()) {
|
||||
while ($line = $result->fetch(PDO::FETCH_NUM)) {
|
||||
$tables[] = $line[0];
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ class Sqlserver extends DboSource {
|
|||
throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $table));
|
||||
}
|
||||
|
||||
foreach ($cols as $column) {
|
||||
while ($column = $cols->fetch(PDO::FETCH_OBJ)) {
|
||||
$field = $column->Field;
|
||||
$fields[$field] = array(
|
||||
'type' => $this->column($column),
|
||||
|
@ -645,14 +645,7 @@ class Sqlserver extends DboSource {
|
|||
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON');
|
||||
}
|
||||
|
||||
$table = $this->fullTableName($table);
|
||||
$fields = implode(', ', array_map(array(&$this, 'name'), $fields));
|
||||
$this->begin();
|
||||
foreach ($values as $value) {
|
||||
$holder = implode(', ', array_map(array(&$this, 'value'), $value));
|
||||
$this->_execute("INSERT INTO {$table} ({$fields}) VALUES ({$holder})");
|
||||
}
|
||||
$this->commit();
|
||||
parent::insertMulti($table, $fields, $values);
|
||||
|
||||
if ($hasPrimaryKey) {
|
||||
$this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF');
|
||||
|
@ -717,9 +710,6 @@ class Sqlserver extends DboSource {
|
|||
* @return string
|
||||
*/
|
||||
protected function _getPrimaryKey($model) {
|
||||
if (!is_object($model)) {
|
||||
$model = new Model(false, $model);
|
||||
}
|
||||
$schema = $this->describe($model);
|
||||
foreach ($schema as $field => $props) {
|
||||
if (isset($props['key']) && $props['key'] == 'primary') {
|
||||
|
|
|
@ -776,6 +776,26 @@ class PaginatorComponentTest extends CakeTestCase {
|
|||
$this->assertEquals($expected, $result['order']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that no sort doesn't trigger an error.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidateSortNoSort() {
|
||||
$model = $this->getMock('Model');
|
||||
$model->alias = 'model';
|
||||
$model->expects($this->any())->method('hasField')->will($this->returnValue(true));
|
||||
|
||||
$options = array('direction' => 'asc');
|
||||
$result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
|
||||
$this->assertFalse(isset($result['order']));
|
||||
|
||||
$options = array('order' => 'invalid desc');
|
||||
$result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
|
||||
|
||||
$this->assertEquals($options['order'], $result['order']);
|
||||
}
|
||||
|
||||
/**
|
||||
* test that maxLimit is respected
|
||||
*
|
||||
|
|
|
@ -224,6 +224,8 @@ class ConfigureTest extends CakeTestCase {
|
|||
$this->assertEquals('value2', Configure::read('Read'));
|
||||
$this->assertEquals('buried2', Configure::read('Deep.Second.SecondDeepest'));
|
||||
$this->assertEquals('buried', Configure::read('Deep.Deeper.Deepest'));
|
||||
$this->assertEquals('Overwrite', Configure::read('TestAcl.classname'));
|
||||
$this->assertEquals('one', Configure::read('TestAcl.custom'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,6 +58,24 @@ class TranslateBehaviorTest extends CakeTestCase {
|
|||
ClassRegistry::flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that count queries with conditions get the correct joins
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function testCountWithConditions() {
|
||||
$this->loadFixtures('Translate', 'TranslatedItem');
|
||||
|
||||
$Model =& new TranslatedItem();
|
||||
$Model->locale = 'eng';
|
||||
$result = $Model->find('count', array(
|
||||
'conditions' => array(
|
||||
'I18n__content.locale' => 'eng'
|
||||
)
|
||||
));
|
||||
$this->assertEqual(3, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* testTranslateModel method
|
||||
*
|
||||
|
|
|
@ -419,9 +419,22 @@ class BehaviorCollectionTest extends CakeTestCase {
|
|||
*/
|
||||
public $fixtures = array(
|
||||
'core.apple', 'core.sample', 'core.article', 'core.user', 'core.comment',
|
||||
'core.attachment', 'core.tag', 'core.articles_tag'
|
||||
'core.attachment', 'core.tag', 'core.articles_tag', 'core.translate'
|
||||
);
|
||||
|
||||
/**
|
||||
* Test load() with enabled => false
|
||||
*
|
||||
*/
|
||||
public function testLoadDisabled() {
|
||||
$Apple = new Apple();
|
||||
$this->assertSame($Apple->Behaviors->attached(), array());
|
||||
|
||||
$Apple->Behaviors->load('Translate', array('enabled' => false));
|
||||
$this->assertTrue($Apple->Behaviors->attached('Translate'));
|
||||
$this->assertFalse($Apple->Behaviors->enabled('Translate'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests loading aliased behaviors
|
||||
*/
|
||||
|
|
|
@ -111,7 +111,7 @@ class SqlserverTestDb extends Sqlserver {
|
|||
*
|
||||
* @package Cake.Test.Case.Model.Datasource.Database
|
||||
*/
|
||||
class SqlserverTestModel extends Model {
|
||||
class SqlserverTestModel extends CakeTestModel {
|
||||
|
||||
/**
|
||||
* name property
|
||||
|
@ -183,7 +183,7 @@ class SqlserverTestModel extends Model {
|
|||
*
|
||||
* @package Cake.Test.Case.Model.Datasource.Database
|
||||
*/
|
||||
class SqlserverClientTestModel extends Model {
|
||||
class SqlserverClientTestModel extends CakeTestModel {
|
||||
/**
|
||||
* name property
|
||||
*
|
||||
|
@ -224,6 +224,20 @@ class SqlserverTestResultIterator extends ArrayIterator {
|
|||
* @return void
|
||||
*/
|
||||
public function closeCursor() {}
|
||||
|
||||
/**
|
||||
* fetch method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fetch() {
|
||||
if (!$this->valid()) {
|
||||
return null;
|
||||
}
|
||||
$current = $this->current();
|
||||
$this->next();
|
||||
return $current;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -283,7 +297,7 @@ class SqlserverTest extends CakeTestCase {
|
|||
* @return void
|
||||
*/
|
||||
public function testQuoting() {
|
||||
$expected = "1.200000";
|
||||
$expected = "1.2";
|
||||
$result = $this->db->value(1.2, 'float');
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
|
@ -586,43 +600,6 @@ class SqlserverTest extends CakeTestCase {
|
|||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* testInsertMulti
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInsertMulti() {
|
||||
$this->db->describe = $this->model->schema();
|
||||
|
||||
$fields = array('id', 'name', 'login');
|
||||
$values = array(
|
||||
array(1, 'Larry', 'PhpNut'),
|
||||
array(2, 'Renan', 'renan.saddam'));
|
||||
$this->db->simulated = array();
|
||||
$this->db->insertMulti($this->model, $fields, $values);
|
||||
$result = $this->db->simulated;
|
||||
$expected = array(
|
||||
'SET IDENTITY_INSERT [sqlserver_test_models] ON',
|
||||
"INSERT INTO [sqlserver_test_models] ([id], [name], [login]) VALUES (1, N'Larry', N'PhpNut')",
|
||||
"INSERT INTO [sqlserver_test_models] ([id], [name], [login]) VALUES (2, N'Renan', N'renan.saddam')",
|
||||
'SET IDENTITY_INSERT [sqlserver_test_models] OFF'
|
||||
);
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$fields = array('name', 'login');
|
||||
$values = array(
|
||||
array('Larry', 'PhpNut'),
|
||||
array('Renan', 'renan.saddam'));
|
||||
$this->db->simulated = array();
|
||||
$this->db->insertMulti($this->model, $fields, $values);
|
||||
$result = $this->db->simulated;
|
||||
$expected = array(
|
||||
"INSERT INTO [sqlserver_test_models] ([name], [login]) VALUES (N'Larry', N'PhpNut')",
|
||||
"INSERT INTO [sqlserver_test_models] ([name], [login]) VALUES (N'Renan', N'renan.saddam')",
|
||||
);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL server < 11 doesn't have proper limit/offset support, test that our hack works.
|
||||
*
|
||||
|
|
|
@ -493,6 +493,9 @@ class DboSourceTest extends CakeTestCase {
|
|||
* @return void
|
||||
*/
|
||||
public function testValue() {
|
||||
if ($this->db instanceof Sqlserver) {
|
||||
$this->markTestSkipped('Cannot run this test with SqlServer');
|
||||
}
|
||||
$result = $this->db->value('{$__cakeForeignKey__$}');
|
||||
$this->assertEquals($result, '{$__cakeForeignKey__$}');
|
||||
|
||||
|
|
|
@ -208,11 +208,11 @@ class ModelIntegrationTest extends BaseModelTest {
|
|||
public function testDynamicBehaviorAttachment() {
|
||||
$this->loadFixtures('Apple', 'Sample', 'Author');
|
||||
$TestModel = new Apple();
|
||||
$this->assertEquals($TestModel->Behaviors->attached(), array());
|
||||
$this->assertEquals(array(), $TestModel->Behaviors->attached());
|
||||
|
||||
$TestModel->Behaviors->attach('Tree', array('left' => 'left_field', 'right' => 'right_field'));
|
||||
$this->assertTrue(is_object($TestModel->Behaviors->Tree));
|
||||
$this->assertEquals($TestModel->Behaviors->attached(), array('Tree'));
|
||||
$this->assertEquals(array('Tree'), $TestModel->Behaviors->attached());
|
||||
|
||||
$expected = array(
|
||||
'parent' => 'parent_id',
|
||||
|
@ -223,16 +223,14 @@ class ModelIntegrationTest extends BaseModelTest {
|
|||
'__parentChange' => false,
|
||||
'recursive' => -1
|
||||
);
|
||||
$this->assertEquals($expected, $TestModel->Behaviors->Tree->settings['Apple']);
|
||||
|
||||
$this->assertEquals($TestModel->Behaviors->Tree->settings['Apple'], $expected);
|
||||
|
||||
$expected['enabled'] = false;
|
||||
$TestModel->Behaviors->attach('Tree', array('enabled' => false));
|
||||
$this->assertEquals($TestModel->Behaviors->Tree->settings['Apple'], $expected);
|
||||
$this->assertEquals($TestModel->Behaviors->attached(), array('Tree'));
|
||||
$this->assertEquals($expected, $TestModel->Behaviors->Tree->settings['Apple']);
|
||||
$this->assertEquals(array('Tree'), $TestModel->Behaviors->attached());
|
||||
|
||||
$TestModel->Behaviors->detach('Tree');
|
||||
$this->assertEquals($TestModel->Behaviors->attached(), array());
|
||||
$this->assertEquals(array(), $TestModel->Behaviors->attached());
|
||||
$this->assertFalse(isset($TestModel->Behaviors->Tree));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,5 +5,8 @@ $config = array(
|
|||
'Deeper' => array(
|
||||
'Deepest' => 'buried'
|
||||
)
|
||||
),
|
||||
'TestAcl' => array(
|
||||
'classname' => 'Original'
|
||||
)
|
||||
);
|
||||
);
|
||||
|
|
|
@ -5,5 +5,9 @@ $config = array(
|
|||
'Second' => array(
|
||||
'SecondDeepest' => 'buried2'
|
||||
)
|
||||
),
|
||||
'TestAcl' => array(
|
||||
'classname' => 'Overwrite',
|
||||
'custom' => 'one'
|
||||
)
|
||||
);
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue