Sergey Makinen
7 years ago
47 changed files with 5444 additions and 434 deletions
@ -0,0 +1,22 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* CheckConstraint represents the metadata of a table `CHECK` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class CheckConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var string |
||||
*/ |
||||
public $expression; |
||||
} |
@ -0,0 +1,28 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* Constraint represents the metadata of a table constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class Constraint extends Object |
||||
{ |
||||
/** |
||||
* @var string[]|null list of column names the constraint belongs to. |
||||
*/ |
||||
public $columnNames; |
||||
/** |
||||
* @var string|null the constraint name. |
||||
*/ |
||||
public $name; |
||||
} |
@ -0,0 +1,216 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* ConstraintFinderTrait provides methos for getting a table constraint information. |
||||
* |
||||
* @property CheckConstraint[][] $schemaChecks Check constraints for all tables in the database. |
||||
* Each array element is an array of [[CheckConstraint]] or its child classes. This property is read-only. |
||||
* @property DefaultConstraint[] $schemaDefaultValues Default value constraints for all tables in the database. |
||||
* Each array element is an array of [[DefaultConstraint]] or its child classes. This property is read-only. |
||||
* @property ForeignKeyConstraint[][] $schemaForeignKeys Foreign keys for all tables in the database. Each |
||||
* array element is an array of [[ForeignKeyConstraint]] or its child classes. This property is read-only. |
||||
* @property IndexConstraint[][] $schemaIndexes Indexes for all tables in the database. Each array element is |
||||
* an array of [[IndexConstraint]] or its child classes. This property is read-only. |
||||
* @property Constraint[] $schemaPrimaryKeys Primary keys for all tables in the database. Each array element |
||||
* is an instance of [[Constraint]] or its child class. This property is read-only. |
||||
* @property IndexConstraint[][] $schemaUniques Unique constraints for all tables in the database. |
||||
* Each array element is an array of [[IndexConstraint]] or its child classes. This property is read-only. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
trait ConstraintFinderTrait |
||||
{ |
||||
/** |
||||
* Loads a primary key for the given table. |
||||
* @param string $tableName table name. |
||||
* @return Constraint|null primary key for the given table, `null` if the table has no primary key. |
||||
*/ |
||||
protected abstract function loadTablePrimaryKey($tableName); |
||||
|
||||
/** |
||||
* Loads all foreign keys for the given table. |
||||
* @param string $tableName table name. |
||||
* @return ForeignKeyConstraint[] foreign keys for the given table. |
||||
*/ |
||||
protected abstract function loadTableForeignKeys($tableName); |
||||
|
||||
/** |
||||
* Loads all indexes for the given table. |
||||
* @param string $tableName table name. |
||||
* @return IndexConstraint[] indexes for the given table. |
||||
*/ |
||||
protected abstract function loadTableIndexes($tableName); |
||||
|
||||
/** |
||||
* Loads all unique constraints for the given table. |
||||
* @param string $tableName table name. |
||||
* @return Constraint[] unique constraints for the given table. |
||||
*/ |
||||
protected abstract function loadTableUniques($tableName); |
||||
|
||||
/** |
||||
* Loads all check constraints for the given table. |
||||
* @param string $tableName table name. |
||||
* @return CheckConstraint[] check constraints for the given table. |
||||
*/ |
||||
protected abstract function loadTableChecks($tableName); |
||||
|
||||
/** |
||||
* Loads all default value constraints for the given table. |
||||
* @param string $tableName table name. |
||||
* @return DefaultConstraint[] default value constraints for the given table. |
||||
*/ |
||||
protected abstract function loadTableDefaultValues($tableName); |
||||
|
||||
/** |
||||
* Obtains the primary key for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return Constraint|null table primary key, `null` if the table has no primary key. |
||||
*/ |
||||
public function getTablePrimaryKey($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'primaryKey', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns primary keys for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is `false`, |
||||
* cached data may be returned if available. |
||||
* @return Constraint[] primary keys for all tables in the database. |
||||
* Each array element is an instance of [[Constraint]] or its child class. |
||||
*/ |
||||
public function getSchemaPrimaryKeys($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'primaryKey', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the foreign keys information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return ForeignKeyConstraint[] table foreign keys. |
||||
*/ |
||||
public function getTableForeignKeys($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'foreignKeys', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns foreign keys for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return ForeignKeyConstraint[][] foreign keys for all tables in the database. |
||||
* Each array element is an array of [[ForeignKeyConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaForeignKeys($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'foreignKeys', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the indexes information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return IndexConstraint[] table indexes. |
||||
*/ |
||||
public function getTableIndexes($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'indexes', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns indexes for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return IndexConstraint[][] indexes for all tables in the database. |
||||
* Each array element is an array of [[IndexConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaIndexes($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'indexes', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the unique constraints information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return Constraint[] table unique constraints. |
||||
*/ |
||||
public function getTableUniques($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'uniques', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns unique constraints for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return Constraint[][] unique constraints for all tables in the database. |
||||
* Each array element is an array of [[Constraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaUniques($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'uniques', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the check constraints information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return CheckConstraint[] table check constraints. |
||||
*/ |
||||
public function getTableChecks($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'checks', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns check constraints for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return CheckConstraint[][] check constraints for all tables in the database. |
||||
* Each array element is an array of [[CheckConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaChecks($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'checks', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the default value constraints information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return DefaultConstraint[] table default value constraints. |
||||
*/ |
||||
public function getTableDefaultValues($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'defaultValues', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns default value constraints for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return DefaultConstraint[] default value constraints for all tables in the database. |
||||
* Each array element is an array of [[DefaultConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaDefaultValues($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'defaultValues', $refresh); |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* DefaultConstraint represents the metadata of a table `DEFAULT` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class DefaultConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var mixed default value as returned by the DBMS. |
||||
*/ |
||||
public $value; |
||||
} |
@ -0,0 +1,38 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* ForeignKeyConstraint represents the metadata of a table `FOREIGN KEY` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class ForeignKeyConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var string|null referenced table schema name. |
||||
*/ |
||||
public $foreignSchemaName; |
||||
/** |
||||
* @var string referenced table name. |
||||
*/ |
||||
public $foreignTableName; |
||||
/** |
||||
* @var string[] list of referenced table column names. |
||||
*/ |
||||
public $foreignColumnNames; |
||||
/** |
||||
* @var string|null referential action if rows in a referenced table are to be updated. |
||||
*/ |
||||
public $onUpdate; |
||||
/** |
||||
* @var string|null referential action if rows in a referenced table are to be deleted. |
||||
*/ |
||||
public $onDelete; |
||||
} |
@ -0,0 +1,26 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* IndexConstraint represents the metadata of a table `INDEX` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class IndexConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var bool whether the index is unique. |
||||
*/ |
||||
public $isUnique; |
||||
/** |
||||
* @var bool whether the index was created for a primary key. |
||||
*/ |
||||
public $isPrimary; |
||||
} |
@ -0,0 +1,296 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* SqlToken represents SQL tokens produced by [[SqlTokenizer]] or its child classes. |
||||
* |
||||
* @property SqlToken[] $children Child tokens. |
||||
* @property bool $hasChildren Whether the token has children. This property is read-only. |
||||
* @property bool $isCollection Whether the token represents a collection of tokens. This property is |
||||
* read-only. |
||||
* @property string $sql SQL code. This property is read-only. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class SqlToken extends Object implements \ArrayAccess |
||||
{ |
||||
const TYPE_CODE = 0; |
||||
const TYPE_STATEMENT = 1; |
||||
const TYPE_TOKEN = 2; |
||||
const TYPE_PARENTHESIS = 3; |
||||
const TYPE_KEYWORD = 4; |
||||
const TYPE_OPERATOR = 5; |
||||
const TYPE_IDENTIFIER = 6; |
||||
const TYPE_STRING_LITERAL = 7; |
||||
|
||||
/** |
||||
* @var int token type. |
||||
* It has to be one of the following constants: |
||||
* - [[TYPE_CODE]] |
||||
* - [[TYPE_STATEMENT]] |
||||
* - [[TYPE_TOKEN]] |
||||
* - [[TYPE_PARENTHESIS]] |
||||
* - [[TYPE_KEYWORD]] |
||||
* - [[TYPE_OPERATOR]] |
||||
* - [[TYPE_IDENTIFIER]] |
||||
* - [[TYPE_STRING_LITERAL]] |
||||
*/ |
||||
public $type = self::TYPE_TOKEN; |
||||
/** |
||||
* @var string|null token content. |
||||
*/ |
||||
public $content; |
||||
/** |
||||
* @var int original SQL token start position. |
||||
*/ |
||||
public $startOffset; |
||||
/** |
||||
* @var int original SQL token end position. |
||||
*/ |
||||
public $endOffset; |
||||
/** |
||||
* @var SqlToken parent token. |
||||
*/ |
||||
public $parent; |
||||
|
||||
/** |
||||
* @var SqlToken[] |
||||
*/ |
||||
private $_children = []; |
||||
|
||||
|
||||
/** |
||||
* Returns the SQL code representing the token. |
||||
* @return string SQL code. |
||||
*/ |
||||
public function __toString() |
||||
{ |
||||
return $this->getSql(); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there is a child token at the specified offset. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `isset($token[$offset])`. |
||||
* @param int $offset child token offset. |
||||
* @return bool whether the token exists. |
||||
*/ |
||||
public function offsetExists($offset) |
||||
{ |
||||
return isset($this->_children[$this->calculateOffset($offset)]); |
||||
} |
||||
|
||||
/** |
||||
* Returns a child token at the specified offset. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `$child = $token[$offset];`. |
||||
* @param int $offset child token offset. |
||||
* @return SqlToken|null the child token at the specified offset, `null` if there's no token. |
||||
*/ |
||||
public function offsetGet($offset) |
||||
{ |
||||
$offset = $this->calculateOffset($offset); |
||||
return isset($this->_children[$offset]) ? $this->_children[$offset] : null; |
||||
} |
||||
|
||||
/** |
||||
* Adds a child token to the token. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `$token[$offset] = $child;`. |
||||
* @param int|null $offset child token offset. |
||||
* @param SqlToken $token token to be added. |
||||
*/ |
||||
public function offsetSet($offset, $token) |
||||
{ |
||||
$token->parent = $this; |
||||
if ($offset === null) { |
||||
$this->_children[] = $token; |
||||
} else { |
||||
$this->_children[$this->calculateOffset($offset)] = $token; |
||||
} |
||||
$this->updateCollectionOffsets(); |
||||
} |
||||
|
||||
/** |
||||
* Removes a child token at the specified offset. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `unset($token[$offset])`. |
||||
* @param int $offset child token offset. |
||||
*/ |
||||
public function offsetUnset($offset) |
||||
{ |
||||
$offset = $this->calculateOffset($offset); |
||||
if (isset($this->_children[$offset])) { |
||||
array_splice($this->_children, $offset, 1); |
||||
} |
||||
$this->updateCollectionOffsets(); |
||||
} |
||||
|
||||
/** |
||||
* Returns child tokens. |
||||
* @return SqlToken[] child tokens. |
||||
*/ |
||||
public function getChildren() |
||||
{ |
||||
return $this->_children; |
||||
} |
||||
|
||||
/** |
||||
* Sets a list of child tokens. |
||||
* @param SqlToken[] $children child tokens. |
||||
*/ |
||||
public function setChildren($children) |
||||
{ |
||||
$this->_children = []; |
||||
foreach ($children as $child) { |
||||
$child->parent = $this; |
||||
$this->_children[] = $child; |
||||
} |
||||
$this->updateCollectionOffsets(); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the token represents a collection of tokens. |
||||
* @return bool whether the token represents a collection of tokens. |
||||
*/ |
||||
public function getIsCollection() |
||||
{ |
||||
return in_array($this->type, [ |
||||
self::TYPE_CODE, |
||||
self::TYPE_STATEMENT, |
||||
self::TYPE_PARENTHESIS, |
||||
], true); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the token represents a collection of tokens and has non-zero number of children. |
||||
* @return bool whether the token has children. |
||||
*/ |
||||
public function getHasChildren() |
||||
{ |
||||
return $this->getIsCollection() && !empty($this->_children); |
||||
} |
||||
|
||||
/** |
||||
* Returns the SQL code representing the token. |
||||
* @return string SQL code. |
||||
*/ |
||||
public function getSql() |
||||
{ |
||||
$code = $this; |
||||
while ($code->parent !== null) { |
||||
$code = $code->parent; |
||||
} |
||||
return mb_substr($code->content, $this->startOffset, $this->endOffset - $this->startOffset, 'UTF-8'); |
||||
} |
||||
|
||||
/** |
||||
* @param string $pattern |
||||
* @param int $offset |
||||
* @param int|null $firstMatchIndex |
||||
* @param int|null $lastMatchIndex |
||||
* @return bool |
||||
*/ |
||||
public function matches($pattern, $offset = 0, &$firstMatchIndex = null, &$lastMatchIndex = null) |
||||
{ |
||||
$patternToken = (new \yii\db\sqlite\SqlTokenizer($pattern))->tokenize(); |
||||
if (!$patternToken->getHasChildren()) { |
||||
return false; |
||||
} |
||||
|
||||
$patternToken = $patternToken[0]; |
||||
return $this->tokensMatch($patternToken, $this, $offset, $firstMatchIndex, $lastMatchIndex); |
||||
} |
||||
|
||||
/** |
||||
* Tests the given token to match the specified pattern token. |
||||
* @param SqlToken $patternToken |
||||
* @param SqlToken $token |
||||
* @param int $offset |
||||
* @param int|null $firstMatchIndex |
||||
* @param int|null $lastMatchIndex |
||||
* @return bool |
||||
*/ |
||||
private function tokensMatch(SqlToken $patternToken, SqlToken $token, $offset = 0, &$firstMatchIndex = null, &$lastMatchIndex = null) |
||||
{ |
||||
if ( |
||||
$patternToken->getIsCollection() !== $token->getIsCollection() |
||||
|| (!$patternToken->getIsCollection() && $patternToken->content !== $token->content) |
||||
) { |
||||
return false; |
||||
} |
||||
|
||||
if ($patternToken->children === $token->children) { |
||||
$firstMatchIndex = $lastMatchIndex = $offset; |
||||
return true; |
||||
} |
||||
|
||||
$firstMatchIndex = $lastMatchIndex = null; |
||||
$wildcard = false; |
||||
for ($index = 0, $count = count($patternToken->children); $index < $count; $index++) { |
||||
if ($patternToken[$index]->content === 'any') { |
||||
$wildcard = true; |
||||
continue; |
||||
} |
||||
|
||||
for ($limit = $wildcard ? count($token->children) : $offset + 1; $offset < $limit; $offset++) { |
||||
if (!$wildcard && !isset($token[$offset])) { |
||||
break; |
||||
} |
||||
|
||||
if (!$this->tokensMatch($patternToken[$index],$token[$offset])) { |
||||
continue; |
||||
} |
||||
|
||||
if ($firstMatchIndex === null) { |
||||
$firstMatchIndex = $offset; |
||||
$lastMatchIndex = $offset; |
||||
} else { |
||||
$lastMatchIndex = $offset; |
||||
} |
||||
$wildcard = false; |
||||
$offset++; |
||||
continue 2; |
||||
} |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Returns an absolute offset in the children array. |
||||
* @param int $offset |
||||
* @return int |
||||
*/ |
||||
private function calculateOffset($offset) |
||||
{ |
||||
if ($offset >= 0) { |
||||
return $offset; |
||||
} |
||||
|
||||
return count($this->_children) + $offset; |
||||
} |
||||
|
||||
/** |
||||
* Updates token SQL code start and end offsets based on its children. |
||||
*/ |
||||
private function updateCollectionOffsets() |
||||
{ |
||||
if (!empty($this->_children)) { |
||||
$this->startOffset = reset($this->_children)->startOffset; |
||||
$this->endOffset = end($this->_children)->endOffset; |
||||
} |
||||
if ($this->parent !== null) { |
||||
$this->parent->updateCollectionOffsets(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,378 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
use yii\base\InvalidParamException; |
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* SqlTokenizer splits SQL query into individual SQL tokens. |
||||
* It's used to obtain an addition information from an SQL code. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
abstract class SqlTokenizer extends Object |
||||
{ |
||||
/** |
||||
* @var string SQL code. |
||||
*/ |
||||
public $sql; |
||||
|
||||
/** |
||||
* @var int SQL code string length. |
||||
*/ |
||||
protected $length; |
||||
/** |
||||
* @var int SQL code string current offset. |
||||
*/ |
||||
protected $offset; |
||||
|
||||
/** |
||||
* @var \SplStack |
||||
*/ |
||||
private $_tokenStack; |
||||
/** |
||||
* @var SqlToken |
||||
*/ |
||||
private $_currentToken; |
||||
/** |
||||
* @var string[] |
||||
*/ |
||||
private $_substrings; |
||||
/** |
||||
* @var string |
||||
*/ |
||||
private $_buffer = ''; |
||||
/** |
||||
* @var SqlToken |
||||
*/ |
||||
private $_token; |
||||
|
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string $sql SQL code to be tokenized. |
||||
* @param array $config name-value pairs that will be used to initialize the object properties |
||||
*/ |
||||
public function __construct($sql, $config = []) |
||||
{ |
||||
$this->sql = $sql; |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* Tokenizes and returns a code type token. |
||||
* @return SqlToken code type token. |
||||
*/ |
||||
public function tokenize() |
||||
{ |
||||
$this->length = mb_strlen($this->sql, 'UTF-8'); |
||||
$this->offset = 0; |
||||
$this->_substrings = []; |
||||
$this->_buffer = ''; |
||||
$this->_token = new SqlToken([ |
||||
'type' => SqlToken::TYPE_CODE, |
||||
'content' => $this->sql, |
||||
]); |
||||
$this->_tokenStack = new \SplStack(); |
||||
$this->_tokenStack->push($this->_token); |
||||
$this->_token[] = new SqlToken(['type' => SqlToken::TYPE_STATEMENT]); |
||||
$this->_tokenStack->push($this->_token[0]); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
while (!$this->isEof()) { |
||||
if ($this->isWhitespace($length) || $this->isComment($length)) { |
||||
$this->addTokenFromBuffer(); |
||||
$this->advance($length); |
||||
continue; |
||||
} |
||||
|
||||
if ($this->tokenizeOperator($length) || $this->tokenizeDelimitedString($length)) { |
||||
$this->advance($length); |
||||
continue; |
||||
} |
||||
|
||||
$this->_buffer .= $this->substring(1); |
||||
$this->advance(1); |
||||
} |
||||
$this->addTokenFromBuffer(); |
||||
if ($this->_token->getHasChildren() && !$this->_token[-1]->getHasChildren()) { |
||||
unset($this->_token[-1]); |
||||
} |
||||
return $this->_token; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there's a whitespace at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* @param int $length length of the matched string. |
||||
* @return bool whether there's a whitespace at the current offset. |
||||
*/ |
||||
protected abstract function isWhitespace(&$length); |
||||
|
||||
/** |
||||
* Returns whether there's a commentary at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* @param int $length length of the matched string. |
||||
* @return bool whether there's a commentary at the current offset. |
||||
*/ |
||||
protected abstract function isComment(&$length); |
||||
|
||||
/** |
||||
* Returns whether there's an operator at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* It may also set `$content` to a string that will be used as a token content. |
||||
* @param int $length length of the matched string. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether there's an operator at the current offset. |
||||
*/ |
||||
protected abstract function isOperator(&$length, &$content); |
||||
|
||||
/** |
||||
* Returns whether there's an identifier at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* It may also set `$content` to a string that will be used as a token content. |
||||
* @param int $length length of the matched string. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether there's an identifier at the current offset. |
||||
*/ |
||||
protected abstract function isIdentifier(&$length, &$content); |
||||
|
||||
/** |
||||
* Returns whether there's a string literal at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* It may also set `$content` to a string that will be used as a token content. |
||||
* @param int $length length of the matched string. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether there's a string literal at the current offset. |
||||
*/ |
||||
protected abstract function isStringLiteral(&$length, &$content); |
||||
|
||||
/** |
||||
* Returns whether the given string is a keyword. |
||||
* The method may set `$content` to a string that will be used as a token content. |
||||
* @param string $string string to be matched. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether the given string is a keyword. |
||||
*/ |
||||
protected abstract function isKeyword($string, &$content); |
||||
|
||||
/** |
||||
* Returns whether the longest common prefix equals to the SQL code of the same length at the current offset. |
||||
* @param string[] $with strings to be tested. |
||||
* The method **will** modify this parameter to speed up lookups. |
||||
* @param bool $caseSensitive whether to perform a case sensitive comparison. |
||||
* @param int|null $length length of the matched string. |
||||
* @param string|null $content matched string. |
||||
* @return bool whether a match is found. |
||||
*/ |
||||
protected function startsWithAnyLongest(array &$with, $caseSensitive, &$length = null, &$content = null) |
||||
{ |
||||
if (empty($with)) { |
||||
return false; |
||||
} |
||||
|
||||
if (!is_array(reset($with))) { |
||||
usort($with, function ($string1, $string2) { |
||||
return mb_strlen($string2, 'UTF-8') - mb_strlen($string1, 'UTF-8'); |
||||
}); |
||||
$map = []; |
||||
foreach ($with as $string) { |
||||
$map[mb_strlen($string, 'UTF-8')][$caseSensitive ? $string : mb_strtoupper($string, 'UTF-8')] = true; |
||||
} |
||||
$with = $map; |
||||
} |
||||
foreach ($with as $testLength => $testValues) { |
||||
$content = $this->substring($testLength, $caseSensitive); |
||||
if (isset($testValues[$content])) { |
||||
$length = $testLength; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Returns a string of the given length starting with the specified offset. |
||||
* @param int $length string length to be returned. |
||||
* @param bool $caseSensitive if it's `false`, the string will be uppercased. |
||||
* @param int|null $offset SQL code offset, defaults to current if `null` is passed. |
||||
* @return string result string, it may be empty if there's nothing to return. |
||||
*/ |
||||
protected function substring($length, $caseSensitive = true, $offset = null) |
||||
{ |
||||
if ($offset === null) { |
||||
$offset = $this->offset; |
||||
} |
||||
if ($offset + $length > $this->length) { |
||||
return ''; |
||||
} |
||||
|
||||
$cacheKey = $offset . ',' . $length; |
||||
if (!isset($this->_substrings[$cacheKey . ',1'])) { |
||||
$this->_substrings[$cacheKey . ',1'] = mb_substr($this->sql, $offset, $length, 'UTF-8'); |
||||
} |
||||
if (!$caseSensitive && !isset($this->_substrings[$cacheKey . ',0'])) { |
||||
$this->_substrings[$cacheKey . ',0'] = mb_strtoupper($this->_substrings[$cacheKey . ',1'], 'UTF-8'); |
||||
} |
||||
return $this->_substrings[$cacheKey . ',' . (int) $caseSensitive]; |
||||
} |
||||
|
||||
/** |
||||
* Returns an index after the given string in the SQL code starting with the specified offset. |
||||
* @param string $string string to be found. |
||||
* @param int|null $offset SQL code offset, defaults to current if `null` is passed. |
||||
* @return int index after the given string or end of string index. |
||||
*/ |
||||
protected function indexAfter($string, $offset = null) |
||||
{ |
||||
if ($offset === null) { |
||||
$offset = $this->offset; |
||||
} |
||||
if ($offset + mb_strlen($string, 'UTF-8') > $this->length) { |
||||
return $this->length; |
||||
} |
||||
|
||||
$afterIndexOf = mb_strpos($this->sql, $string, $offset, 'UTF-8'); |
||||
if ($afterIndexOf === false) { |
||||
$afterIndexOf = $this->length; |
||||
} else { |
||||
$afterIndexOf += mb_strlen($string, 'UTF-8'); |
||||
} |
||||
return $afterIndexOf; |
||||
} |
||||
|
||||
/** |
||||
* Determines whether there is a delimited string at the current offset and adds it to the token children. |
||||
* @param int $length |
||||
* @return bool |
||||
*/ |
||||
private function tokenizeDelimitedString(&$length) |
||||
{ |
||||
$isIdentifier = $this->isIdentifier($length, $content); |
||||
$isStringLiteral = !$isIdentifier && $this->isStringLiteral($length, $content); |
||||
if (!$isIdentifier && !$isStringLiteral) { |
||||
return false; |
||||
} |
||||
|
||||
$this->addTokenFromBuffer(); |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => $isIdentifier ? SqlToken::TYPE_IDENTIFIER : SqlToken::TYPE_STRING_LITERAL, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Determines whether there is an operator at the current offset and adds it to the token children. |
||||
* @param int $length |
||||
* @return bool |
||||
*/ |
||||
private function tokenizeOperator(&$length) |
||||
{ |
||||
if (!$this->isOperator($length, $content)) { |
||||
return false; |
||||
} |
||||
|
||||
$this->addTokenFromBuffer(); |
||||
switch ($this->substring($length)) { |
||||
case '(': |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
$this->_currentToken[] = new SqlToken(['type' => SqlToken::TYPE_PARENTHESIS]); |
||||
$this->_tokenStack->push($this->_currentToken[-1]); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
break; |
||||
case ')': |
||||
$this->_tokenStack->pop(); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => ')', |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
break; |
||||
case ';': |
||||
if (!$this->_currentToken->getHasChildren()) { |
||||
break; |
||||
} |
||||
|
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
$this->_tokenStack->pop(); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
$this->_currentToken[] = new SqlToken(['type' => SqlToken::TYPE_STATEMENT]); |
||||
$this->_tokenStack->push($this->_currentToken[-1]); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
break; |
||||
default: |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
break; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Determines a type of text in the buffer, tokenizes it and adds it to the token children. |
||||
*/ |
||||
private function addTokenFromBuffer() |
||||
{ |
||||
if ($this->_buffer === '') { |
||||
return; |
||||
} |
||||
|
||||
$isKeyword = $this->isKeyword($this->_buffer, $content); |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => $isKeyword ? SqlToken::TYPE_KEYWORD : SqlToken::TYPE_TOKEN, |
||||
'content' => is_string($content) ? $content : $this->_buffer, |
||||
'startOffset' => $this->offset - mb_strlen($this->_buffer, 'UTF-8'), |
||||
'endOffset' => $this->offset, |
||||
]); |
||||
$this->_buffer = ''; |
||||
} |
||||
|
||||
/** |
||||
* Adds the specified length to the current offset. |
||||
* @param int $length |
||||
* @throws InvalidParamException |
||||
*/ |
||||
private function advance($length) |
||||
{ |
||||
if ($length <= 0) { |
||||
throw new InvalidParamException('Length must be greater than 0.'); |
||||
} |
||||
|
||||
$this->offset += $length; |
||||
$this->_substrings = []; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the SQL code is completely traversed. |
||||
* @return bool |
||||
*/ |
||||
private function isEof() |
||||
{ |
||||
return $this->offset >= $this->length; |
||||
} |
||||
} |
@ -0,0 +1,288 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db\sqlite; |
||||
|
||||
/** |
||||
* SqlTokenizer splits SQLite query into individual SQL tokens. |
||||
* It's used to obtain a `CHECK` constraint information from a `CREATE TABLE` SQL code. |
||||
* |
||||
* @see http://www.sqlite.org/draft/tokenreq.html |
||||
* @see https://sqlite.org/lang.html |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class SqlTokenizer extends \yii\db\SqlTokenizer |
||||
{ |
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isWhitespace(&$length) |
||||
{ |
||||
static $whitespaces = [ |
||||
"\f" => true, |
||||
"\n" => true, |
||||
"\r" => true, |
||||
"\t" => true, |
||||
' ' => true, |
||||
]; |
||||
|
||||
$length = 1; |
||||
return isset($whitespaces[$this->substring($length)]); |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isComment(&$length) |
||||
{ |
||||
static $comments = [ |
||||
'--' => true, |
||||
'/*' => true, |
||||
]; |
||||
|
||||
$length = 2; |
||||
if (!isset($comments[$this->substring($length)])) { |
||||
return false; |
||||
} |
||||
|
||||
if ($this->substring($length) === '--') { |
||||
$length = $this->indexAfter("\n") - $this->offset; |
||||
} else { |
||||
$length = $this->indexAfter('*/') - $this->offset; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isOperator(&$length, &$content) |
||||
{ |
||||
static $operators = [ |
||||
'!=', |
||||
'%', |
||||
'&', |
||||
'(', |
||||
')', |
||||
'*', |
||||
'+', |
||||
',', |
||||
'-', |
||||
'.', |
||||
'/', |
||||
';', |
||||
'<', |
||||
'<<', |
||||
'<=', |
||||
'<>', |
||||
'=', |
||||
'==', |
||||
'>', |
||||
'>=', |
||||
'>>', |
||||
'|', |
||||
'||', |
||||
'~', |
||||
]; |
||||
|
||||
return $this->startsWithAnyLongest($operators, true, $length); |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isIdentifier(&$length, &$content) |
||||
{ |
||||
static $identifierDelimiters = [ |
||||
'"' => '"', |
||||
'[' => ']', |
||||
'`' => '`', |
||||
]; |
||||
|
||||
if (!isset($identifierDelimiters[$this->substring(1)])) { |
||||
return false; |
||||
} |
||||
|
||||
$delimiter = $identifierDelimiters[$this->substring(1)]; |
||||
$offset = $this->offset; |
||||
while (true) { |
||||
$offset = $this->indexAfter($delimiter, $offset + 1); |
||||
if ($delimiter === ']' || $this->substring(1, true, $offset) !== $delimiter) { |
||||
break; |
||||
} |
||||
} |
||||
$length = $offset - $this->offset; |
||||
$content = $this->substring($length - 2,true, $this->offset + 1); |
||||
if ($delimiter !== ']') { |
||||
$content = strtr($content, ["$delimiter$delimiter" => $delimiter]); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isStringLiteral(&$length, &$content) |
||||
{ |
||||
if ($this->substring(1) !== "'") { |
||||
return false; |
||||
} |
||||
|
||||
$offset = $this->offset; |
||||
while (true) { |
||||
$offset = $this->indexAfter("'", $offset + 1); |
||||
if ($this->substring(1, true, $offset) !== "'") { |
||||
break; |
||||
} |
||||
} |
||||
$length = $offset - $this->offset; |
||||
$content = strtr($this->substring($length - 2,true, $this->offset + 1), ["''" => "'"]); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isKeyword($string, &$content) |
||||
{ |
||||
static $keywords = [ |
||||
'ABORT' => true, |
||||
'ACTION' => true, |
||||
'ADD' => true, |
||||
'AFTER' => true, |
||||
'ALL' => true, |
||||
'ALTER' => true, |
||||
'ANALYZE' => true, |
||||
'AND' => true, |
||||
'AS' => true, |
||||
'ASC' => true, |
||||
'ATTACH' => true, |
||||
'AUTOINCREMENT' => true, |
||||
'BEFORE' => true, |
||||
'BEGIN' => true, |
||||
'BETWEEN' => true, |
||||
'BY' => true, |
||||
'CASCADE' => true, |
||||
'CASE' => true, |
||||
'CAST' => true, |
||||
'CHECK' => true, |
||||
'COLLATE' => true, |
||||
'COLUMN' => true, |
||||
'COMMIT' => true, |
||||
'CONFLICT' => true, |
||||
'CONSTRAINT' => true, |
||||
'CREATE' => true, |
||||
'CROSS' => true, |
||||
'CURRENT_DATE' => true, |
||||
'CURRENT_TIME' => true, |
||||
'CURRENT_TIMESTAMP' => true, |
||||
'DATABASE' => true, |
||||
'DEFAULT' => true, |
||||
'DEFERRABLE' => true, |
||||
'DEFERRED' => true, |
||||
'DELETE' => true, |
||||
'DESC' => true, |
||||
'DETACH' => true, |
||||
'DISTINCT' => true, |
||||
'DROP' => true, |
||||
'EACH' => true, |
||||
'ELSE' => true, |
||||
'END' => true, |
||||
'ESCAPE' => true, |
||||
'EXCEPT' => true, |
||||
'EXCLUSIVE' => true, |
||||
'EXISTS' => true, |
||||
'EXPLAIN' => true, |
||||
'FAIL' => true, |
||||
'FOR' => true, |
||||
'FOREIGN' => true, |
||||
'FROM' => true, |
||||
'FULL' => true, |
||||
'GLOB' => true, |
||||
'GROUP' => true, |
||||
'HAVING' => true, |
||||
'IF' => true, |
||||
'IGNORE' => true, |
||||
'IMMEDIATE' => true, |
||||
'IN' => true, |
||||
'INDEX' => true, |
||||
'INDEXED' => true, |
||||
'INITIALLY' => true, |
||||
'INNER' => true, |
||||
'INSERT' => true, |
||||
'INSTEAD' => true, |
||||
'INTERSECT' => true, |
||||
'INTO' => true, |
||||
'IS' => true, |
||||
'ISNULL' => true, |
||||
'JOIN' => true, |
||||
'KEY' => true, |
||||
'LEFT' => true, |
||||
'LIKE' => true, |
||||
'LIMIT' => true, |
||||
'MATCH' => true, |
||||
'NATURAL' => true, |
||||
'NO' => true, |
||||
'NOT' => true, |
||||
'NOTNULL' => true, |
||||
'NULL' => true, |
||||
'OF' => true, |
||||
'OFFSET' => true, |
||||
'ON' => true, |
||||
'OR' => true, |
||||
'ORDER' => true, |
||||
'OUTER' => true, |
||||
'PLAN' => true, |
||||
'PRAGMA' => true, |
||||
'PRIMARY' => true, |
||||
'QUERY' => true, |
||||
'RAISE' => true, |
||||
'RECURSIVE' => true, |
||||
'REFERENCES' => true, |
||||
'REGEXP' => true, |
||||
'REINDEX' => true, |
||||
'RELEASE' => true, |
||||
'RENAME' => true, |
||||
'REPLACE' => true, |
||||
'RESTRICT' => true, |
||||
'RIGHT' => true, |
||||
'ROLLBACK' => true, |
||||
'ROW' => true, |
||||
'SAVEPOINT' => true, |
||||
'SELECT' => true, |
||||
'SET' => true, |
||||
'TABLE' => true, |
||||
'TEMP' => true, |
||||
'TEMPORARY' => true, |
||||
'THEN' => true, |
||||
'TO' => true, |
||||
'TRANSACTION' => true, |
||||
'TRIGGER' => true, |
||||
'UNION' => true, |
||||
'UNIQUE' => true, |
||||
'UPDATE' => true, |
||||
'USING' => true, |
||||
'VACUUM' => true, |
||||
'VALUES' => true, |
||||
'VIEW' => true, |
||||
'VIRTUAL' => true, |
||||
'WHEN' => true, |
||||
'WHERE' => true, |
||||
'WITH' => true, |
||||
'WITHOUT' => true, |
||||
]; |
||||
|
||||
$string = mb_strtoupper($string, 'UTF-8'); |
||||
if (!isset($keywords[$string])) { |
||||
return false; |
||||
} |
||||
|
||||
$content = $string; |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,23 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\db; |
||||
|
||||
class AnyCaseValue extends CompareValue |
||||
{ |
||||
public $value; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string|string[] $value |
||||
* @param array $config |
||||
*/ |
||||
public function __construct($value, $config = []) |
||||
{ |
||||
if (is_array($value)) { |
||||
$this->value = array_map('strtolower', $value); |
||||
} else { |
||||
$this->value = strtolower($value); |
||||
} |
||||
parent::__construct($config); |
||||
} |
||||
} |
@ -0,0 +1,19 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\db; |
||||
|
||||
class AnyValue extends CompareValue |
||||
{ |
||||
/** |
||||
* @var self |
||||
*/ |
||||
private static $_instance; |
||||
|
||||
public static function getInstance() |
||||
{ |
||||
if (self::$_instance === null) { |
||||
self::$_instance = new self(); |
||||
} |
||||
return self::$_instance; |
||||
} |
||||
} |
@ -0,0 +1,9 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\db; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
abstract class CompareValue extends Object |
||||
{ |
||||
} |
Loading…
Reference in new issue