├── phpcs.xml.dist
├── src
├── conditions
│ ├── LikeConditionBuilder.php
│ └── InConditionBuilder.php
├── ColumnSchemaBuilder.php
├── ExpressionBuilder.php
├── ColumnSchema.php
├── PdoAdapter.php
├── Command.php
├── Connection.php
├── Transaction.php
├── QueryBuilder.php
└── Schema.php
├── composer.json
├── LICENSE.md
├── README.md
└── composer.lock
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 | A custom coding standard
4 |
5 |
6 |
7 |
8 |
9 | /tests/bootstrap.php$
10 |
11 |
12 | /vendor/*
13 |
--------------------------------------------------------------------------------
/src/conditions/LikeConditionBuilder.php:
--------------------------------------------------------------------------------
1 | '\%',
27 | '_' => '\_',
28 | '\\' => '\\\\',
29 | ];
30 | }
31 |
--------------------------------------------------------------------------------
/src/ColumnSchemaBuilder.php:
--------------------------------------------------------------------------------
1 |
14 | * @since 2.0
15 | */
16 | class ColumnSchemaBuilder extends \yii\db\ColumnSchemaBuilder
17 | {
18 |
19 | /**
20 | * @inheritdoc
21 | */
22 | public function __toString()
23 | {
24 | switch ($this->getTypeCategory()) {
25 | case self::CATEGORY_PK:
26 | $format = '{type}{length}{check}';
27 | break;
28 | default:
29 | $format = '{type}{length}{default}{notnull}{unique}{check}';
30 | }
31 | return $this->buildCompleteString($format);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/ExpressionBuilder.php:
--------------------------------------------------------------------------------
1 | params);
30 | $string = $expression->__toString();
31 |
32 | static $expressionMap = [
33 | "strftime('%Y')" => "EXTRACT(YEAR FROM TIMESTAMP 'now')"
34 | ];
35 |
36 | if (isset($expressionMap[$string])) {
37 | return $expressionMap[$string];
38 | }
39 |
40 | return $string;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/conditions/InConditionBuilder.php:
--------------------------------------------------------------------------------
1 | $column) {
22 | $quotedColumns[$i] = strpos($column, '(') === false ? $this->queryBuilder->db->quoteColumnName($column) : $column;
23 | }
24 | $vss = [];
25 | foreach ($values as $value) {
26 | $vs = [];
27 | foreach ($columns as $i => $column) {
28 | if (isset($value[$column])) {
29 | $phName = $this->queryBuilder->bindParam($value[$column], $params);
30 | $vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' = ' : ' != ') . $phName;
31 | } else {
32 | $vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' IS' : ' IS NOT') . ' NULL';
33 | }
34 | }
35 | $vss[] = '(' . implode($operator === 'IN' ? ' AND ' : ' OR ', $vs) . ')';
36 | }
37 |
38 | return '(' . implode($operator === 'IN' ? ' OR ' : ' AND ', $vss) . ')';
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edgardmessias/yii2-firebird",
3 | "description": "Firebird connector for Yii2 framework",
4 | "keywords": ["yii2", "firebird", "active-record"],
5 | "type": "yii2-extension",
6 | "license": "BSD-3-Clause",
7 | "support": {
8 | "issues": "https://github.com/edgardmessias/yii2-firebird/issues",
9 | "forum": "http://www.yiiframework.com/forum/",
10 | "wiki": "http://www.yiiframework.com/wiki/",
11 | "irc": "irc://irc.freenode.net/yii",
12 | "source": "https://github.com/edgardmessias/yii2-firebird"
13 | },
14 | "authors": [
15 | {
16 | "name": "Edgard Lorraine Messias",
17 | "email": "edgardmessias@gmail.com"
18 | }
19 | ],
20 | "require": {
21 | "yiisoft/yii2": "^2.0.15.0"
22 | },
23 | "require-dev": {
24 | "yiisoft/yii2-dev": "~2.0.15.0",
25 | "yiisoft/yii2-coding-standards": "^2.0.2",
26 | "phpunit/phpunit": "4.8.34"
27 | },
28 | "autoload": {
29 | "psr-4": {
30 | "edgardmessias\\db\\firebird\\": "src"
31 | }
32 | },
33 | "config": {
34 | "platform": {
35 | "php": "5.4"
36 | },
37 | "fxp-asset": {
38 | "installer-paths": {
39 | "npm-asset-library": "vendor/npm",
40 | "bower-asset-library": "vendor/bower"
41 | },
42 | "vcs-driver-options": {
43 | "github-no-api": true
44 | },
45 | "pattern-skip-version": "(-build|-patch)"
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The yii2-firebird is free software. It is released under the terms of
2 | the following BSD License.
3 |
4 | Copyright © 2016 by Edgard Lorraine Messias (https://github.com/edgardmessias)
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions
9 | are met:
10 |
11 | * Redistributions of source code must retain the above copyright
12 | notice, this list of conditions and the following disclaimer.
13 | * Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in
15 | the documentation and/or other materials provided with the
16 | distribution.
17 | * Neither the name of Edgard Lorraine Messias nor the names of its
18 | contributors may be used to endorse or promote products derived
19 | from this software without specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | POSSIBILITY OF SUCH DAMAGE.
33 |
--------------------------------------------------------------------------------
/src/ColumnSchema.php:
--------------------------------------------------------------------------------
1 |
17 | * @since 2.0
18 | */
19 | class ColumnSchema extends \yii\db\ColumnSchema
20 | {
21 |
22 | /**
23 | * Converts the input value according to [[phpType]] after retrieval from the database.
24 | * If the value is null or an [[Expression]], it will not be converted.
25 | * @param mixed $value input value
26 | * @return mixed converted value
27 | * @since 2.0.3
28 | */
29 | protected function typecast($value)
30 | {
31 | if ($value === ''
32 | && !in_array(
33 | $this->type,
34 | [
35 | Schema::TYPE_TEXT,
36 | Schema::TYPE_STRING,
37 | Schema::TYPE_BINARY,
38 | Schema::TYPE_CHAR
39 | ],
40 | true)
41 | ) {
42 | return null;
43 | }
44 |
45 | if ($value === null
46 | || gettype($value) === $this->phpType
47 | || $value instanceof ExpressionInterface
48 | || $value instanceof Query
49 | ) {
50 | return $value;
51 | }
52 |
53 | if (is_array($value)
54 | && count($value) === 2
55 | && isset($value[1])
56 | && in_array($value[1], $this->getPdoParamTypes(), true)
57 | ) {
58 | return new PdoValue($value[0], $value[1]);
59 | }
60 |
61 | switch ($this->phpType) {
62 | case 'resource':
63 | case 'string':
64 | if (is_resource($value)) {
65 | return $value;
66 | }
67 | if (is_float($value)) {
68 | // ensure type cast always has . as decimal separator in all locales
69 | return str_replace(',', '.', (string) $value);
70 | }
71 | return (string) $value;
72 | case 'integer':
73 | if (is_bool($value)) {
74 | return ($value) ? 1 : 0;
75 | }
76 | return (int) $value;
77 | case 'boolean':
78 | return (boolean) $value;
79 | case 'double':
80 | return (double) $value;
81 | }
82 |
83 | return $value;
84 | }
85 |
86 | /**
87 | * @return int[] array of numbers that represent possible PDO parameter types
88 | */
89 | private function getPdoParamTypes()
90 | {
91 | return [\PDO::PARAM_BOOL, \PDO::PARAM_INT, \PDO::PARAM_STR, \PDO::PARAM_LOB, \PDO::PARAM_NULL, \PDO::PARAM_STMT];
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/PdoAdapter.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | class PdoAdapter extends PDO
19 | {
20 |
21 | private $_inTransaction = false;
22 |
23 | /**
24 | * Do some basic setup for Firebird.
25 | * o Force use of exceptions on error.
26 | * o Force all metadata to lower case.
27 | * Yii will behave in unpredicatable ways if
28 | * metadata is not lowercase.
29 | * o Ensure that table names are not prefixed to
30 | * fieldnames when returning metadata.
31 | * Finally call parent constructor.
32 | *
33 | */
34 | public function __construct($dsn, $username, $password, $driver_options = [])
35 | {
36 | // Windows OS paths with backslashes should be changed
37 | $dsn = str_replace('\\', '/', $dsn);
38 | // apply error mode
39 | $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
40 | // lower case column names in results are necessary for Yii ActiveRecord proper functioning
41 | $driver_options[PDO::ATTR_CASE] = PDO::CASE_LOWER;
42 | // ensure we only receive fieldname not tablename.fieldname.
43 | $driver_options[PDO::ATTR_FETCH_TABLE_NAMES] = false;
44 | parent::__construct($dsn, $username, $password, $driver_options);
45 | }
46 |
47 | /**
48 | * Initiates a transaction
49 | * @return bool TRUE on success or FALSE on failure.
50 | */
51 | public function beginTransaction($isolationLevel = null)
52 | {
53 | $this->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
54 |
55 | if ($isolationLevel === false) {
56 | $this->_inTransaction = true;
57 | return true;
58 | }
59 |
60 | if ($isolationLevel === null) {
61 | $r = $this->exec('SET TRANSACTION');
62 | $success = ($r !== false);
63 | if ($success) {
64 | $this->_inTransaction = true;
65 | }
66 | return ($success);
67 | }
68 |
69 | $r = $this->exec("SET TRANSACTION ISOLATION LEVEL $isolationLevel");
70 | $success = ($r !== false);
71 | if ($success) {
72 | $this->_inTransaction = true;
73 | }
74 | return ($success);
75 | }
76 |
77 | /**
78 | * Commits a transaction
79 | * @return bool TRUE on success or FALSE on failure.
80 | */
81 | public function commit()
82 | {
83 | $r = $this->exec('COMMIT');
84 | $this->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
85 | $success = ($r !== false);
86 | if ($success) {
87 | $this->_inTransaction = false;
88 | }
89 | return ($success);
90 | }
91 |
92 | /**
93 | * Rolls back a transaction
94 | * @return bool TRUE on success or FALSE on failure.
95 | */
96 | public function rollBack()
97 | {
98 | $r = $this->exec('ROLLBACK');
99 | $this->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
100 | $success = ($r !== false);
101 | if ($success) {
102 | $this->_inTransaction = false;
103 | }
104 | return ($success);
105 | }
106 |
107 | /**
108 | * Checks if inside a transaction
109 | * @return bool TRUE if a transaction is currently active, and FALSE if not.
110 | */
111 | public function inTransaction()
112 | {
113 | return $this->_inTransaction;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/Command.php:
--------------------------------------------------------------------------------
1 |
13 | * @since 2.0
14 | */
15 | class Command extends \yii\db\Command
16 | {
17 |
18 | /**
19 | * Binds a parameter to the SQL statement to be executed.
20 | * @param string|integer $name parameter identifier. For a prepared statement
21 | * using named placeholders, this will be a parameter name of
22 | * the form `:name`. For a prepared statement using question mark
23 | * placeholders, this will be the 1-indexed position of the parameter.
24 | * @param mixed $value Name of the PHP variable to bind to the SQL statement parameter
25 | * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
26 | * @param integer $length length of the data type
27 | * @param mixed $driverOptions the driver-specific options
28 | * @return static the current command being executed
29 | * @see http://www.php.net/manual/en/function.PDOStatement-bindParam.php
30 | */
31 | public function bindParam($name, &$value, $dataType = null, $length = null, $driverOptions = null)
32 | {
33 | if ($dataType === null) {
34 | $dataType = $this->db->getSchema()->getPdoType($value);
35 | }
36 | if ($dataType == \PDO::PARAM_BOOL) {
37 | $dataType = \PDO::PARAM_INT;
38 | }
39 | return parent::bindParam($name, $value, $dataType, $length, $driverOptions);
40 | }
41 |
42 | /**
43 | * Specifies the SQL statement to be executed.
44 | * The previous SQL execution (if any) will be cancelled, and [[params]] will be cleared as well.
45 | * @param string $sql the SQL statement to be set.
46 | * @return static this command instance
47 | */
48 | public function setSql($sql)
49 | {
50 | $matches = null;
51 | if (preg_match("/^\s*DROP TABLE IF EXISTS (['\"]?([^\s\;]+)['\"]?);?\s*$/i", $sql, $matches)) {
52 | if ($this->db->getSchema()->getTableSchema($matches[2]) !== null) {
53 | $sql = $this->db->getQueryBuilder()->dropTable($matches[2]);
54 | } else {
55 | $sql = 'select 1 from RDB$DATABASE;'; //Prevent Drop Table
56 | }
57 | }
58 |
59 | return parent::setSql($sql);
60 | }
61 |
62 | public function getSql() {
63 | $sql = parent::getSql();
64 | if (is_string($sql)) {
65 | // Unquote the {{@table@}} to {{table}} for insert
66 | $sql = preg_replace('/(\{\{)@(%?[\w\-\. ]+%?)@(\}\})/', '\1\2\3', $sql);
67 | }
68 | return $sql;
69 | }
70 |
71 | /**
72 | * Binds a value to a parameter.
73 | * @param string|integer $name Parameter identifier. For a prepared statement
74 | * using named placeholders, this will be a parameter name of
75 | * the form `:name`. For a prepared statement using question mark
76 | * placeholders, this will be the 1-indexed position of the parameter.
77 | * @param mixed $value The value to bind to the parameter
78 | * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
79 | * @return static the current command being executed
80 | * @see http://www.php.net/manual/en/function.PDOStatement-bindValue.php
81 | */
82 | public function bindValue($name, $value, $dataType = null)
83 | {
84 | if ($dataType === null) {
85 | $dataType = $this->db->getSchema()->getPdoType($value);
86 | }
87 | if ($dataType == \PDO::PARAM_BOOL) {
88 | $dataType = \PDO::PARAM_INT;
89 | }
90 |
91 | return parent::bindValue($name, $value, $dataType);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Firebird Extension for Yii 2
2 | ==========================
3 | [](https://packagist.org/packages/edgardmessias/yii2-firebird)
4 | [](https://packagist.org/packages/edgardmessias/yii2-firebird)
5 | [](https://packagist.org/packages/edgardmessias/yii2-firebird)
6 | [](https://packagist.org/packages/edgardmessias/yii2-firebird)
7 |
8 | This branch use last stable version of Yii2 (dev)
9 |
10 | This extension adds [Firebird](http://www.firebirdsql.org/) database engine extension for the [Yii framework 2.0](http://www.yiiframework.com).
11 |
12 | [](http://www.yiiframework.com/)
13 | [](https://travis-ci.org/edgardmessias/yii2-firebird)
14 | [](https://www.versioneye.com/php/edgardmessias:yii2-firebird/dev-master)
15 | [](https://www.versioneye.com/php/edgardmessias:yii2-firebird/references)
16 | [](https://scrutinizer-ci.com/g/edgardmessias/yii2-firebird/?branch=master)
17 | [](https://scrutinizer-ci.com/g/edgardmessias/yii2-firebird/?branch=master)
18 |
19 | Requirements
20 | ------------
21 |
22 | At least Firebird version 2.0 is required. However, in order to use all extension features.
23 |
24 | Partial support with Firebird 3.0
25 |
26 | Unsupported
27 | ------------
28 |
29 | Functions not supported by the Firebird database:
30 |
31 | * Rename Table - [See this FAQ](http://www.firebirdfaq.org/faq363/)
32 | * Check Integrity - [Track](http://tracker.firebirdsql.org/browse/CORE-1924)
33 | * BLOB data type for pdo_firebird <= 7.0.13 - [See this bug](https://bugs.php.net/bug.php?id=61183)
34 | * BOOLEAN data type for pdo_firebird - [See this bug](https://bugs.php.net/bug.php?id=74462)
35 |
36 | Installation
37 | ------------
38 |
39 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
40 |
41 | Either run
42 |
43 | ```bash
44 | php composer.phar require --prefer-dist "edgardmessias/yii2-firebird:*"
45 | ```
46 |
47 | or add
48 |
49 | ```json
50 | "edgardmessias/yii2-firebird": "*"
51 | ```
52 |
53 | to the require section of your composer.json.
54 |
55 |
56 | Configuration
57 | -------------
58 |
59 | To use this extension, simply add the following code in your application configuration:
60 |
61 | ```php
62 | return [
63 | //....
64 | 'components' => [
65 | 'db' => [
66 | 'class' => 'edgardmessias\db\firebird\Connection',
67 | 'dsn' => 'firebird:dbname=localhost:/tmp/TEST.FDB;charset=ISO8859_1',
68 | 'username' => 'username',
69 | 'password' => 'password',
70 | ],
71 | ],
72 | ];
73 | ```
74 |
75 | ## Donations:
76 | * Donation is as per your goodwill to support my development.
77 | * If you are interested in my future developments, i would really appreciate a small donation to support this project.
78 | ```html
79 | My Monero Wallet Address (XMR)
80 | 429VTmDsAw4aKgibxkk4PzZbxzj8txYtq5XrKHc28pXsUtMDWniL749WbwaVe4vUMveKAzAiA4j8xgUi29TpKXpm41bmrwQ
81 | ```
82 | ```html
83 | My Bitcoin Wallet Address (BTC)
84 | 38hcARGVzgYrcdYPkXxBXKTqScdixvFhZ4
85 | ```
86 | ```html
87 | My Ethereum Wallet Address (ETH)
88 | 0xdb77aa3d0e496c73a0dac816ac33ea389cf54681
89 | ```
90 | Another Cryptocurrency: https://freewallet.org/id/edgardmessias
91 |
--------------------------------------------------------------------------------
/src/Connection.php:
--------------------------------------------------------------------------------
1 |
13 | * @since 2.0
14 | */
15 | class Connection extends \yii\db\Connection
16 | {
17 | /**
18 | * Firebird server version
19 | */
20 | public $firebird_version = null;
21 |
22 | /**
23 | * @see https://www.firebirdsql.org/file/documentation/release_notes/html/en/3_0/rnfb30-ddl-enhance.html#rnfb30-ddl-identity
24 | * @var boolean|null
25 | */
26 | public $supportColumnIdentity = null;
27 |
28 | /**
29 | * @see https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-insert.html#fblangref25-dml-insert-select-unstable
30 | * @var boolean|null
31 | */
32 | public $supportStableCursor = null;
33 |
34 | /**
35 | * @see https://bugs.php.net/bug.php?id=72931
36 | * @var boolean|null
37 | */
38 | public $supportReturningInsert = null;
39 |
40 | /**
41 | * @see https://bugs.php.net/bug.php?id=61183
42 | * @var boolean|null
43 | */
44 | public $supportBlobDataType = null;
45 |
46 | /**
47 | * @inheritdoc
48 | */
49 | public $schemaMap = [
50 | 'firebird' => 'edgardmessias\db\firebird\Schema', // Firebird
51 | ];
52 |
53 | /**
54 | * @inheritdoc
55 | */
56 | public $pdoClass = 'edgardmessias\db\firebird\PdoAdapter';
57 |
58 | /**
59 | * @inheritdoc
60 | */
61 | public $commandClass = 'edgardmessias\db\firebird\Command';
62 | /**
63 | * @var Transaction the currently active transaction
64 | */
65 | private $_transaction;
66 |
67 | /**
68 | * Returns the currently active transaction.
69 | * @return Transaction the currently active transaction. Null if no active transaction.
70 | */
71 | public function getTransaction()
72 | {
73 | return $this->_transaction && $this->_transaction->getIsActive() ? $this->_transaction : null;
74 | }
75 |
76 | /**
77 | * Starts a transaction.
78 | * @param string|null $isolationLevel The isolation level to use for this transaction.
79 | * See [[Transaction::begin()]] for details.
80 | * @return Transaction the transaction initiated
81 | */
82 | public function beginTransaction($isolationLevel = null)
83 | {
84 | $this->open();
85 |
86 | if (($transaction = $this->getTransaction()) === null) {
87 | $transaction = $this->_transaction = new Transaction(['db' => $this]);
88 | }
89 | $transaction->begin($isolationLevel);
90 |
91 | return $transaction;
92 | }
93 |
94 | public function close()
95 | {
96 | if ($this->pdo !== null) {
97 | $this->_transaction = null;
98 | }
99 | parent::close();
100 | }
101 |
102 | public function init()
103 | {
104 | parent::init();
105 |
106 | if ($this->firebird_version) {
107 | return;
108 | }
109 |
110 | try {
111 | $pdo = $this->createPdoInstance();
112 |
113 | $server_version = $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION);
114 |
115 | if (preg_match('/\w{2}-[TV](\d+\.\d+\.\d+).*remote server/', $server_version, $matches)) {
116 | $this->firebird_version = $matches[1];
117 | }
118 | } catch (\Exception $ex) {
119 | }
120 |
121 | $supports = [
122 | 'supportColumnIdentity' => version_compare($this->firebird_version, '3.0.0', '>='),
123 | 'supportStableCursor' => version_compare($this->firebird_version, '3.0.0', '>='),
124 | 'supportReturningInsert' => version_compare($this->firebird_version, '3.0.0', '<') || version_compare(phpversion('pdo_firebird'), '7.0.15', '>='),
125 | 'supportBlobDataType' => version_compare(phpversion('pdo_firebird'), '7.0.13', '>'),
126 | ];
127 |
128 | foreach ($supports as $key => $value) {
129 | if ($this->{$key} === null) {
130 | $this->{$key} = $value;
131 | }
132 | }
133 | }
134 |
135 | /**
136 | * Reset the connection after cloning.
137 | */
138 | public function __clone()
139 | {
140 | parent::__clone();
141 |
142 | $this->_transaction = null;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/Transaction.php:
--------------------------------------------------------------------------------
1 | beginTransaction();
25 | * try {
26 | * $connection->createCommand($sql1)->execute();
27 | * $connection->createCommand($sql2)->execute();
28 | * //.... other SQL executions
29 | * $transaction->commit();
30 | * } catch (Exception $e) {
31 | * $transaction->rollBack();
32 | * }
33 | * ~~~
34 | *
35 | * @property boolean $isActive Whether this transaction is active. Only an active transaction can [[commit()]]
36 | * or [[rollBack()]]. This property is read-only.
37 | * @property string $isolationLevel The transaction isolation level to use for this transaction. This can be
38 | * one of [[READ_UNCOMMITTED]], [[READ_COMMITTED]], [[REPEATABLE_READ]] and [[SERIALIZABLE]] but also a string
39 | * containing DBMS specific syntax to be used after `SET TRANSACTION ISOLATION LEVEL`. This property is
40 | * write-only.
41 | *
42 | * @author Edgard Lorraine Messias
43 | * @since 1.0
44 | */
45 | class Transaction extends \yii\db\Transaction
46 | {
47 |
48 | /**
49 | * @var integer the nesting level of the transaction. 0 means the outermost level.
50 | */
51 | private $_level = 0;
52 |
53 | /**
54 | * Returns a value indicating whether this transaction is active.
55 | * @return boolean whether this transaction is active. Only an active transaction
56 | * can [[commit()]] or [[rollBack()]].
57 | */
58 | public function getIsActive()
59 | {
60 | return $this->_level > 0 && $this->db && $this->db->isActive;
61 | }
62 |
63 | /**
64 | * Begins a transaction.
65 | * @param string|null $isolationLevel The [isolation level][] to use for this transaction.
66 | * This can be one of [[READ_UNCOMMITTED]], [[READ_COMMITTED]], [[REPEATABLE_READ]] and [[SERIALIZABLE]] but
67 | * also a string containing DBMS specific syntax to be used after `SET TRANSACTION ISOLATION LEVEL`.
68 | * If not specified (`null`) the isolation level will not be set explicitly and the DBMS default will be used.
69 | *
70 | * > Note: This setting does not work for PostgreSQL, where setting the isolation level before the transaction
71 | * has no effect. You have to call [[setIsolationLevel()]] in this case after the transaction has started.
72 | *
73 | * > Note: Some DBMS allow setting of the isolation level only for the whole connection so subsequent transactions
74 | * may get the same isolation level even if you did not specify any. When using this feature
75 | * you may need to set the isolation level for all transactions explicitly to avoid conflicting settings.
76 | * At the time of this writing affected DBMS are MSSQL and SQLite.
77 | *
78 | * [isolation level]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
79 | * @throws InvalidConfigException if [[db]] is `null`.
80 | */
81 | public function begin($isolationLevel = null)
82 | {
83 | if ($this->db === null) {
84 | throw new InvalidConfigException('Transaction::db must be set.');
85 | }
86 | $this->db->open();
87 |
88 | if ($this->_level == 0) {
89 | Yii::trace('Begin transaction' . ($isolationLevel ? ' with isolation level ' . $isolationLevel : ''), __METHOD__);
90 |
91 | $this->db->trigger(Connection::EVENT_BEGIN_TRANSACTION);
92 | if ($isolationLevel !== null) {
93 | $this->db->pdo->beginTransaction(false);
94 | $this->db->getSchema()->setTransactionIsolationLevel($isolationLevel);
95 | } else {
96 | $this->db->pdo->beginTransaction();
97 | }
98 | $this->_level = 1;
99 |
100 | return;
101 | }
102 |
103 | $schema = $this->db->getSchema();
104 | if ($schema->supportsSavepoint()) {
105 | Yii::trace('Set savepoint ' . $this->_level, __METHOD__);
106 | $schema->createSavepoint('LEVEL' . $this->_level);
107 | } else {
108 | Yii::info('Transaction not started: nested transaction not supported', __METHOD__);
109 | }
110 | $this->_level++;
111 | }
112 |
113 | /**
114 | * Commits a transaction.
115 | * @throws Exception if the transaction is not active
116 | */
117 | public function commit()
118 | {
119 | if (!$this->getIsActive()) {
120 | throw new Exception('Failed to commit transaction: transaction was inactive.');
121 | }
122 |
123 | $this->_level--;
124 | if ($this->_level == 0) {
125 | Yii::trace('Commit transaction', __METHOD__);
126 | $this->db->pdo->commit();
127 | $this->db->trigger(Connection::EVENT_COMMIT_TRANSACTION);
128 | return;
129 | }
130 |
131 | $schema = $this->db->getSchema();
132 | if ($schema->supportsSavepoint()) {
133 | Yii::trace('Release savepoint ' . $this->_level, __METHOD__);
134 | $schema->releaseSavepoint('LEVEL' . $this->_level);
135 | } else {
136 | Yii::info('Transaction not committed: nested transaction not supported', __METHOD__);
137 | }
138 | }
139 |
140 | /**
141 | * Rolls back a transaction.
142 | * @throws Exception if the transaction is not active
143 | */
144 | public function rollBack()
145 | {
146 | if (!$this->getIsActive()) {
147 | // do nothing if transaction is not active: this could be the transaction is committed
148 | // but the event handler to "commitTransaction" throw an exception
149 | return;
150 | }
151 |
152 | $this->_level--;
153 | if ($this->_level == 0) {
154 | Yii::trace('Roll back transaction', __METHOD__);
155 | $this->db->pdo->rollBack();
156 | $this->db->trigger(Connection::EVENT_ROLLBACK_TRANSACTION);
157 | return;
158 | }
159 |
160 | $schema = $this->db->getSchema();
161 | if ($schema->supportsSavepoint()) {
162 | Yii::trace('Roll back to savepoint ' . $this->_level, __METHOD__);
163 | $schema->rollBackSavepoint('LEVEL' . $this->_level);
164 | } else {
165 | Yii::info('Transaction not rolled back: nested transaction not supported', __METHOD__);
166 | // throw an exception to fail the outer transaction
167 | throw new Exception('Roll back failed: nested transaction not supported.');
168 | }
169 | }
170 |
171 | /**
172 | * Sets the transaction isolation level for this transaction.
173 | *
174 | * This method can be used to set the isolation level while the transaction is already active.
175 | * However this is not supported by all DBMS so you might rather specify the isolation level directly
176 | * when calling [[begin()]].
177 | * @param string $level The transaction isolation level to use for this transaction.
178 | * This can be one of [[READ_UNCOMMITTED]], [[READ_COMMITTED]], [[REPEATABLE_READ]] and [[SERIALIZABLE]] but
179 | * also a string containing DBMS specific syntax to be used after `SET TRANSACTION ISOLATION LEVEL`.
180 | * @throws Exception if the transaction is not active
181 | * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
182 | */
183 | public function setIsolationLevel($level)
184 | {
185 | if (!$this->getIsActive()) {
186 | throw new Exception('Failed to set isolation level: transaction was inactive.');
187 | }
188 | Yii::trace('Setting transaction isolation level to ' . $level, __METHOD__);
189 | $this->db->getSchema()->setTransactionIsolationLevel($level);
190 | }
191 |
192 | /**
193 | * @return integer The current nesting level of the transaction.
194 | * @since 2.0.8
195 | */
196 | public function getLevel()
197 | {
198 | return $this->_level;
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/QueryBuilder.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 2.0
20 | */
21 | class QueryBuilder extends \yii\db\QueryBuilder
22 | {
23 |
24 | /**
25 | * @var array mapping from abstract column types (keys) to physical column types (values).
26 | */
27 | public $typeMap = [
28 | Schema::TYPE_PK => 'integer NOT NULL PRIMARY KEY',
29 | Schema::TYPE_UPK => 'integer NOT NULL PRIMARY KEY',
30 | Schema::TYPE_BIGPK => 'bigint NOT NULL PRIMARY KEY',
31 | Schema::TYPE_UBIGPK => 'bigint NOT NULL PRIMARY KEY',
32 | Schema::TYPE_CHAR => 'char(1)',
33 | Schema::TYPE_STRING => 'varchar(255)',
34 | Schema::TYPE_TEXT => 'blob sub_type text',
35 | Schema::TYPE_SMALLINT => 'smallint',
36 | Schema::TYPE_INTEGER => 'integer',
37 | Schema::TYPE_BIGINT => 'bigint',
38 | Schema::TYPE_FLOAT => 'float',
39 | Schema::TYPE_DOUBLE => 'double precision',
40 | Schema::TYPE_DECIMAL => 'numeric(10,0)',
41 | Schema::TYPE_DATETIME => 'timestamp',
42 | Schema::TYPE_TIMESTAMP => 'timestamp',
43 | Schema::TYPE_TIME => 'time',
44 | Schema::TYPE_DATE => 'date',
45 | Schema::TYPE_BINARY => 'blob',
46 | Schema::TYPE_BOOLEAN => 'smallint',
47 | Schema::TYPE_MONEY => 'numeric(18,4)',
48 | ];
49 |
50 | public function init()
51 | {
52 | if ($this->db->supportColumnIdentity) {
53 | $this->typeMap[Schema::TYPE_PK] = 'integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY';
54 | $this->typeMap[Schema::TYPE_UPK] = 'integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY';
55 | $this->typeMap[Schema::TYPE_BIGPK] = 'bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY';
56 | $this->typeMap[Schema::TYPE_UBIGPK] = 'bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY';
57 | $this->typeMap[Schema::TYPE_BOOLEAN] = 'boolean';
58 | }
59 |
60 | parent::init();
61 | }
62 |
63 | protected function defaultExpressionBuilders()
64 | {
65 | return array_merge(parent::defaultExpressionBuilders(), [
66 | 'yii\db\Expression' => 'edgardmessias\db\firebird\ExpressionBuilder',
67 | 'yii\db\conditions\InCondition' => 'edgardmessias\db\firebird\conditions\InConditionBuilder',
68 | 'yii\db\conditions\LikeCondition' => 'edgardmessias\db\firebird\conditions\LikeConditionBuilder',
69 | ]);
70 | }
71 |
72 | /**
73 | * Generates a SELECT SQL statement from a [[Query]] object.
74 | * @param Query $query the [[Query]] object from which the SQL statement will be generated.
75 | * @param array $params the parameters to be bound to the generated SQL statement. These parameters will
76 | * be included in the result with the additional parameters generated during the query building process.
77 | * @return array the generated SQL statement (the first array element) and the corresponding
78 | * parameters to be bound to the SQL statement (the second array element). The parameters returned
79 | * include those provided in `$params`.
80 | */
81 | public function build($query, $params = [])
82 | {
83 | $query = $query->prepare($this);
84 |
85 | $params = empty($params) ? $query->params : array_merge($params, $query->params);
86 |
87 | $clauses = [
88 | $this->buildSelect($query->select, $params, $query->distinct, $query->selectOption),
89 | $this->buildFrom($query->from, $params),
90 | $this->buildJoin($query->join, $params),
91 | $this->buildWhere($query->where, $params),
92 | $this->buildGroupBy($query->groupBy),
93 | $this->buildHaving($query->having, $params),
94 | ];
95 |
96 | $sql = implode($this->separator, array_filter($clauses));
97 | $sql = $this->buildOrderByAndLimit($sql, $query->orderBy, $query->limit, $query->offset);
98 |
99 | if (!empty($query->orderBy)) {
100 | foreach ($query->orderBy as $expression) {
101 | if ($expression instanceof Expression) {
102 | $params = array_merge($params, $expression->params);
103 | }
104 | }
105 | }
106 | if (!empty($query->groupBy)) {
107 | foreach ($query->groupBy as $expression) {
108 | if ($expression instanceof Expression) {
109 | $params = array_merge($params, $expression->params);
110 | }
111 | }
112 | }
113 |
114 | $union = $this->buildUnion($query->union, $params);
115 | if ($union !== '') {
116 | $sql = "$sql{$this->separator}$union";
117 | }
118 |
119 | return [$sql, $params];
120 | }
121 |
122 | /**
123 | * @inheritdoc
124 | */
125 | public function buildSelect($columns, &$params, $distinct = false, $selectOption = null)
126 | {
127 | if (is_array($columns)) {
128 | foreach ($columns as $i => $column) {
129 | if (!is_string($column)) {
130 | continue;
131 | }
132 | $matches = [];
133 | if (preg_match('/^(COUNT|SUM|AVG|MIN|MAX)\([\{\[]{0,2}(\w+|\*)[\}\]]{0,2}\)$/i', $column, $matches)) {
134 | $function = $matches[1];
135 | $alias = $matches[2] != '*' ? $matches[2] : 'ALL';
136 |
137 | $columns[$i] = "{$column} AS {$function}_{$alias}";
138 | }
139 | }
140 | }
141 |
142 | return parent::buildSelect($columns, $params, $distinct, $selectOption);
143 | }
144 |
145 | public function buildLimit($limit, $offset)
146 | {
147 | $sql = '';
148 | if ($this->hasLimit($limit)) {
149 | if ($limit instanceof \yii\db\ExpressionInterface) {
150 | $limit = "($limit)";
151 | }
152 | $sql = 'FIRST ' . $limit;
153 | }
154 | if ($this->hasOffset($offset)) {
155 | if ($offset instanceof \yii\db\ExpressionInterface) {
156 | $offset = "($offset)";
157 | }
158 | $sql .= ' SKIP ' . $offset;
159 | }
160 |
161 | return ltrim($sql);
162 | }
163 |
164 | /**
165 | * @inheritdoc
166 | */
167 | public function buildOrderByAndLimit($sql, $orderBy, $limit, $offset)
168 | {
169 |
170 | $orderBy = $this->buildOrderBy($orderBy);
171 | if ($orderBy !== '') {
172 | $sql .= $this->separator . $orderBy;
173 | }
174 |
175 | $limit = $this->buildLimit($limit, $offset);
176 | if ($limit !== '') {
177 | $sql = preg_replace('/^SELECT /i', 'SELECT ' . $limit . ' ', $sql, 1);
178 | }
179 |
180 | return $sql;
181 | }
182 |
183 | /**
184 | * @param array $unions
185 | * @param array $params the binding parameters to be populated
186 | * @return string the UNION clause built from [[Query::$union]].
187 | */
188 | public function buildUnion($unions, &$params)
189 | {
190 | if (empty($unions)) {
191 | return '';
192 | }
193 |
194 | $result = '';
195 |
196 | foreach ($unions as $i => $union) {
197 | $query = $union['query'];
198 | if ($query instanceof Query) {
199 | list($unions[$i]['query'], $params) = $this->build($query, $params);
200 | }
201 |
202 | $result .= 'UNION ' . ($union['all'] ? 'ALL ' : '') . $unions[$i]['query'] . ' ';
203 | }
204 |
205 | return trim($result);
206 | }
207 |
208 | /**
209 | * @inheritdoc
210 | */
211 | public function prepareInsertValues($table, $columns, $params = [])
212 | {
213 | $schema = $this->db->getSchema();
214 | $tableSchema = $schema->getTableSchema($table);
215 | $columnSchemas = $tableSchema !== null ? $tableSchema->columns : [];
216 |
217 | //Empty insert
218 | if (empty($columns) && !empty($columnSchemas)) {
219 | $columns = [];
220 | foreach ($columnSchemas as $columnSchema) {
221 | if (!$columnSchema->autoIncrement) {
222 | $columns[$columnSchema->name] = $columnSchema->defaultValue;
223 | }
224 | }
225 | }
226 |
227 | if (is_array($columns)) {
228 | foreach ($columns as $name => $value) {
229 | if ($value instanceof \yii\db\ExpressionInterface) {
230 | continue;
231 | }
232 | if ($value instanceof \yii\db\PdoValue) {
233 | continue;
234 | }
235 | if (isset($columnSchemas[$name]) && in_array($columnSchemas[$name]->type, [Schema::TYPE_TEXT, Schema::TYPE_BINARY])) {
236 | $columns[$name] = [$value, \PDO::PARAM_LOB];
237 | }
238 | }
239 | }
240 |
241 | return parent::prepareInsertValues($table, $columns, $params);
242 | }
243 |
244 | /**
245 | * @inheritdoc
246 | */
247 | protected function prepareInsertSelectSubQuery($columns, $schema, $params = [])
248 | {
249 | /**
250 | * @see https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-insert.html#fblangref25-dml-insert-select-unstable
251 | */
252 | if (!$this->db->supportStableCursor) {
253 | throw new NotSupportedException('Firebird < 3.0.0 has the "Unstable Cursor" problem');
254 | }
255 |
256 | return parent::prepareInsertSelectSubQuery($columns, $schema, $params);
257 | }
258 |
259 | /**
260 | * @inheritdoc
261 | */
262 | public function prepareUpdateSets($table, $columns, $params = [])
263 | {
264 | $schema = $this->db->getSchema();
265 | $tableSchema = $schema->getTableSchema($table);
266 | $columnSchemas = $tableSchema !== null ? $tableSchema->columns : [];
267 |
268 | foreach ($columns as $name => $value) {
269 | if ($value instanceof \yii\db\ExpressionInterface) {
270 | continue;
271 | }
272 | if ($value instanceof \yii\db\PdoValue) {
273 | continue;
274 | }
275 | if (isset($columnSchemas[$name]) && in_array($columnSchemas[$name]->type, [Schema::TYPE_TEXT, Schema::TYPE_BINARY])) {
276 | $columns[$name] = [$value, \PDO::PARAM_LOB];
277 | }
278 | }
279 | return parent::prepareUpdateSets($table, $columns, $params);
280 | }
281 |
282 | public function rawInsert($table, $columns, $values, &$params)
283 | {
284 | $schema = $this->db->getSchema();
285 | if (($tableSchema = $schema->getTableSchema($table)) !== null) {
286 | $columnSchemas = $tableSchema->columns;
287 | } else {
288 | $columnSchemas = [];
289 | }
290 |
291 | $cs = [];
292 | $vs = [];
293 | foreach ($values as $i => $value) {
294 | if (isset($columns[$i], $columnSchemas[$columns[$i]]) && !is_array($value)) {
295 | $value = $columnSchemas[$columns[$i]]->dbTypecast($value);
296 | }
297 | if (is_string($value)) {
298 | // Quote the {{table}} to {{@table@}} for insert
299 | $value = preg_replace('/(\{\{)(%?[\w\-\. ]+%?)(\}\})/', '\1@\2@\3', $value);
300 | $value = $schema->quoteValue($value);
301 | } elseif (is_float($value)) {
302 | // ensure type cast always has . as decimal separator in all locales
303 | $value = \yii\helpers\StringHelper::floatToString($value);
304 | } elseif ($value === false) {
305 | $value = 0;
306 | } elseif ($value === null) {
307 | $value = 'NULL';
308 | } elseif ($value instanceof ExpressionInterface) {
309 | $value = $this->buildExpression($value, $params);
310 | }
311 |
312 | if (isset($columns[$i])) {
313 | $cs[] = $schema->quoteColumnName($columns[$i]);
314 | }
315 | $vs[] = $value;
316 | }
317 |
318 | if (empty($vs)) {
319 | return 'INSERT INTO ' . $schema->quoteTableName($table)
320 | . ' DEFAULT VALUES';
321 | }
322 |
323 | return 'INSERT INTO ' . $schema->quoteTableName($table)
324 | . ' (' . implode(', ', $cs) . ') VALUES (' . implode(', ', $vs) . ')';
325 | }
326 |
327 | /**
328 | * @inheritdoc
329 | */
330 | public function batchInsert($table, $columns, $rows, &$params = [])
331 | {
332 | if (empty($rows)) {
333 | return '';
334 | }
335 |
336 | $schema = $this->db->getSchema();
337 | if (($tableSchema = $schema->getTableSchema($table)) !== null) {
338 | $columnSchemas = $tableSchema->columns;
339 | } else {
340 | $columnSchemas = [];
341 | }
342 |
343 | $values = [];
344 | foreach ($rows as $row) {
345 | $values[] = $this->rawInsert($table, $columns, $row, $params) . ';';
346 | }
347 |
348 | return 'EXECUTE block AS BEGIN ' . implode(' ', $values) . ' END;';
349 | }
350 |
351 | /**
352 | * {@inheritdoc}
353 | * @see https://www.firebirdsql.org/refdocs/langrefupd21-update-or-insert.html
354 | * @see https://www.firebirdsql.org/refdocs/langrefupd21-merge.html
355 | */
356 | public function upsert($table, $insertColumns, $updateColumns, &$params)
357 | {
358 | /** @var Constraint[] $constraints */
359 | list($uniqueNames, $insertNames, $updateNames) = $this->prepareUpsertColumns($table, $insertColumns, $updateColumns, $constraints);
360 | if (empty($uniqueNames)) {
361 | return 'UPDATE OR ' . $this->insert($table, $insertColumns, $params);
362 | }
363 |
364 | $onCondition = ['or'];
365 | $quotedTableName = $this->db->quoteTableName($table);
366 | foreach ($constraints as $constraint) {
367 | $constraintCondition = ['and'];
368 | foreach ($constraint->columnNames as $name) {
369 | $quotedName = $this->db->quoteColumnName($name);
370 | $constraintCondition[] = "$quotedTableName.$quotedName=\"EXCLUDED\".$quotedName";
371 | }
372 | $onCondition[] = $constraintCondition;
373 | }
374 | $on = $this->buildCondition($onCondition, $params);
375 | list(, $placeholders, $values, $params) = $this->prepareInsertValues($table, $insertColumns, $params);
376 | if (!empty($placeholders)) {
377 | /** @var Schema $schema */
378 | $schema = $this->db->getSchema();
379 | $tableSchema = $schema->getTableSchema($table);
380 | $columnSchemas = $tableSchema !== null ? $tableSchema->columns : [];
381 |
382 | $usingSelectValues = [];
383 | foreach ($insertNames as $index => $name) {
384 | if (isset($columnSchemas[$name])) {
385 | $usingSelectValues[$name] = new Expression("CAST({$placeholders[$index]} AS {$columnSchemas[$name]->dbType})");
386 | }
387 | }
388 | $usingSubQuery = (new Query())
389 | ->select($usingSelectValues)
390 | ->from('RDB$DATABASE');
391 | list($usingValues, $params) = $this->build($usingSubQuery, $params);
392 | }
393 | $mergeSql = 'MERGE INTO ' . $this->db->quoteTableName($table) . ' '
394 | . 'USING (' . (isset($usingValues) ? $usingValues : ltrim($values, ' ')) . ') "EXCLUDED" '
395 | . "ON ($on)";
396 | $insertValues = [];
397 | foreach ($insertNames as $name) {
398 | $quotedName = $this->db->quoteColumnName($name);
399 | if (strrpos($quotedName, '.') === false) {
400 | $quotedName = '"EXCLUDED".' . $quotedName;
401 | }
402 | $insertValues[] = $quotedName;
403 | }
404 | $insertSql = 'INSERT (' . implode(', ', $insertNames) . ')'
405 | . ' VALUES (' . implode(', ', $insertValues) . ')';
406 | if ($updateColumns === false) {
407 | return "$mergeSql WHEN NOT MATCHED THEN $insertSql";
408 | }
409 |
410 | if ($updateColumns === true) {
411 | $updateColumns = [];
412 | foreach ($updateNames as $name) {
413 | $quotedName = $this->db->quoteColumnName($name);
414 | if (strrpos($quotedName, '.') === false) {
415 | $quotedName = '"EXCLUDED".' . $quotedName;
416 | }
417 | $updateColumns[$name] = new Expression($quotedName);
418 | }
419 | }
420 | list($updates, $params) = $this->prepareUpdateSets($table, $updateColumns, $params);
421 | $updateSql = 'UPDATE SET ' . implode(', ', $updates);
422 | return "$mergeSql WHEN MATCHED THEN $updateSql WHEN NOT MATCHED THEN $insertSql";
423 | }
424 |
425 | /**
426 | * @inheritdoc
427 | */
428 | public function renameTable($oldName, $newName)
429 | {
430 | throw new \yii\base\NotSupportedException($this->db->getDriverName() . ' does not support rename table.');
431 | }
432 |
433 | /**
434 | * @inheritdoc
435 | */
436 | public function truncateTable($table)
437 | {
438 | return 'DELETE FROM ' . $this->db->quoteTableName($table);
439 | }
440 |
441 | /**
442 | * @inheritdoc
443 | */
444 | public function dropColumn($table, $column)
445 | {
446 | return 'ALTER TABLE ' . $this->db->quoteTableName($table)
447 | . ' DROP ' . $this->db->quoteColumnName($column);
448 | }
449 |
450 | /**
451 | * @inheritdoc
452 | */
453 | public function renameColumn($table, $oldName, $newName)
454 | {
455 | return 'ALTER TABLE ' . $this->db->quoteTableName($table)
456 | . ' ALTER ' . $this->db->quoteColumnName($oldName)
457 | . ' TO ' . $this->db->quoteColumnName($newName);
458 | }
459 |
460 | /**
461 | * @inheritdoc
462 | */
463 | public function alterColumn($table, $column, $type)
464 | {
465 | $schema = $this->db->getSchema();
466 | $tableSchema = $schema->getTableSchema($table);
467 | $columnSchema = $tableSchema->getColumn($column);
468 |
469 | $allowNullNewType = !preg_match('/not +null/i', $type);
470 |
471 | $type = preg_replace('/ +(not)? *null/i', '', $type);
472 |
473 | $hasType = false;
474 |
475 | $matches = [];
476 | if (isset($this->typeMap[$type])) {
477 | $hasType = true;
478 | } elseif (preg_match('/^(\w+)[\( ]/', $type, $matches)) {
479 | if (isset($this->typeMap[$matches[1]])) {
480 | $hasType = true;
481 | }
482 | }
483 |
484 | $baseSql = 'ALTER TABLE ' . $this->db->quoteTableName($table)
485 | . ' ALTER ' . $this->db->quoteColumnName($column)
486 | . (($hasType) ? ' TYPE ' : ' ') . $this->getColumnType($type);
487 |
488 | if (version_compare($this->db->firebird_version, '3.0.0', '>=')) {
489 | $nullSql = false;
490 |
491 | if ($columnSchema->allowNull != $allowNullNewType) {
492 | $nullSql = 'ALTER TABLE ' . $this->db->quoteTableName($table)
493 | . ' ALTER ' . $this->db->quoteColumnName($column)
494 | . ($allowNullNewType ? ' DROP' : ' SET')
495 | . ' NOT NULL';
496 | }
497 |
498 | $sql = 'EXECUTE BLOCK AS BEGIN'
499 | . ' EXECUTE STATEMENT ' . $this->db->quoteValue($baseSql) . ';';
500 |
501 | /**
502 | * In any case (whichever option you choose), make sure that the column doesn't have any NULLs.
503 | * Firebird will not check it for you. Later when you backup the database, everything is fine,
504 | * but restore will fail as the NOT NULL column has NULLs in it. To be safe, each time you change from NULL to NOT NULL.
505 | */
506 | if (!$allowNullNewType) {
507 | $sql .= ' UPDATE ' . $this->db->quoteTableName($table) . ' SET ' . $this->db->quoteColumnName($column) . ' = 0'
508 | . ' WHERE ' . $this->db->quoteColumnName($column) . ' IS NULL;';
509 | }
510 |
511 | if ($nullSql) {
512 | $sql .= ' EXECUTE STATEMENT ' . $this->db->quoteValue($nullSql) . ';';
513 | }
514 |
515 | $sql .= ' END';
516 | return $sql;
517 | }
518 |
519 | if ($columnSchema->allowNull == $allowNullNewType) {
520 | return $baseSql;
521 | } else {
522 | $sql = 'EXECUTE BLOCK AS BEGIN'
523 | . ' EXECUTE STATEMENT ' . $this->db->quoteValue($baseSql) . ';'
524 | . ' UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = ' . ($allowNullNewType ? 'NULL' : '1')
525 | . ' WHERE UPPER(RDB$FIELD_NAME) = UPPER(\'' . $column . '\') AND UPPER(RDB$RELATION_NAME) = UPPER(\'' . $table . '\');';
526 | /**
527 | * In any case (whichever option you choose), make sure that the column doesn't have any NULLs.
528 | * Firebird will not check it for you. Later when you backup the database, everything is fine,
529 | * but restore will fail as the NOT NULL column has NULLs in it. To be safe, each time you change from NULL to NOT NULL.
530 | */
531 | if (!$allowNullNewType) {
532 | $sql .= ' UPDATE ' . $this->db->quoteTableName($table) . ' SET ' . $this->db->quoteColumnName($column) . ' = 0'
533 | . ' WHERE ' . $this->db->quoteColumnName($column) . ' IS NULL;';
534 | }
535 | $sql .= ' END';
536 | return $sql;
537 | }
538 | }
539 |
540 | /**
541 | * @inheritdoc
542 | */
543 | public function dropIndex($name, $table)
544 | {
545 | return 'DROP INDEX ' . $this->db->quoteTableName($name);
546 | }
547 |
548 | /**
549 | * {@inheritdoc}
550 | */
551 | public function addDefaultValue($name, $table, $column, $value)
552 | {
553 | return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ALTER COLUMN '
554 | . $this->db->quoteColumnName($column) . ' SET DEFAULT ' . $this->db->quoteValue($value);
555 | }
556 |
557 | /**
558 | * {@inheritdoc}
559 | */
560 | public function dropDefaultValue($name, $table)
561 | {
562 | return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ALTER COLUMN '
563 | . $this->db->quoteColumnName($name) . ' DROP DEFAULT';
564 | }
565 |
566 | /**
567 | * @inheritdoc
568 | */
569 | public function resetSequence($table, $value = null)
570 | {
571 | $tableSchema = $this->db->getTableSchema($table);
572 | if ($tableSchema === null) {
573 | throw new InvalidParamException("Table not found: $table");
574 | }
575 | if ($tableSchema->sequenceName === null) {
576 | throw new InvalidParamException("There is not sequence associated with table '$table'.");
577 | }
578 |
579 | if ($value !== null) {
580 | $value = (int) $value;
581 | } else {
582 | // use master connection to get the biggest PK value
583 | $value = $this->db->useMaster(function (Connection $db) use ($tableSchema) {
584 | $key = false;
585 | foreach ($tableSchema->primaryKey as $name) {
586 | if ($tableSchema->columns[$name]->autoIncrement) {
587 | $key = $name;
588 | break;
589 | }
590 | }
591 | if ($key === false) {
592 | return 0;
593 | }
594 | return $db->createCommand("SELECT MAX({$this->db->quoteColumnName($key)}) FROM {$this->db->quoteTableName($tableSchema->name)}")->queryScalar();
595 | }) + 1;
596 | }
597 |
598 | return "ALTER SEQUENCE {$this->db->quoteColumnName($tableSchema->sequenceName)} RESTART WITH $value";
599 | }
600 |
601 | /**
602 | * @inheritdoc
603 | */
604 | public function createTable($table, $columns, $options = null)
605 | {
606 | $sql = parent::createTable($table, $columns, $options);
607 |
608 | if ($this->db->supportColumnIdentity) {
609 | return $sql;
610 | }
611 |
612 | foreach ($columns as $name => $type) {
613 | if (!is_string($name)) {
614 | continue;
615 | }
616 |
617 | if (strpos($type, Schema::TYPE_PK) === 0 || strpos($type, Schema::TYPE_BIGPK) === 0) {
618 | $sqlTrigger = <<db->quoteTableName($table)}
620 | ACTIVE BEFORE INSERT POSITION 0
621 | AS
622 | BEGIN
623 | if (NEW.{$this->db->quoteColumnName($name)} is NULL) then NEW.{$this->db->quoteColumnName($name)} = NEXT VALUE FOR seq_{$table}_{$name};
624 | END
625 | SQLTRIGGER;
626 |
627 | $sqlBlock = <<db->quoteValue($sql)};
631 | EXECUTE STATEMENT {$this->db->quoteValue("CREATE SEQUENCE seq_{$table}_{$name}")};
632 | EXECUTE STATEMENT {$this->db->quoteValue($sqlTrigger)};
633 | END;
634 | SQL;
635 |
636 | return $sqlBlock;
637 | }
638 | }
639 |
640 | return $sql;
641 | }
642 |
643 | /**
644 | * @inheritdoc
645 | */
646 | public function dropTable($table)
647 | {
648 | $sql = parent::dropTable($table);
649 |
650 | $tableSchema = $this->db->getTableSchema($table);
651 | if ($tableSchema === null || $tableSchema->sequenceName === null) {
652 | return $sql;
653 | }
654 |
655 | /**
656 | * Not drop sequence for sequence "GENERATED BY DEFAULT AS IDENTITY"
657 | */
658 | if ($this->db->supportColumnIdentity) {
659 | $sqlUserSquence = 'SELECT 1 FROM RDB$GENERATORS
660 | WHERE RDB$SYSTEM_FLAG = 0 AND RDB$GENERATOR_NAME = :name';
661 |
662 | $is_user_sequence = $this->db->createCommand($sqlUserSquence, [':name' => $tableSchema->sequenceName])->queryScalar();
663 |
664 | if (!$is_user_sequence) {
665 | return $sql;
666 | }
667 | }
668 |
669 | $sqlBlock = <<db->quoteValue($sql)};
673 | EXECUTE STATEMENT {$this->db->quoteValue("DROP SEQUENCE {$tableSchema->sequenceName}")};
674 | END;
675 | SQL;
676 | return $sqlBlock;
677 | }
678 |
679 | /**
680 | * Creates a SELECT EXISTS() SQL statement.
681 | * @param string $rawSql the subquery in a raw form to select from.
682 | * @return string the SELECT EXISTS() SQL statement.
683 | *
684 | * @since 2.0.8
685 | */
686 | public function selectExists($rawSql)
687 | {
688 | return 'SELECT CASE WHEN EXISTS(' . $rawSql . ') THEN 1 ELSE 0 END FROM RDB$DATABASE';
689 | }
690 | }
691 |
--------------------------------------------------------------------------------
/src/Schema.php:
--------------------------------------------------------------------------------
1 | index type. This
33 | * property is read-only.
34 | * @property QueryBuilder $queryBuilder The query builder for this connection. This property is read-only.
35 | *
36 | * @author Edgard Lorraine Messias
37 | * @since 2.0
38 | */
39 | class Schema extends BaseSchema implements ConstraintFinderInterface
40 | {
41 | use ViewFinderTrait;
42 | use ConstraintFinderTrait;
43 |
44 | private $_lastInsertID = null;
45 |
46 | /**
47 | * @var array map of DB errors and corresponding exceptions
48 | * If left part is found in DB error message exception class from the right part is used.
49 | */
50 | public $exceptionMap = [
51 | 'SQLSTATE[23' => 'yii\db\IntegrityException',
52 | 'SQLSTATE[HY000]: General error: -803 violation of PRIMARY' => 'yii\db\IntegrityException',
53 | ];
54 | public $reservedWords = [
55 | 'ADD',
56 | 'ADMIN',
57 | 'ALL',
58 | 'ALTER',
59 | 'AND',
60 | 'ANY',
61 | 'AS',
62 | 'AT',
63 | 'AVG',
64 | 'BEGIN',
65 | 'BETWEEN',
66 | 'BIGINT',
67 | 'BIT_LENGTH',
68 | 'BLOB',
69 | 'BOTH',
70 | 'BOOLEAN',
71 | 'BY',
72 | 'CASE',
73 | 'CAST',
74 | 'CHAR',
75 | 'CHAR_LENGTH',
76 | 'CHARACTER',
77 | 'CHARACTER_LENGTH',
78 | 'CHECK',
79 | 'CLOSE',
80 | 'COLLATE',
81 | 'COLUMN',
82 | 'COMMIT',
83 | 'CONNECT',
84 | 'CONSTRAINT',
85 | 'CORR',
86 | 'COUNT',
87 | 'COVAR_POP',
88 | 'CREATE',
89 | 'CROSS',
90 | 'CURRENT',
91 | 'CURRENT_CONNECTION',
92 | 'CURRENT_DATE',
93 | 'CURRENT_ROLE',
94 | 'CURRENT_TIME',
95 | 'CURRENT_TIMESTAMP',
96 | 'CURRENT_TRANSACTION',
97 | 'CURRENT_USER',
98 | 'CURSOR',
99 | 'DATE',
100 | 'DAY',
101 | 'DEC',
102 | 'DECIMAL',
103 | 'DECLARE',
104 | 'DEFAULT',
105 | 'DELETE',
106 | 'DELETING',
107 | 'DETERMINISTIC',
108 | 'DISCONNECT',
109 | 'DISTINCT',
110 | 'DOUBLE',
111 | 'DROP',
112 | 'ELSE',
113 | 'END',
114 | 'ESCAPE',
115 | 'EXECUTE',
116 | 'EXISTS',
117 | 'EXTERNAL',
118 | 'EXRACT',
119 | 'FALSE',
120 | 'FETCH',
121 | 'FILTER',
122 | 'FLOAT',
123 | 'FOR',
124 | 'FOREIGN',
125 | 'FROM',
126 | 'FULL',
127 | 'FUNCTION',
128 | 'GDSCODE',
129 | 'GLOBAL',
130 | 'GRANT',
131 | 'GROUP',
132 | 'HAVING',
133 | 'HOUR',
134 | 'IN',
135 | 'INDEX',
136 | 'INNER',
137 | 'INSENSITIVE',
138 | 'INSERT',
139 | 'INSERTING',
140 | 'INT',
141 | 'INTEGER',
142 | 'INTO',
143 | 'IS',
144 | 'JOIN',
145 | 'LEADING',
146 | 'LEFT',
147 | 'LIKE',
148 | 'LONG',
149 | 'LOWER',
150 | 'MAX',
151 | 'MAXIMUM_SEGMENT',
152 | 'MERGE',
153 | 'MIN',
154 | 'MINUTE',
155 | 'MONTH',
156 | 'NATIONAL',
157 | 'NATURAL',
158 | 'NCHAR',
159 | 'NO',
160 | 'NOT',
161 | 'NULL',
162 | 'NUMERIC',
163 | 'OCTET_LENGTH',
164 | 'OF',
165 | 'OFFSET',
166 | 'ON',
167 | 'OPEN',
168 | 'OR',
169 | 'ORDER',
170 | 'OUTER',
171 | 'OVER',
172 | 'PARAMETER',
173 | 'PASSWORD',
174 | 'PLAN',
175 | 'POSITION',
176 | 'POST_EVENT',
177 | 'PRECISION',
178 | 'PRIMARY',
179 | 'PROCEDURE',
180 | 'RDB$DB_KEY',
181 | 'RDB$RECORD_VERSION',
182 | 'REAL',
183 | 'RECORD_VERSION',
184 | 'RECREATE',
185 | 'RECURSIVE',
186 | 'REFERENCES',
187 | 'REGR_AVGX',
188 | 'REGR_AVGY',
189 | 'REGR_COUNT',
190 | 'REGR_INTERCEPT',
191 | 'REGR_R2',
192 | 'REGR_SLOPE',
193 | 'REGR_SXX',
194 | 'REGR_SXY',
195 | 'REGR_SYY',
196 | 'RELEASE',
197 | 'RETURN',
198 | 'RETURNING_VALUES',
199 | 'RETURNS',
200 | 'REVOKE',
201 | 'RIGHT',
202 | 'ROLLBACK',
203 | 'ROW',
204 | 'ROWS',
205 | 'ROW_COUNT',
206 | 'SAVEPOINT',
207 | 'SCROLL',
208 | 'SECOND',
209 | 'SELECT',
210 | 'SENSITIVE',
211 | 'SET',
212 | 'SIMILAR',
213 | 'SOME',
214 | 'SQLCODE',
215 | 'SQLSTATE',
216 | 'START',
217 | 'STDDEV_POP',
218 | 'STDDEV_SAMP',
219 | 'SUM',
220 | 'TABLE',
221 | 'THEN',
222 | 'TIME',
223 | 'TIMESTAMP',
224 | 'TO',
225 | 'TRAILING',
226 | 'TRIGGER',
227 | 'TRIM',
228 | 'TRUE',
229 | 'UNION',
230 | 'UNIQUE',
231 | 'UNKNOWN',
232 | 'UPDATE',
233 | 'UPDATING',
234 | 'UPPER',
235 | 'USER',
236 | 'USING',
237 | 'VALUE',
238 | 'VALUES',
239 | 'VARCHAR',
240 | 'VARIABLE',
241 | 'VARYING',
242 | 'VAR_POP',
243 | 'VAR_SAMP',
244 | 'VIEW',
245 | 'WHEN',
246 | 'WHERE',
247 | 'WHILE',
248 | 'WITH',
249 | 'YEAR',
250 | ];
251 |
252 | /**
253 | * @var array mapping from physical column types (keys) to abstract column types (values)
254 | */
255 | public $typeMap = [
256 | 'bigint' => self::TYPE_BIGINT,
257 | 'char' => self::TYPE_CHAR,
258 | 'varchar' => self::TYPE_STRING,
259 | 'timestamp' => self::TYPE_TIMESTAMP,
260 | 'decimal' => self::TYPE_DECIMAL,
261 | 'float' => self::TYPE_FLOAT,
262 | 'blob' => self::TYPE_BINARY,
263 | 'integer' => self::TYPE_INTEGER,
264 | 'blob sub_type text' => self::TYPE_TEXT,
265 | 'numeric' => self::TYPE_DECIMAL,
266 | 'double precision' => self::TYPE_DOUBLE,
267 | 'smallint' => self::TYPE_SMALLINT,
268 | ];
269 |
270 | /**
271 | * {@inheritdoc}
272 | */
273 | protected function resolveTableName($name)
274 | {
275 | $resolvedName = new TableSchema();
276 | $this->resolveTableNames($resolvedName, $name);
277 | return $resolvedName;
278 | }
279 |
280 | /**
281 | * Creates a query builder for the database.
282 | * This method may be overridden by child classes to create a DBMS-specific query builder.
283 | * @return QueryBuilder query builder instance
284 | */
285 | public function createQueryBuilder()
286 | {
287 | return new QueryBuilder($this->db);
288 | }
289 |
290 | /**
291 | * @inheritdoc
292 | */
293 | public function createColumnSchemaBuilder($type, $length = null)
294 | {
295 | return new ColumnSchemaBuilder($type, $length);
296 | }
297 |
298 | public function quoteSimpleTableName($name)
299 | {
300 | if ($this->db->tablePrefix !== '') {
301 | return $name;
302 | }
303 |
304 | $word = strtoupper(str_replace('%', '', $name));
305 | if (in_array($word, $this->reservedWords)) {
306 | return strpos($name, '"') !== false ? $name : '"' . $name . '"';
307 | }
308 |
309 | return $name;
310 | }
311 |
312 | public function quoteSimpleColumnName($name)
313 | {
314 | if (in_array(strtoupper($name), $this->reservedWords)) {
315 | return parent::quoteSimpleColumnName($name);
316 | }
317 | return $name;
318 | }
319 |
320 | protected function loadTableSchema($name)
321 | {
322 | $table = $this->resolveTableName($name);
323 | if ($this->findColumns($table)) {
324 | $this->findConstraints($table);
325 | return $table;
326 | }
327 | return null;
328 | }
329 |
330 | public function getPdoType($data)
331 | {
332 | static $typeMap = [
333 | // php type => PDO type
334 | 'boolean' => \PDO::PARAM_INT,
335 | 'integer' => \PDO::PARAM_INT,
336 | 'string' => \PDO::PARAM_STR,
337 | 'resource' => \PDO::PARAM_LOB,
338 | 'NULL' => \PDO::PARAM_NULL,
339 | ];
340 | $type = gettype($data);
341 |
342 | return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
343 | }
344 |
345 | /**
346 | *
347 | * @param TableSchema $table
348 | * @param string $name
349 | */
350 | protected function resolveTableNames($table, $name)
351 | {
352 | $parts = explode('.', str_replace('"', '', $name));
353 | if (isset($parts[1])) {
354 | $table->schemaName = $parts[0];
355 | $table->name = strtolower($parts[1]);
356 | $table->fullName = $this->quoteTableName($table->schemaName) . '.' . $this->quoteTableName($table->name);
357 | } else {
358 | $table->name = strtolower($parts[0]);
359 | $table->fullName = $this->quoteTableName($table->name);
360 | }
361 | }
362 |
363 | /**
364 | * Collects the table column metadata.
365 | *
366 | * @param TableSchema $table the table metadata
367 | * @return boolean whether the table exists in the database
368 | */
369 | protected function findColumns($table)
370 | {
371 | // Zoggo - Converted sql to use join syntax
372 | // robregonm - Added isAutoInc
373 | $sql = 'SELECT
374 | rel.rdb$field_name AS fname,
375 | rel.rdb$default_source AS fdefault,
376 | fld.rdb$field_type AS fcodtype,
377 | fld.rdb$field_sub_type AS fcodsubtype,
378 | fld.rdb$field_length AS flength,
379 | fld.rdb$character_length AS fcharlength,
380 | fld.rdb$field_scale AS fscale,
381 | fld.rdb$field_precision AS fprecision,
382 | rel.rdb$null_flag AS fnull,
383 | rel.rdb$description AS fcomment,
384 | fld.rdb$default_value AS fdefault_value,';
385 |
386 | if ($this->db->supportColumnIdentity) {
387 | $sql .= '
388 | rel.rdb$generator_name AS fgenerator_name,';
389 | }
390 |
391 | $sql .= '
392 | (SELECT RDB$TRIGGER_SOURCE FROM RDB$TRIGGERS
393 | WHERE RDB$SYSTEM_FLAG = 0
394 | AND UPPER(RDB$RELATION_NAME)=UPPER(\'' . $table->name . '\')
395 | AND RDB$TRIGGER_TYPE = 1
396 | AND RDB$TRIGGER_INACTIVE = 0
397 | AND (UPPER(REPLACE(RDB$TRIGGER_SOURCE,\' \',\'\')) LIKE \'%NEW.\'||TRIM(rel.rdb$field_name)||\'=GEN_ID%\'
398 | OR UPPER(REPLACE(RDB$TRIGGER_SOURCE,\' \',\'\')) LIKE \'%NEW.\'||TRIM(rel.rdb$field_name)||\'=NEXTVALUEFOR%\'))
399 | AS fautoinc
400 | FROM
401 | rdb$relation_fields rel
402 | JOIN rdb$fields fld ON rel.rdb$field_source=fld.rdb$field_name
403 | WHERE
404 | UPPER(rel.rdb$relation_name)=UPPER(\'' . $table->name . '\')
405 | ORDER BY
406 | rel.rdb$field_position;';
407 | try {
408 | $columns = $this->db->createCommand($sql)->queryAll();
409 | if (empty($columns)) {
410 | return false;
411 | }
412 | } catch (Exception $e) {
413 | return false;
414 | }
415 | $sql = 'SELECT
416 | idx.rdb$field_name AS fname
417 | FROM
418 | rdb$relation_constraints rc
419 | JOIN rdb$index_segments idx ON idx.rdb$index_name=rc.rdb$index_name
420 | WHERE rc.rdb$constraint_type=\'PRIMARY KEY\'
421 | AND UPPER(rc.rdb$relation_name)=UPPER(\'' . $table->name . '\')';
422 | try {
423 | $pkeys = $this->db->createCommand($sql)->queryColumn();
424 | } catch (Exception $e) {
425 | return false;
426 | }
427 | $pkeys = array_map('rtrim', $pkeys);
428 | $pkeys = array_map('strtolower', $pkeys);
429 | foreach ($columns as $key => $column) {
430 | $column = array_map('strtolower', $column);
431 | $columns[$key]['fprimary'] = in_array(rtrim($column['fname']), $pkeys);
432 | }
433 | foreach ($columns as $column) {
434 | $c = $this->loadColumnSchema($column);
435 | if ($table->sequenceName === null && $c->autoIncrement) {
436 | $matches = [];
437 |
438 | if (isset($column['fgenerator_name']) && $column['fgenerator_name']) {
439 | $table->sequenceName = $column['fgenerator_name'];
440 | } elseif (preg_match("/NEW.{$c->name}\s*=\s*GEN_ID\((\w+)/i", $column['fautoinc'], $matches)) {
441 | $table->sequenceName = $matches[1];
442 | } elseif (preg_match("/NEW.{$c->name}\s*=\s*NEXT\s+VALUE\s+FOR\s+(\w+)/i", $column['fautoinc'], $matches)) {
443 | $table->sequenceName = $matches[1];
444 | }
445 | }
446 | $table->columns[$c->name] = $c;
447 | if ($c->isPrimaryKey) {
448 | $table->primaryKey[] = $c->name;
449 | }
450 | }
451 | return (count($table->columns) > 0);
452 | }
453 |
454 | /**
455 | * @return ColumnSchema
456 | * @throws \yii\base\InvalidConfigException
457 | */
458 | protected function createColumnSchema()
459 | {
460 | return \Yii::createObject('\edgardmessias\db\firebird\ColumnSchema');
461 | }
462 |
463 | /**
464 | * Creates a table column.
465 | *
466 | * @param array $column column metadata
467 | * @return ColumnSchema normalized column metadata
468 | */
469 | protected function loadColumnSchema($column)
470 | {
471 | $c = $this->createColumnSchema();
472 | $c->name = strtolower(rtrim($column['fname']));
473 | $c->allowNull = (int) $column['fnull'] !== 1;
474 | $c->isPrimaryKey = $column['fprimary'];
475 | $c->autoIncrement = (isset($column['fgenerator_name']) && $column['fgenerator_name']) || (boolean) $column['fautoinc'];
476 | $c->comment = $column['fcomment'] === null ? '' : $column['fcomment'];
477 |
478 | $c->type = self::TYPE_STRING;
479 |
480 | $defaultValue = null;
481 | if (!empty($column['fdefault'])) {
482 | // remove whitespace, 'DEFAULT ' prefix and surrounding single quotes; all optional
483 | if (preg_match("/\s*(DEFAULT\s+){0,1}('(.*)'|(.*))\s*/i", $column['fdefault'], $parts)) {
484 | $defaultValue = array_pop($parts);
485 | }
486 | // handle escaped single quotes like in "funny''quoted''string"
487 | $defaultValue = str_replace('\'\'', '\'', $defaultValue);
488 | }
489 | if ($defaultValue === null) {
490 | $defaultValue = $column['fdefault_value'];
491 | }
492 | $dbType = '';
493 | $baseTypes = [
494 | 7 => 'SMALLINT',
495 | 8 => 'INTEGER',
496 | 16 => 'INT64',
497 | 9 => 'QUAD',
498 | 10 => 'FLOAT',
499 | 11 => 'D_FLOAT',
500 | 17 => 'BOOLEAN',
501 | 27 => 'DOUBLE PRECISION',
502 | 12 => 'DATE',
503 | 13 => 'TIME',
504 | 35 => 'TIMESTAMP',
505 | 261 => 'BLOB',
506 | 40 => 'CSTRING',
507 | 45 => 'BLOB_ID',
508 | ];
509 | $baseCharTypes = [
510 | 37 => 'VARCHAR',
511 | 14 => 'CHAR',
512 | ];
513 | if (array_key_exists((int) $column['fcodtype'], $baseTypes)) {
514 | $dbType = $baseTypes[(int) $column['fcodtype']];
515 | } elseif (array_key_exists((int) $column['fcodtype'], $baseCharTypes)) {
516 | $c->size = (int) $column['fcharlength'];
517 | $c->precision = $c->size;
518 | $dbType = $baseCharTypes[(int) $column['fcodtype']] . "($c->size)";
519 | }
520 | switch ((int) $column['fcodtype']) {
521 | case 7:
522 | case 8:
523 | switch ((int) $column['fcodsubtype']) {
524 | case 1:
525 | $c->precision = (int) $column['fprecision'];
526 | $c->size = $c->precision;
527 | $c->scale = abs((int) $column['fscale']);
528 | $dbType = "NUMERIC({$c->precision},{$c->scale})";
529 | break;
530 | case 2:
531 | $c->precision = (int) $column['fprecision'];
532 | $c->size = $c->precision;
533 | $c->scale = abs((int) $column['fscale']);
534 | $dbType = "DECIMAL({$c->precision},{$c->scale})";
535 | break;
536 | }
537 | break;
538 | case 16:
539 | switch ((int) $column['fcodsubtype']) {
540 | case 1:
541 | $c->precision = (int) $column['fprecision'];
542 | $c->size = $c->precision;
543 | $c->scale = abs((int) $column['fscale']);
544 | $dbType = "NUMERIC({$c->precision},{$c->scale})";
545 | break;
546 | case 2:
547 | $c->precision = (int) $column['fprecision'];
548 | $c->size = $c->precision;
549 | $c->scale = abs((int) $column['fscale']);
550 | $dbType = "DECIMAL({$c->precision},{$c->scale})";
551 | break;
552 | default:
553 | $dbType = 'BIGINT';
554 | break;
555 | }
556 | break;
557 | case 261:
558 | switch ((int) $column['fcodsubtype']) {
559 | case 1:
560 | $dbType = 'BLOB SUB_TYPE TEXT';
561 | $c->size = null;
562 | break;
563 | }
564 | break;
565 | }
566 |
567 | $c->dbType = strtolower($dbType);
568 |
569 | $c->type = self::TYPE_STRING;
570 | if (preg_match('/^([\w\ ]+)(?:\(([^\)]+)\))?/', $c->dbType, $matches)) {
571 | $type = strtolower($matches[1]);
572 | if (isset($this->typeMap[$type])) {
573 | $c->type = $this->typeMap[$type];
574 | }
575 | }
576 |
577 |
578 | $c->phpType = $this->getColumnPhpType($c);
579 |
580 | $c->defaultValue = null;
581 | if ($defaultValue !== null) {
582 | if (in_array($c->type, [self::TYPE_DATE, self::TYPE_DATETIME, self::TYPE_TIME, self::TYPE_TIMESTAMP])
583 | && preg_match('/(CURRENT_|NOW|NULL|TODAY|TOMORROW|YESTERDAY)/i', $defaultValue)) {
584 | $c->defaultValue = new Expression(trim($defaultValue));
585 | } else {
586 | $c->defaultValue = $c->phpTypecast($defaultValue);
587 | }
588 | }
589 |
590 | return $c;
591 | }
592 |
593 | /**
594 | * Collects the foreign key column details for the given table.
595 | *
596 | * @param TableSchema $table the table metadata
597 | */
598 | protected function findConstraints($table)
599 | {
600 | // Zoggo - Converted sql to use join syntax
601 | $sql = 'SELECT
602 | a.rdb$constraint_name as fconstraint,
603 | c.rdb$relation_name AS ftable,
604 | d.rdb$field_name AS pfield,
605 | e.rdb$field_name AS ffield
606 | FROM
607 | rdb$ref_constraints b
608 | JOIN rdb$relation_constraints a ON a.rdb$constraint_name=b.rdb$constraint_name
609 | JOIN rdb$relation_constraints c ON b.rdb$const_name_uq=c.rdb$constraint_name
610 | JOIN rdb$index_segments d ON c.rdb$index_name=d.rdb$index_name
611 | JOIN rdb$index_segments e ON a.rdb$index_name=e.rdb$index_name AND e.rdb$field_position = d.rdb$field_position
612 | WHERE
613 | a.rdb$constraint_type=\'FOREIGN KEY\' AND
614 | UPPER(a.rdb$relation_name)=UPPER(\'' . $table->name . '\') ';
615 | try {
616 | $fkeys = $this->db->createCommand($sql)->queryAll();
617 | } catch (Exception $e) {
618 | return false;
619 | }
620 |
621 | $constraints = [];
622 | foreach ($fkeys as $fkey) {
623 | // Zoggo - Added strtolower here to guarantee that values are
624 | // returned lower case. Otherwise gii generates wrong code.
625 | $fkey = array_map('rtrim', $fkey);
626 | $fkey = array_map('strtolower', $fkey);
627 |
628 | if (!isset($constraints[$fkey['fconstraint']])) {
629 | $constraints[$fkey['fconstraint']] = [
630 | $fkey['ftable']
631 | ];
632 | }
633 | $constraints[$fkey['fconstraint']][$fkey['ffield']] = $fkey['pfield'];
634 | }
635 | $table->foreignKeys = $constraints;
636 | }
637 |
638 | protected function findTableNames($schema = '')
639 | {
640 | $sql = 'SELECT
641 | rdb$relation_name
642 | FROM
643 | rdb$relations
644 | WHERE
645 | (rdb$system_flag is null OR rdb$system_flag=0)';
646 | try {
647 | $tables = $this->db->createCommand($sql)->queryColumn();
648 | } catch (Exception $e) {
649 | return false;
650 | }
651 |
652 | $tables = array_map('rtrim', $tables);
653 | $tables = array_map('strtolower', $tables);
654 |
655 | return $tables;
656 | }
657 |
658 | /**
659 | * Returns all unique indexes for the given table.
660 | * Each array element is of the following structure:
661 | *
662 | * ~~~
663 | * [
664 | * 'IndexName1' => ['col1' [, ...]],
665 | * 'IndexName2' => ['col2' [, ...]],
666 | * ]
667 | * ~~~
668 | *
669 | * @param TableSchema $table the table metadata
670 | * @return array all unique indexes for the given table.
671 | * @since 2.0.4
672 | */
673 | public function findUniqueIndexes($table)
674 | {
675 | $query = '
676 | SELECT id.RDB$INDEX_NAME as index_name, ids.RDB$FIELD_NAME as column_name
677 | FROM RDB$INDICES id
678 | INNER JOIN RDB$INDEX_SEGMENTS ids ON ids.RDB$INDEX_NAME = id.RDB$INDEX_NAME
679 | WHERE id.RDB$UNIQUE_FLAG = 1
680 | AND id.RDB$SYSTEM_FLAG = 0
681 | AND UPPER(id.RDB$RELATION_NAME) = UPPER(\'' . $table->name . '\')
682 | ORDER BY id.RDB$RELATION_NAME, id.RDB$INDEX_NAME, ids.RDB$FIELD_POSITION';
683 | $result = [];
684 | $command = $this->db->createCommand($query);
685 | foreach ($command->queryAll() as $row) {
686 | $result[strtolower(rtrim($row['index_name']))][] = strtolower(rtrim($row['column_name']));
687 | }
688 | return $result;
689 | }
690 |
691 | /**
692 | * Sets the isolation level of the current transaction.
693 | * @param string $level The transaction isolation level to use for this transaction.
694 | * This can be one of [[Transaction::READ_UNCOMMITTED]], [[Transaction::READ_COMMITTED]], [[Transaction::REPEATABLE_READ]]
695 | * and [[Transaction::SERIALIZABLE]] but also a string containing DBMS specific syntax to be used
696 | * after `SET TRANSACTION ISOLATION LEVEL`.
697 | * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
698 | */
699 | public function setTransactionIsolationLevel($level)
700 | {
701 | if ($level == Transaction::READ_UNCOMMITTED) {
702 | parent::setTransactionIsolationLevel('READ COMMITTED RECORD_VERSION');
703 | } elseif ($level == Transaction::REPEATABLE_READ) {
704 | parent::setTransactionIsolationLevel('SNAPSHOT');
705 | } elseif ($level == Transaction::SERIALIZABLE) {
706 | parent::setTransactionIsolationLevel('SNAPSHOT TABLE STABILITY');
707 | } else {
708 | parent::setTransactionIsolationLevel($level);
709 | }
710 | }
711 |
712 | /**
713 | * @inheritdoc
714 | */
715 | public function insert($table, $columns)
716 | {
717 | $this->_lastInsertID = false;
718 | $params = [];
719 | $sql = "";
720 | $returnColumns = $this->getTableSchema($table)->primaryKey;
721 | if (!empty($returnColumns)) {
722 | if (!$this->db->supportReturningInsert) {
723 | $returs = [];
724 | $returning = [];
725 | $columnSchemas = $this->getTableSchema($table)->columns;
726 | foreach ((array) $returnColumns as $name) {
727 | $returs[] = $this->quoteColumnName($name) . ' ' . $columnSchemas[$name]->dbType;
728 | $returning[] = $this->quoteColumnName($name);
729 | }
730 |
731 | $sql = $this->db->getQueryBuilder()->rawInsert($table, array_keys($columns), array_values($columns), $params);
732 |
733 | $sql = "EXECUTE block RETURNS ("
734 | . implode(', ',$returs)
735 | . ") AS BEGIN\n"
736 | . $sql . ' RETURNING ' . implode(', ', $returning)
737 | . ' INTO ' . implode(', ', $returning)
738 | . ";\nSUSPEND;\nEND;";
739 | } else {
740 | $sql = $this->db->getQueryBuilder()->insert($table, $columns, $params);
741 | $returning = [];
742 | foreach ((array) $returnColumns as $name) {
743 | $returning[] = $this->quoteColumnName($name);
744 | }
745 | $sql .= ' RETURNING ' . implode(', ', $returning);
746 | }
747 | }
748 |
749 | $command = $this->db->createCommand($sql, $params);
750 | $command->prepare(false);
751 | $result = $command->queryOne();
752 |
753 | if (!$command->pdoStatement->rowCount()) {
754 | return false;
755 | } else {
756 | if (!empty($returnColumns)) {
757 | foreach ((array) $returnColumns as $name) {
758 | if ($this->getTableSchema($table)->getColumn($name)->autoIncrement) {
759 | $this->_lastInsertID = $result[$name];
760 | break;
761 | }
762 | }
763 | }
764 | return $result;
765 | }
766 | }
767 |
768 | /**
769 | * @inheritdoc
770 | */
771 | public function getLastInsertID($sequenceName = '')
772 | {
773 | if (!$this->db->isActive) {
774 | throw new InvalidCallException('DB Connection is not active.');
775 | }
776 |
777 | if ($sequenceName !== '') {
778 | return $this->db->createCommand('SELECT GEN_ID(' . $this->db->quoteTableName($sequenceName) . ', 0 ) FROM RDB$DATABASE;')->queryScalar();
779 | }
780 |
781 | if ($this->_lastInsertID !== false) {
782 | return $this->_lastInsertID;
783 | }
784 | return null;
785 | }
786 |
787 | protected function loadTablePrimaryKey($tableName)
788 | {
789 | static $sql = <<<'SQL'
790 | SELECT RC.RDB$CONSTRAINT_NAME AS NAME, IDX.RDB$FIELD_NAME AS COLUMN_NAME
791 | FROM RDB$RELATION_CONSTRAINTS RC
792 | JOIN RDB$INDEX_SEGMENTS IDX
793 | ON IDX.RDB$INDEX_NAME = RC.RDB$INDEX_NAME
794 | WHERE RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY'
795 | AND UPPER(RC.RDB$RELATION_NAME) = UPPER(:tableName)
796 | ORDER BY IDX.RDB$FIELD_POSITION
797 | SQL;
798 |
799 | $resolvedName = $this->resolveTableName($tableName);
800 | $constraints = $this->db->createCommand($sql, [
801 | ':tableName' => $resolvedName->name,
802 | ])->queryAll();
803 | $constraints = $this->normalizePdoRowKeyCase($constraints, true);
804 | $constraints = ArrayHelper::index($constraints, null, ['name']);
805 |
806 | foreach ($constraints as $name => $constraint) {
807 | $columns = ArrayHelper::getColumn($constraint, 'column_name');
808 | $columns = array_map('trim', $columns);
809 | $columns = array_map('strtolower', $columns);
810 | return new Constraint([
811 | 'name' => strtolower(trim($name)),
812 | 'columnNames' => $columns,
813 | ]);
814 | }
815 |
816 | return null;
817 | }
818 |
819 | protected function loadTableUniques($tableName)
820 | {
821 | static $sql = <<<'SQL'
822 | SELECT RC.RDB$CONSTRAINT_NAME AS NAME, IDX.RDB$FIELD_NAME AS COLUMN_NAME
823 | FROM RDB$RELATION_CONSTRAINTS RC
824 | JOIN RDB$INDEX_SEGMENTS IDX
825 | ON IDX.RDB$INDEX_NAME = RC.RDB$INDEX_NAME
826 | WHERE RC.RDB$CONSTRAINT_TYPE = 'UNIQUE'
827 | AND UPPER(RC.RDB$RELATION_NAME) = UPPER(:tableName)
828 | ORDER BY IDX.RDB$FIELD_POSITION
829 | SQL;
830 |
831 | $resolvedName = $this->resolveTableName($tableName);
832 | $constraints = $this->db->createCommand($sql, [
833 | ':tableName' => $resolvedName->name,
834 | ])->queryAll();
835 | $constraints = $this->normalizePdoRowKeyCase($constraints, true);
836 | $constraints = ArrayHelper::index($constraints, null, ['name']);
837 |
838 | $result = [];
839 | foreach ($constraints as $name => $rows) {
840 | $columns = ArrayHelper::getColumn($rows, 'column_name');
841 | $columns = array_map('trim', $columns);
842 | $columns = array_map('strtolower', $columns);
843 | $result[] = new Constraint([
844 | 'name' => strtolower(trim($name)),
845 | 'columnNames' => $columns,
846 | ]);
847 | }
848 |
849 | return $result;
850 | }
851 |
852 | protected function loadTableChecks($tableName)
853 | {
854 | // DISTINCT not work on blob, need cast to varchar
855 | // 8191 Is max for UTF-8
856 | static $sql = <<<'SQL'
857 | SELECT DISTINCT RC.RDB$CONSTRAINT_NAME AS NAME,
858 | DEP.RDB$FIELD_NAME AS COLUMN_NAME,
859 | CAST(TRIG.RDB$TRIGGER_SOURCE AS VARCHAR(8191)) AS CHECK_EXPR
860 | FROM RDB$RELATION_CONSTRAINTS RC
861 | JOIN RDB$CHECK_CONSTRAINTS CH_CONST
862 | ON CH_CONST.RDB$CONSTRAINT_NAME = RC.RDB$CONSTRAINT_NAME
863 | JOIN RDB$TRIGGERS TRIG
864 | ON TRIG.RDB$TRIGGER_NAME = CH_CONST.RDB$TRIGGER_NAME
865 | JOIN RDB$DEPENDENCIES DEP
866 | ON DEP.RDB$DEPENDENT_NAME = TRIG.RDB$TRIGGER_NAME
867 | AND DEP.RDB$DEPENDED_ON_NAME = TRIG.RDB$RELATION_NAME
868 | WHERE RC.RDB$CONSTRAINT_TYPE = 'CHECK'
869 | AND UPPER(RC.RDB$RELATION_NAME) = UPPER(:tableName)
870 | SQL;
871 |
872 | $resolvedName = $this->resolveTableName($tableName);
873 | $constraints = $this->db->createCommand($sql, [
874 | ':tableName' => $resolvedName->name,
875 | ])->queryAll();
876 | $constraints = $this->normalizePdoRowKeyCase($constraints, true);
877 | $constraints = ArrayHelper::index($constraints, null, ['name']);
878 |
879 | $result = [];
880 | foreach ($constraints as $name => $constraint) {
881 | $columns = ArrayHelper::getColumn($constraint, 'column_name');
882 | $columns = array_map('trim', $columns);
883 | $columns = array_map('strtolower', $columns);
884 |
885 | $check_expr = $constraint[0]['check_expr'];
886 | $check_expr = preg_replace('/^\s*CHECK\s*/i', '', $check_expr); // remove "CHECK " at begin
887 | $check_expr = preg_replace('/^\((.*)\)$/i', '\1', $check_expr); // remove bracket () at begin and end
888 |
889 | $result[] = new CheckConstraint([
890 | 'name' => strtolower(trim($name)),
891 | 'columnNames' => $columns,
892 | 'expression' => $check_expr,
893 | ]);
894 | }
895 |
896 | return $result;
897 | }
898 |
899 | protected function loadTableIndexes($tableName)
900 | {
901 | static $sql = <<<'SQL'
902 | SELECT IDX.RDB$INDEX_NAME AS NAME,
903 | SEG.RDB$FIELD_NAME AS COLUMN_NAME,
904 | IDX.RDB$UNIQUE_FLAG AS INDEX_IS_UNIQUE,
905 | CASE WHEN CONST.RDB$CONSTRAINT_NAME IS NOT NULL THEN 1 ELSE 0 END AS INDEX_IS_PRIMARY
906 | FROM RDB$INDICES IDX
907 | JOIN RDB$INDEX_SEGMENTS SEG
908 | LEFT JOIN RDB$RELATION_CONSTRAINTS CONST ON CONST.RDB$INDEX_NAME = SEG.RDB$INDEX_NAME AND CONST.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY'
909 | ON SEG.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME
910 | WHERE UPPER(IDX.RDB$RELATION_NAME) = UPPER(:tableName)
911 | ORDER BY SEG.RDB$FIELD_POSITION
912 | SQL;
913 |
914 | $resolvedName = $this->resolveTableName($tableName);
915 | $indexes = $this->db->createCommand($sql, [
916 | ':tableName' => $resolvedName->name,
917 | ])->queryAll();
918 | $indexes = $this->normalizePdoRowKeyCase($indexes, true);
919 | $indexes = ArrayHelper::index($indexes, null, 'name');
920 | $result = [];
921 | foreach ($indexes as $name => $index) {
922 | $columns = ArrayHelper::getColumn($index, 'column_name');
923 | $columns = array_map('trim', $columns);
924 | $columns = array_map('strtolower', $columns);
925 |
926 | $result[] = new IndexConstraint([
927 | 'isPrimary' => (bool) $index[0]['index_is_primary'],
928 | 'isUnique' => (bool) $index[0]['index_is_unique'],
929 | 'name' => strtolower(trim($name)),
930 | 'columnNames' => $columns,
931 | ]);
932 | }
933 |
934 | return $result;
935 | }
936 |
937 | protected function loadTableDefaultValues($tableName)
938 | {
939 | throw new \yii\base\NotSupportedException('FirebirdSQL does not support default value constraints.');
940 | }
941 |
942 | protected function loadTableForeignKeys($tableName)
943 | {
944 | static $sql = <<<'SQL'
945 | SELECT A.RDB$CONSTRAINT_NAME AS NAME,
946 | E.RDB$FIELD_NAME AS COLUMN_NAME,
947 | C.RDB$RELATION_NAME AS FOREIGN_TABLE_NAME,
948 | D.RDB$FIELD_NAME AS FOREIGN_COLUMN_NAME,
949 | B.RDB$UPDATE_RULE AS ON_UPDATE,
950 | B.RDB$DELETE_RULE AS ON_DELETE
951 | FROM RDB$REF_CONSTRAINTS B
952 | JOIN RDB$RELATION_CONSTRAINTS A
953 | ON A.RDB$CONSTRAINT_NAME = B.RDB$CONSTRAINT_NAME
954 | JOIN RDB$RELATION_CONSTRAINTS C
955 | ON B.RDB$CONST_NAME_UQ = C.RDB$CONSTRAINT_NAME
956 | JOIN RDB$INDEX_SEGMENTS D
957 | ON C.RDB$INDEX_NAME = D.RDB$INDEX_NAME
958 | JOIN RDB$INDEX_SEGMENTS E
959 | ON A.RDB$INDEX_NAME = E.RDB$INDEX_NAME
960 | AND E.RDB$FIELD_POSITION = D.RDB$FIELD_POSITION
961 | WHERE A.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY'
962 | AND UPPER(A.RDB$RELATION_NAME) = UPPER(:tableName)
963 | ORDER BY E.RDB$FIELD_POSITION
964 | SQL;
965 |
966 | $resolvedName = $this->resolveTableName($tableName);
967 | $constraints = $this->db->createCommand($sql, [
968 | ':tableName' => $resolvedName->name,
969 | ])->queryAll();
970 | $constraints = $this->normalizePdoRowKeyCase($constraints, true);
971 | $constraints = ArrayHelper::index($constraints, null, ['name']);
972 |
973 | $result = [];
974 | foreach ($constraints as $name => $constraint) {
975 | $columnNames = ArrayHelper::getColumn($constraint, 'column_name');
976 | $columnNames = array_map('trim', $columnNames);
977 | $columnNames = array_map('strtolower', $columnNames);
978 |
979 | $foreignColumnNames = ArrayHelper::getColumn($constraint, 'foreign_column_name');
980 | $foreignColumnNames = array_map('trim', $foreignColumnNames);
981 | $foreignColumnNames = array_map('strtolower', $foreignColumnNames);
982 |
983 | $result[] = new ForeignKeyConstraint([
984 | 'name' => strtolower(trim($name)),
985 | 'columnNames' => $columnNames,
986 | 'foreignTableName' => strtolower(trim($constraint[0]['foreign_table_name'])),
987 | 'foreignColumnNames' => $foreignColumnNames,
988 | 'onDelete' => trim($constraint[0]['on_delete']),
989 | 'onUpdate' => trim($constraint[0]['on_update']),
990 | ]);
991 | }
992 |
993 | return $result;
994 | }
995 |
996 | protected function findViewNames($schema = '')
997 | {
998 | $sql = <<<'SQL'
999 | SELECT RDB$RELATION_NAME
1000 | FROM RDB$RELATIONS
1001 | WHERE RDB$VIEW_BLR IS NOT NULL
1002 | AND (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0)
1003 | SQL;
1004 |
1005 | $views = $this->db->createCommand($sql)->queryColumn();
1006 | $views = array_map('trim', $views);
1007 | $views = array_map('strtolower', $views);
1008 |
1009 | return $views;
1010 | }
1011 | }
1012 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "5aaeea677f3ba305bc64ad566e0d7c14",
8 | "packages": [
9 | {
10 | "name": "bower-asset/inputmask",
11 | "version": "3.3.11",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/RobinHerbots/Inputmask.git",
15 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b",
20 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "bower-asset/jquery": ">=1.7"
25 | },
26 | "type": "bower-asset-library",
27 | "extra": {
28 | "bower-asset-main": [
29 | "./dist/inputmask/inputmask.js",
30 | "./dist/inputmask/inputmask.extensions.js",
31 | "./dist/inputmask/inputmask.date.extensions.js",
32 | "./dist/inputmask/inputmask.numeric.extensions.js",
33 | "./dist/inputmask/inputmask.phone.extensions.js",
34 | "./dist/inputmask/jquery.inputmask.js",
35 | "./dist/inputmask/global/document.js",
36 | "./dist/inputmask/global/window.js",
37 | "./dist/inputmask/phone-codes/phone.js",
38 | "./dist/inputmask/phone-codes/phone-be.js",
39 | "./dist/inputmask/phone-codes/phone-nl.js",
40 | "./dist/inputmask/phone-codes/phone-ru.js",
41 | "./dist/inputmask/phone-codes/phone-uk.js",
42 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jqlite.js",
43 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jquery.js",
44 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.js",
45 | "./dist/inputmask/bindings/inputmask.binding.js"
46 | ],
47 | "bower-asset-ignore": [
48 | "**/*",
49 | "!dist/*",
50 | "!dist/inputmask/*",
51 | "!dist/min/*",
52 | "!dist/min/inputmask/*"
53 | ]
54 | },
55 | "license": [
56 | "http://opensource.org/licenses/mit-license.php"
57 | ],
58 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.",
59 | "keywords": [
60 | "form",
61 | "input",
62 | "inputmask",
63 | "jquery",
64 | "mask",
65 | "plugins"
66 | ],
67 | "time": "2017-11-21T11:46:23+00:00"
68 | },
69 | {
70 | "name": "bower-asset/jquery",
71 | "version": "3.2.1",
72 | "source": {
73 | "type": "git",
74 | "url": "https://github.com/jquery/jquery-dist.git",
75 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e"
76 | },
77 | "dist": {
78 | "type": "zip",
79 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/77d2a51d0520d2ee44173afdf4e40a9201f5964e",
80 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e",
81 | "shasum": ""
82 | },
83 | "type": "bower-asset-library",
84 | "extra": {
85 | "bower-asset-main": "dist/jquery.js",
86 | "bower-asset-ignore": [
87 | "package.json"
88 | ]
89 | },
90 | "license": [
91 | "MIT"
92 | ],
93 | "keywords": [
94 | "browser",
95 | "javascript",
96 | "jquery",
97 | "library"
98 | ],
99 | "time": "2017-03-20T19:02:00+00:00"
100 | },
101 | {
102 | "name": "bower-asset/punycode",
103 | "version": "v1.3.2",
104 | "source": {
105 | "type": "git",
106 | "url": "https://github.com/bestiejs/punycode.js.git",
107 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
108 | },
109 | "dist": {
110 | "type": "zip",
111 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
112 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
113 | "shasum": ""
114 | },
115 | "type": "bower-asset-library",
116 | "extra": {
117 | "bower-asset-main": "punycode.js",
118 | "bower-asset-ignore": [
119 | "coverage",
120 | "tests",
121 | ".*",
122 | "component.json",
123 | "Gruntfile.js",
124 | "node_modules",
125 | "package.json"
126 | ]
127 | }
128 | },
129 | {
130 | "name": "bower-asset/yii2-pjax",
131 | "version": "2.0.7.1",
132 | "source": {
133 | "type": "git",
134 | "url": "https://github.com/yiisoft/jquery-pjax.git",
135 | "reference": "aef7b953107264f00234902a3880eb50dafc48be"
136 | },
137 | "dist": {
138 | "type": "zip",
139 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/aef7b953107264f00234902a3880eb50dafc48be",
140 | "reference": "aef7b953107264f00234902a3880eb50dafc48be",
141 | "shasum": ""
142 | },
143 | "require": {
144 | "bower-asset/jquery": ">=1.8"
145 | },
146 | "type": "bower-asset-library",
147 | "extra": {
148 | "bower-asset-main": "./jquery.pjax.js",
149 | "bower-asset-ignore": [
150 | ".travis.yml",
151 | "Gemfile",
152 | "Gemfile.lock",
153 | "CONTRIBUTING.md",
154 | "vendor/",
155 | "script/",
156 | "test/"
157 | ]
158 | },
159 | "license": [
160 | "MIT"
161 | ],
162 | "time": "2017-10-12T10:11:14+00:00"
163 | },
164 | {
165 | "name": "cebe/markdown",
166 | "version": "1.1.2",
167 | "source": {
168 | "type": "git",
169 | "url": "https://github.com/cebe/markdown.git",
170 | "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e"
171 | },
172 | "dist": {
173 | "type": "zip",
174 | "url": "https://api.github.com/repos/cebe/markdown/zipball/25b28bae8a6f185b5030673af77b32e1163d5c6e",
175 | "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e",
176 | "shasum": ""
177 | },
178 | "require": {
179 | "lib-pcre": "*",
180 | "php": ">=5.4.0"
181 | },
182 | "require-dev": {
183 | "cebe/indent": "*",
184 | "facebook/xhprof": "*@dev",
185 | "phpunit/phpunit": "4.1.*"
186 | },
187 | "bin": [
188 | "bin/markdown"
189 | ],
190 | "type": "library",
191 | "extra": {
192 | "branch-alias": {
193 | "dev-master": "1.1.x-dev"
194 | }
195 | },
196 | "autoload": {
197 | "psr-4": {
198 | "cebe\\markdown\\": ""
199 | }
200 | },
201 | "notification-url": "https://packagist.org/downloads/",
202 | "license": [
203 | "MIT"
204 | ],
205 | "authors": [
206 | {
207 | "name": "Carsten Brandt",
208 | "email": "mail@cebe.cc",
209 | "homepage": "http://cebe.cc/",
210 | "role": "Creator"
211 | }
212 | ],
213 | "description": "A super fast, highly extensible markdown parser for PHP",
214 | "homepage": "https://github.com/cebe/markdown#readme",
215 | "keywords": [
216 | "extensible",
217 | "fast",
218 | "gfm",
219 | "markdown",
220 | "markdown-extra"
221 | ],
222 | "time": "2017-07-16T21:13:23+00:00"
223 | },
224 | {
225 | "name": "ezyang/htmlpurifier",
226 | "version": "v4.10.0",
227 | "source": {
228 | "type": "git",
229 | "url": "https://github.com/ezyang/htmlpurifier.git",
230 | "reference": "d85d39da4576a6934b72480be6978fb10c860021"
231 | },
232 | "dist": {
233 | "type": "zip",
234 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021",
235 | "reference": "d85d39da4576a6934b72480be6978fb10c860021",
236 | "shasum": ""
237 | },
238 | "require": {
239 | "php": ">=5.2"
240 | },
241 | "require-dev": {
242 | "simpletest/simpletest": "^1.1"
243 | },
244 | "type": "library",
245 | "autoload": {
246 | "psr-0": {
247 | "HTMLPurifier": "library/"
248 | },
249 | "files": [
250 | "library/HTMLPurifier.composer.php"
251 | ]
252 | },
253 | "notification-url": "https://packagist.org/downloads/",
254 | "license": [
255 | "LGPL"
256 | ],
257 | "authors": [
258 | {
259 | "name": "Edward Z. Yang",
260 | "email": "admin@htmlpurifier.org",
261 | "homepage": "http://ezyang.com"
262 | }
263 | ],
264 | "description": "Standards compliant HTML filter written in PHP",
265 | "homepage": "http://htmlpurifier.org/",
266 | "keywords": [
267 | "html"
268 | ],
269 | "time": "2018-02-23T01:58:20+00:00"
270 | },
271 | {
272 | "name": "yiisoft/yii2-composer",
273 | "version": "2.0.6",
274 | "source": {
275 | "type": "git",
276 | "url": "https://github.com/yiisoft/yii2-composer.git",
277 | "reference": "163419f1f197e02f015713b0d4f85598d8f8aa80"
278 | },
279 | "dist": {
280 | "type": "zip",
281 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/163419f1f197e02f015713b0d4f85598d8f8aa80",
282 | "reference": "163419f1f197e02f015713b0d4f85598d8f8aa80",
283 | "shasum": ""
284 | },
285 | "require": {
286 | "composer-plugin-api": "^1.0"
287 | },
288 | "require-dev": {
289 | "composer/composer": "^1.0"
290 | },
291 | "type": "composer-plugin",
292 | "extra": {
293 | "class": "yii\\composer\\Plugin",
294 | "branch-alias": {
295 | "dev-master": "2.0.x-dev"
296 | }
297 | },
298 | "autoload": {
299 | "psr-4": {
300 | "yii\\composer\\": ""
301 | }
302 | },
303 | "notification-url": "https://packagist.org/downloads/",
304 | "license": [
305 | "BSD-3-Clause"
306 | ],
307 | "authors": [
308 | {
309 | "name": "Qiang Xue",
310 | "email": "qiang.xue@gmail.com"
311 | },
312 | {
313 | "name": "Carsten Brandt",
314 | "email": "mail@cebe.cc"
315 | }
316 | ],
317 | "description": "The composer plugin for Yii extension installer",
318 | "keywords": [
319 | "composer",
320 | "extension installer",
321 | "yii2"
322 | ],
323 | "time": "2018-03-21T16:15:55+00:00"
324 | },
325 | {
326 | "name": "yiisoft/yii2-dev",
327 | "version": "2.0.15.1",
328 | "source": {
329 | "type": "git",
330 | "url": "https://github.com/yiisoft/yii2.git",
331 | "reference": "20aa5080189cbacd4180d3b115752817921eb364"
332 | },
333 | "dist": {
334 | "type": "zip",
335 | "url": "https://api.github.com/repos/yiisoft/yii2/zipball/20aa5080189cbacd4180d3b115752817921eb364",
336 | "reference": "20aa5080189cbacd4180d3b115752817921eb364",
337 | "shasum": ""
338 | },
339 | "require": {
340 | "bower-asset/inputmask": "~3.2.2 | ~3.3.5",
341 | "bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
342 | "bower-asset/punycode": "1.3.*",
343 | "bower-asset/yii2-pjax": "~2.0.1",
344 | "cebe/markdown": "~1.0.0 | ~1.1.0",
345 | "ext-ctype": "*",
346 | "ext-mbstring": "*",
347 | "ezyang/htmlpurifier": "~4.6",
348 | "lib-pcre": "*",
349 | "php": ">=5.4.0",
350 | "yiisoft/yii2-composer": "~2.0.4"
351 | },
352 | "replace": {
353 | "yiisoft/yii2": "self.version"
354 | },
355 | "require-dev": {
356 | "cebe/indent": "~1.0.2",
357 | "friendsofphp/php-cs-fixer": "~2.2.3",
358 | "phpunit/phpunit": "4.8.34"
359 | },
360 | "suggest": {
361 | "yiisoft/yii2-coding-standards": "you can use this package to check for code style issues when contributing to yii"
362 | },
363 | "bin": [
364 | "framework/yii"
365 | ],
366 | "type": "yii2-extension",
367 | "extra": {
368 | "branch-alias": {
369 | "dev-master": "2.0.x-dev"
370 | }
371 | },
372 | "autoload": {
373 | "psr-4": {
374 | "yii\\": "framework/",
375 | "yii\\cs\\": "cs/src/"
376 | }
377 | },
378 | "notification-url": "https://packagist.org/downloads/",
379 | "license": [
380 | "BSD-3-Clause"
381 | ],
382 | "authors": [
383 | {
384 | "name": "Qiang Xue",
385 | "email": "qiang.xue@gmail.com",
386 | "homepage": "http://www.yiiframework.com/",
387 | "role": "Founder and project lead"
388 | },
389 | {
390 | "name": "Alexander Makarov",
391 | "email": "sam@rmcreative.ru",
392 | "homepage": "http://rmcreative.ru/",
393 | "role": "Core framework development"
394 | },
395 | {
396 | "name": "Maurizio Domba",
397 | "homepage": "http://mdomba.info/",
398 | "role": "Core framework development"
399 | },
400 | {
401 | "name": "Carsten Brandt",
402 | "email": "mail@cebe.cc",
403 | "homepage": "http://cebe.cc/",
404 | "role": "Core framework development"
405 | },
406 | {
407 | "name": "Timur Ruziev",
408 | "email": "resurtm@gmail.com",
409 | "homepage": "http://resurtm.com/",
410 | "role": "Core framework development"
411 | },
412 | {
413 | "name": "Paul Klimov",
414 | "email": "klimov.paul@gmail.com",
415 | "role": "Core framework development"
416 | },
417 | {
418 | "name": "Dmitry Naumenko",
419 | "email": "d.naumenko.a@gmail.com",
420 | "role": "Core framework development"
421 | },
422 | {
423 | "name": "Boudewijn Vahrmeijer",
424 | "email": "info@dynasource.eu",
425 | "homepage": "http://dynasource.eu",
426 | "role": "Core framework development"
427 | }
428 | ],
429 | "description": "Yii PHP Framework Version 2 - Development Package",
430 | "homepage": "http://www.yiiframework.com/",
431 | "keywords": [
432 | "framework",
433 | "yii2"
434 | ],
435 | "time": "2018-03-21T18:36:53+00:00"
436 | }
437 | ],
438 | "packages-dev": [
439 | {
440 | "name": "doctrine/instantiator",
441 | "version": "1.0.5",
442 | "source": {
443 | "type": "git",
444 | "url": "https://github.com/doctrine/instantiator.git",
445 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
446 | },
447 | "dist": {
448 | "type": "zip",
449 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
450 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
451 | "shasum": ""
452 | },
453 | "require": {
454 | "php": ">=5.3,<8.0-DEV"
455 | },
456 | "require-dev": {
457 | "athletic/athletic": "~0.1.8",
458 | "ext-pdo": "*",
459 | "ext-phar": "*",
460 | "phpunit/phpunit": "~4.0",
461 | "squizlabs/php_codesniffer": "~2.0"
462 | },
463 | "type": "library",
464 | "extra": {
465 | "branch-alias": {
466 | "dev-master": "1.0.x-dev"
467 | }
468 | },
469 | "autoload": {
470 | "psr-4": {
471 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
472 | }
473 | },
474 | "notification-url": "https://packagist.org/downloads/",
475 | "license": [
476 | "MIT"
477 | ],
478 | "authors": [
479 | {
480 | "name": "Marco Pivetta",
481 | "email": "ocramius@gmail.com",
482 | "homepage": "http://ocramius.github.com/"
483 | }
484 | ],
485 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
486 | "homepage": "https://github.com/doctrine/instantiator",
487 | "keywords": [
488 | "constructor",
489 | "instantiate"
490 | ],
491 | "time": "2015-06-14T21:17:01+00:00"
492 | },
493 | {
494 | "name": "phpdocumentor/reflection-docblock",
495 | "version": "2.0.5",
496 | "source": {
497 | "type": "git",
498 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
499 | "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b"
500 | },
501 | "dist": {
502 | "type": "zip",
503 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b",
504 | "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b",
505 | "shasum": ""
506 | },
507 | "require": {
508 | "php": ">=5.3.3"
509 | },
510 | "require-dev": {
511 | "phpunit/phpunit": "~4.0"
512 | },
513 | "suggest": {
514 | "dflydev/markdown": "~1.0",
515 | "erusev/parsedown": "~1.0"
516 | },
517 | "type": "library",
518 | "extra": {
519 | "branch-alias": {
520 | "dev-master": "2.0.x-dev"
521 | }
522 | },
523 | "autoload": {
524 | "psr-0": {
525 | "phpDocumentor": [
526 | "src/"
527 | ]
528 | }
529 | },
530 | "notification-url": "https://packagist.org/downloads/",
531 | "license": [
532 | "MIT"
533 | ],
534 | "authors": [
535 | {
536 | "name": "Mike van Riel",
537 | "email": "mike.vanriel@naenius.com"
538 | }
539 | ],
540 | "time": "2016-01-25T08:17:30+00:00"
541 | },
542 | {
543 | "name": "phpspec/prophecy",
544 | "version": "1.7.5",
545 | "source": {
546 | "type": "git",
547 | "url": "https://github.com/phpspec/prophecy.git",
548 | "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
549 | },
550 | "dist": {
551 | "type": "zip",
552 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
553 | "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
554 | "shasum": ""
555 | },
556 | "require": {
557 | "doctrine/instantiator": "^1.0.2",
558 | "php": "^5.3|^7.0",
559 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
560 | "sebastian/comparator": "^1.1|^2.0",
561 | "sebastian/recursion-context": "^1.0|^2.0|^3.0"
562 | },
563 | "require-dev": {
564 | "phpspec/phpspec": "^2.5|^3.2",
565 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
566 | },
567 | "type": "library",
568 | "extra": {
569 | "branch-alias": {
570 | "dev-master": "1.7.x-dev"
571 | }
572 | },
573 | "autoload": {
574 | "psr-0": {
575 | "Prophecy\\": "src/"
576 | }
577 | },
578 | "notification-url": "https://packagist.org/downloads/",
579 | "license": [
580 | "MIT"
581 | ],
582 | "authors": [
583 | {
584 | "name": "Konstantin Kudryashov",
585 | "email": "ever.zet@gmail.com",
586 | "homepage": "http://everzet.com"
587 | },
588 | {
589 | "name": "Marcello Duarte",
590 | "email": "marcello.duarte@gmail.com"
591 | }
592 | ],
593 | "description": "Highly opinionated mocking framework for PHP 5.3+",
594 | "homepage": "https://github.com/phpspec/prophecy",
595 | "keywords": [
596 | "Double",
597 | "Dummy",
598 | "fake",
599 | "mock",
600 | "spy",
601 | "stub"
602 | ],
603 | "time": "2018-02-19T10:16:54+00:00"
604 | },
605 | {
606 | "name": "phpunit/php-code-coverage",
607 | "version": "2.2.4",
608 | "source": {
609 | "type": "git",
610 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
611 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
612 | },
613 | "dist": {
614 | "type": "zip",
615 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
616 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
617 | "shasum": ""
618 | },
619 | "require": {
620 | "php": ">=5.3.3",
621 | "phpunit/php-file-iterator": "~1.3",
622 | "phpunit/php-text-template": "~1.2",
623 | "phpunit/php-token-stream": "~1.3",
624 | "sebastian/environment": "^1.3.2",
625 | "sebastian/version": "~1.0"
626 | },
627 | "require-dev": {
628 | "ext-xdebug": ">=2.1.4",
629 | "phpunit/phpunit": "~4"
630 | },
631 | "suggest": {
632 | "ext-dom": "*",
633 | "ext-xdebug": ">=2.2.1",
634 | "ext-xmlwriter": "*"
635 | },
636 | "type": "library",
637 | "extra": {
638 | "branch-alias": {
639 | "dev-master": "2.2.x-dev"
640 | }
641 | },
642 | "autoload": {
643 | "classmap": [
644 | "src/"
645 | ]
646 | },
647 | "notification-url": "https://packagist.org/downloads/",
648 | "license": [
649 | "BSD-3-Clause"
650 | ],
651 | "authors": [
652 | {
653 | "name": "Sebastian Bergmann",
654 | "email": "sb@sebastian-bergmann.de",
655 | "role": "lead"
656 | }
657 | ],
658 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
659 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
660 | "keywords": [
661 | "coverage",
662 | "testing",
663 | "xunit"
664 | ],
665 | "time": "2015-10-06T15:47:00+00:00"
666 | },
667 | {
668 | "name": "phpunit/php-file-iterator",
669 | "version": "1.4.5",
670 | "source": {
671 | "type": "git",
672 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
673 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
674 | },
675 | "dist": {
676 | "type": "zip",
677 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
678 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
679 | "shasum": ""
680 | },
681 | "require": {
682 | "php": ">=5.3.3"
683 | },
684 | "type": "library",
685 | "extra": {
686 | "branch-alias": {
687 | "dev-master": "1.4.x-dev"
688 | }
689 | },
690 | "autoload": {
691 | "classmap": [
692 | "src/"
693 | ]
694 | },
695 | "notification-url": "https://packagist.org/downloads/",
696 | "license": [
697 | "BSD-3-Clause"
698 | ],
699 | "authors": [
700 | {
701 | "name": "Sebastian Bergmann",
702 | "email": "sb@sebastian-bergmann.de",
703 | "role": "lead"
704 | }
705 | ],
706 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
707 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
708 | "keywords": [
709 | "filesystem",
710 | "iterator"
711 | ],
712 | "time": "2017-11-27T13:52:08+00:00"
713 | },
714 | {
715 | "name": "phpunit/php-text-template",
716 | "version": "1.2.1",
717 | "source": {
718 | "type": "git",
719 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
720 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
721 | },
722 | "dist": {
723 | "type": "zip",
724 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
725 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
726 | "shasum": ""
727 | },
728 | "require": {
729 | "php": ">=5.3.3"
730 | },
731 | "type": "library",
732 | "autoload": {
733 | "classmap": [
734 | "src/"
735 | ]
736 | },
737 | "notification-url": "https://packagist.org/downloads/",
738 | "license": [
739 | "BSD-3-Clause"
740 | ],
741 | "authors": [
742 | {
743 | "name": "Sebastian Bergmann",
744 | "email": "sebastian@phpunit.de",
745 | "role": "lead"
746 | }
747 | ],
748 | "description": "Simple template engine.",
749 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
750 | "keywords": [
751 | "template"
752 | ],
753 | "time": "2015-06-21T13:50:34+00:00"
754 | },
755 | {
756 | "name": "phpunit/php-timer",
757 | "version": "1.0.9",
758 | "source": {
759 | "type": "git",
760 | "url": "https://github.com/sebastianbergmann/php-timer.git",
761 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
762 | },
763 | "dist": {
764 | "type": "zip",
765 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
766 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
767 | "shasum": ""
768 | },
769 | "require": {
770 | "php": "^5.3.3 || ^7.0"
771 | },
772 | "require-dev": {
773 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
774 | },
775 | "type": "library",
776 | "extra": {
777 | "branch-alias": {
778 | "dev-master": "1.0-dev"
779 | }
780 | },
781 | "autoload": {
782 | "classmap": [
783 | "src/"
784 | ]
785 | },
786 | "notification-url": "https://packagist.org/downloads/",
787 | "license": [
788 | "BSD-3-Clause"
789 | ],
790 | "authors": [
791 | {
792 | "name": "Sebastian Bergmann",
793 | "email": "sb@sebastian-bergmann.de",
794 | "role": "lead"
795 | }
796 | ],
797 | "description": "Utility class for timing",
798 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
799 | "keywords": [
800 | "timer"
801 | ],
802 | "time": "2017-02-26T11:10:40+00:00"
803 | },
804 | {
805 | "name": "phpunit/php-token-stream",
806 | "version": "1.4.12",
807 | "source": {
808 | "type": "git",
809 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
810 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
811 | },
812 | "dist": {
813 | "type": "zip",
814 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
815 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
816 | "shasum": ""
817 | },
818 | "require": {
819 | "ext-tokenizer": "*",
820 | "php": ">=5.3.3"
821 | },
822 | "require-dev": {
823 | "phpunit/phpunit": "~4.2"
824 | },
825 | "type": "library",
826 | "extra": {
827 | "branch-alias": {
828 | "dev-master": "1.4-dev"
829 | }
830 | },
831 | "autoload": {
832 | "classmap": [
833 | "src/"
834 | ]
835 | },
836 | "notification-url": "https://packagist.org/downloads/",
837 | "license": [
838 | "BSD-3-Clause"
839 | ],
840 | "authors": [
841 | {
842 | "name": "Sebastian Bergmann",
843 | "email": "sebastian@phpunit.de"
844 | }
845 | ],
846 | "description": "Wrapper around PHP's tokenizer extension.",
847 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
848 | "keywords": [
849 | "tokenizer"
850 | ],
851 | "time": "2017-12-04T08:55:13+00:00"
852 | },
853 | {
854 | "name": "phpunit/phpunit",
855 | "version": "4.8.34",
856 | "source": {
857 | "type": "git",
858 | "url": "https://github.com/sebastianbergmann/phpunit.git",
859 | "reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca"
860 | },
861 | "dist": {
862 | "type": "zip",
863 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7eb45205d27edd94bd2b3614085ea158bd1e2bca",
864 | "reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca",
865 | "shasum": ""
866 | },
867 | "require": {
868 | "ext-dom": "*",
869 | "ext-json": "*",
870 | "ext-pcre": "*",
871 | "ext-reflection": "*",
872 | "ext-spl": "*",
873 | "php": ">=5.3.3",
874 | "phpspec/prophecy": "^1.3.1",
875 | "phpunit/php-code-coverage": "~2.1",
876 | "phpunit/php-file-iterator": "~1.4",
877 | "phpunit/php-text-template": "~1.2",
878 | "phpunit/php-timer": "^1.0.6",
879 | "phpunit/phpunit-mock-objects": "~2.3",
880 | "sebastian/comparator": "~1.2.2",
881 | "sebastian/diff": "~1.2",
882 | "sebastian/environment": "~1.3",
883 | "sebastian/exporter": "~1.2",
884 | "sebastian/global-state": "~1.0",
885 | "sebastian/version": "~1.0",
886 | "symfony/yaml": "~2.1|~3.0"
887 | },
888 | "suggest": {
889 | "phpunit/php-invoker": "~1.1"
890 | },
891 | "bin": [
892 | "phpunit"
893 | ],
894 | "type": "library",
895 | "extra": {
896 | "branch-alias": {
897 | "dev-master": "4.8.x-dev"
898 | }
899 | },
900 | "autoload": {
901 | "classmap": [
902 | "src/"
903 | ]
904 | },
905 | "notification-url": "https://packagist.org/downloads/",
906 | "license": [
907 | "BSD-3-Clause"
908 | ],
909 | "authors": [
910 | {
911 | "name": "Sebastian Bergmann",
912 | "email": "sebastian@phpunit.de",
913 | "role": "lead"
914 | }
915 | ],
916 | "description": "The PHP Unit Testing framework.",
917 | "homepage": "https://phpunit.de/",
918 | "keywords": [
919 | "phpunit",
920 | "testing",
921 | "xunit"
922 | ],
923 | "time": "2017-01-26T16:15:36+00:00"
924 | },
925 | {
926 | "name": "phpunit/phpunit-mock-objects",
927 | "version": "2.3.8",
928 | "source": {
929 | "type": "git",
930 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
931 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
932 | },
933 | "dist": {
934 | "type": "zip",
935 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
936 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
937 | "shasum": ""
938 | },
939 | "require": {
940 | "doctrine/instantiator": "^1.0.2",
941 | "php": ">=5.3.3",
942 | "phpunit/php-text-template": "~1.2",
943 | "sebastian/exporter": "~1.2"
944 | },
945 | "require-dev": {
946 | "phpunit/phpunit": "~4.4"
947 | },
948 | "suggest": {
949 | "ext-soap": "*"
950 | },
951 | "type": "library",
952 | "extra": {
953 | "branch-alias": {
954 | "dev-master": "2.3.x-dev"
955 | }
956 | },
957 | "autoload": {
958 | "classmap": [
959 | "src/"
960 | ]
961 | },
962 | "notification-url": "https://packagist.org/downloads/",
963 | "license": [
964 | "BSD-3-Clause"
965 | ],
966 | "authors": [
967 | {
968 | "name": "Sebastian Bergmann",
969 | "email": "sb@sebastian-bergmann.de",
970 | "role": "lead"
971 | }
972 | ],
973 | "description": "Mock Object library for PHPUnit",
974 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
975 | "keywords": [
976 | "mock",
977 | "xunit"
978 | ],
979 | "time": "2015-10-02T06:51:40+00:00"
980 | },
981 | {
982 | "name": "sebastian/comparator",
983 | "version": "1.2.4",
984 | "source": {
985 | "type": "git",
986 | "url": "https://github.com/sebastianbergmann/comparator.git",
987 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
988 | },
989 | "dist": {
990 | "type": "zip",
991 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
992 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
993 | "shasum": ""
994 | },
995 | "require": {
996 | "php": ">=5.3.3",
997 | "sebastian/diff": "~1.2",
998 | "sebastian/exporter": "~1.2 || ~2.0"
999 | },
1000 | "require-dev": {
1001 | "phpunit/phpunit": "~4.4"
1002 | },
1003 | "type": "library",
1004 | "extra": {
1005 | "branch-alias": {
1006 | "dev-master": "1.2.x-dev"
1007 | }
1008 | },
1009 | "autoload": {
1010 | "classmap": [
1011 | "src/"
1012 | ]
1013 | },
1014 | "notification-url": "https://packagist.org/downloads/",
1015 | "license": [
1016 | "BSD-3-Clause"
1017 | ],
1018 | "authors": [
1019 | {
1020 | "name": "Jeff Welch",
1021 | "email": "whatthejeff@gmail.com"
1022 | },
1023 | {
1024 | "name": "Volker Dusch",
1025 | "email": "github@wallbash.com"
1026 | },
1027 | {
1028 | "name": "Bernhard Schussek",
1029 | "email": "bschussek@2bepublished.at"
1030 | },
1031 | {
1032 | "name": "Sebastian Bergmann",
1033 | "email": "sebastian@phpunit.de"
1034 | }
1035 | ],
1036 | "description": "Provides the functionality to compare PHP values for equality",
1037 | "homepage": "http://www.github.com/sebastianbergmann/comparator",
1038 | "keywords": [
1039 | "comparator",
1040 | "compare",
1041 | "equality"
1042 | ],
1043 | "time": "2017-01-29T09:50:25+00:00"
1044 | },
1045 | {
1046 | "name": "sebastian/diff",
1047 | "version": "1.4.3",
1048 | "source": {
1049 | "type": "git",
1050 | "url": "https://github.com/sebastianbergmann/diff.git",
1051 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
1052 | },
1053 | "dist": {
1054 | "type": "zip",
1055 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
1056 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
1057 | "shasum": ""
1058 | },
1059 | "require": {
1060 | "php": "^5.3.3 || ^7.0"
1061 | },
1062 | "require-dev": {
1063 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
1064 | },
1065 | "type": "library",
1066 | "extra": {
1067 | "branch-alias": {
1068 | "dev-master": "1.4-dev"
1069 | }
1070 | },
1071 | "autoload": {
1072 | "classmap": [
1073 | "src/"
1074 | ]
1075 | },
1076 | "notification-url": "https://packagist.org/downloads/",
1077 | "license": [
1078 | "BSD-3-Clause"
1079 | ],
1080 | "authors": [
1081 | {
1082 | "name": "Kore Nordmann",
1083 | "email": "mail@kore-nordmann.de"
1084 | },
1085 | {
1086 | "name": "Sebastian Bergmann",
1087 | "email": "sebastian@phpunit.de"
1088 | }
1089 | ],
1090 | "description": "Diff implementation",
1091 | "homepage": "https://github.com/sebastianbergmann/diff",
1092 | "keywords": [
1093 | "diff"
1094 | ],
1095 | "time": "2017-05-22T07:24:03+00:00"
1096 | },
1097 | {
1098 | "name": "sebastian/environment",
1099 | "version": "1.3.8",
1100 | "source": {
1101 | "type": "git",
1102 | "url": "https://github.com/sebastianbergmann/environment.git",
1103 | "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
1104 | },
1105 | "dist": {
1106 | "type": "zip",
1107 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
1108 | "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
1109 | "shasum": ""
1110 | },
1111 | "require": {
1112 | "php": "^5.3.3 || ^7.0"
1113 | },
1114 | "require-dev": {
1115 | "phpunit/phpunit": "^4.8 || ^5.0"
1116 | },
1117 | "type": "library",
1118 | "extra": {
1119 | "branch-alias": {
1120 | "dev-master": "1.3.x-dev"
1121 | }
1122 | },
1123 | "autoload": {
1124 | "classmap": [
1125 | "src/"
1126 | ]
1127 | },
1128 | "notification-url": "https://packagist.org/downloads/",
1129 | "license": [
1130 | "BSD-3-Clause"
1131 | ],
1132 | "authors": [
1133 | {
1134 | "name": "Sebastian Bergmann",
1135 | "email": "sebastian@phpunit.de"
1136 | }
1137 | ],
1138 | "description": "Provides functionality to handle HHVM/PHP environments",
1139 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1140 | "keywords": [
1141 | "Xdebug",
1142 | "environment",
1143 | "hhvm"
1144 | ],
1145 | "time": "2016-08-18T05:49:44+00:00"
1146 | },
1147 | {
1148 | "name": "sebastian/exporter",
1149 | "version": "1.2.2",
1150 | "source": {
1151 | "type": "git",
1152 | "url": "https://github.com/sebastianbergmann/exporter.git",
1153 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
1154 | },
1155 | "dist": {
1156 | "type": "zip",
1157 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
1158 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
1159 | "shasum": ""
1160 | },
1161 | "require": {
1162 | "php": ">=5.3.3",
1163 | "sebastian/recursion-context": "~1.0"
1164 | },
1165 | "require-dev": {
1166 | "ext-mbstring": "*",
1167 | "phpunit/phpunit": "~4.4"
1168 | },
1169 | "type": "library",
1170 | "extra": {
1171 | "branch-alias": {
1172 | "dev-master": "1.3.x-dev"
1173 | }
1174 | },
1175 | "autoload": {
1176 | "classmap": [
1177 | "src/"
1178 | ]
1179 | },
1180 | "notification-url": "https://packagist.org/downloads/",
1181 | "license": [
1182 | "BSD-3-Clause"
1183 | ],
1184 | "authors": [
1185 | {
1186 | "name": "Jeff Welch",
1187 | "email": "whatthejeff@gmail.com"
1188 | },
1189 | {
1190 | "name": "Volker Dusch",
1191 | "email": "github@wallbash.com"
1192 | },
1193 | {
1194 | "name": "Bernhard Schussek",
1195 | "email": "bschussek@2bepublished.at"
1196 | },
1197 | {
1198 | "name": "Sebastian Bergmann",
1199 | "email": "sebastian@phpunit.de"
1200 | },
1201 | {
1202 | "name": "Adam Harvey",
1203 | "email": "aharvey@php.net"
1204 | }
1205 | ],
1206 | "description": "Provides the functionality to export PHP variables for visualization",
1207 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
1208 | "keywords": [
1209 | "export",
1210 | "exporter"
1211 | ],
1212 | "time": "2016-06-17T09:04:28+00:00"
1213 | },
1214 | {
1215 | "name": "sebastian/global-state",
1216 | "version": "1.1.1",
1217 | "source": {
1218 | "type": "git",
1219 | "url": "https://github.com/sebastianbergmann/global-state.git",
1220 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
1221 | },
1222 | "dist": {
1223 | "type": "zip",
1224 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
1225 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
1226 | "shasum": ""
1227 | },
1228 | "require": {
1229 | "php": ">=5.3.3"
1230 | },
1231 | "require-dev": {
1232 | "phpunit/phpunit": "~4.2"
1233 | },
1234 | "suggest": {
1235 | "ext-uopz": "*"
1236 | },
1237 | "type": "library",
1238 | "extra": {
1239 | "branch-alias": {
1240 | "dev-master": "1.0-dev"
1241 | }
1242 | },
1243 | "autoload": {
1244 | "classmap": [
1245 | "src/"
1246 | ]
1247 | },
1248 | "notification-url": "https://packagist.org/downloads/",
1249 | "license": [
1250 | "BSD-3-Clause"
1251 | ],
1252 | "authors": [
1253 | {
1254 | "name": "Sebastian Bergmann",
1255 | "email": "sebastian@phpunit.de"
1256 | }
1257 | ],
1258 | "description": "Snapshotting of global state",
1259 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1260 | "keywords": [
1261 | "global state"
1262 | ],
1263 | "time": "2015-10-12T03:26:01+00:00"
1264 | },
1265 | {
1266 | "name": "sebastian/recursion-context",
1267 | "version": "1.0.5",
1268 | "source": {
1269 | "type": "git",
1270 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1271 | "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
1272 | },
1273 | "dist": {
1274 | "type": "zip",
1275 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
1276 | "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
1277 | "shasum": ""
1278 | },
1279 | "require": {
1280 | "php": ">=5.3.3"
1281 | },
1282 | "require-dev": {
1283 | "phpunit/phpunit": "~4.4"
1284 | },
1285 | "type": "library",
1286 | "extra": {
1287 | "branch-alias": {
1288 | "dev-master": "1.0.x-dev"
1289 | }
1290 | },
1291 | "autoload": {
1292 | "classmap": [
1293 | "src/"
1294 | ]
1295 | },
1296 | "notification-url": "https://packagist.org/downloads/",
1297 | "license": [
1298 | "BSD-3-Clause"
1299 | ],
1300 | "authors": [
1301 | {
1302 | "name": "Jeff Welch",
1303 | "email": "whatthejeff@gmail.com"
1304 | },
1305 | {
1306 | "name": "Sebastian Bergmann",
1307 | "email": "sebastian@phpunit.de"
1308 | },
1309 | {
1310 | "name": "Adam Harvey",
1311 | "email": "aharvey@php.net"
1312 | }
1313 | ],
1314 | "description": "Provides functionality to recursively process PHP variables",
1315 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1316 | "time": "2016-10-03T07:41:43+00:00"
1317 | },
1318 | {
1319 | "name": "sebastian/version",
1320 | "version": "1.0.6",
1321 | "source": {
1322 | "type": "git",
1323 | "url": "https://github.com/sebastianbergmann/version.git",
1324 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
1325 | },
1326 | "dist": {
1327 | "type": "zip",
1328 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1329 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1330 | "shasum": ""
1331 | },
1332 | "type": "library",
1333 | "autoload": {
1334 | "classmap": [
1335 | "src/"
1336 | ]
1337 | },
1338 | "notification-url": "https://packagist.org/downloads/",
1339 | "license": [
1340 | "BSD-3-Clause"
1341 | ],
1342 | "authors": [
1343 | {
1344 | "name": "Sebastian Bergmann",
1345 | "email": "sebastian@phpunit.de",
1346 | "role": "lead"
1347 | }
1348 | ],
1349 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1350 | "homepage": "https://github.com/sebastianbergmann/version",
1351 | "time": "2015-06-21T13:59:46+00:00"
1352 | },
1353 | {
1354 | "name": "squizlabs/php_codesniffer",
1355 | "version": "2.9.1",
1356 | "source": {
1357 | "type": "git",
1358 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
1359 | "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62"
1360 | },
1361 | "dist": {
1362 | "type": "zip",
1363 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62",
1364 | "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62",
1365 | "shasum": ""
1366 | },
1367 | "require": {
1368 | "ext-simplexml": "*",
1369 | "ext-tokenizer": "*",
1370 | "ext-xmlwriter": "*",
1371 | "php": ">=5.1.2"
1372 | },
1373 | "require-dev": {
1374 | "phpunit/phpunit": "~4.0"
1375 | },
1376 | "bin": [
1377 | "scripts/phpcs",
1378 | "scripts/phpcbf"
1379 | ],
1380 | "type": "library",
1381 | "extra": {
1382 | "branch-alias": {
1383 | "dev-master": "2.x-dev"
1384 | }
1385 | },
1386 | "autoload": {
1387 | "classmap": [
1388 | "CodeSniffer.php",
1389 | "CodeSniffer/CLI.php",
1390 | "CodeSniffer/Exception.php",
1391 | "CodeSniffer/File.php",
1392 | "CodeSniffer/Fixer.php",
1393 | "CodeSniffer/Report.php",
1394 | "CodeSniffer/Reporting.php",
1395 | "CodeSniffer/Sniff.php",
1396 | "CodeSniffer/Tokens.php",
1397 | "CodeSniffer/Reports/",
1398 | "CodeSniffer/Tokenizers/",
1399 | "CodeSniffer/DocGenerators/",
1400 | "CodeSniffer/Standards/AbstractPatternSniff.php",
1401 | "CodeSniffer/Standards/AbstractScopeSniff.php",
1402 | "CodeSniffer/Standards/AbstractVariableSniff.php",
1403 | "CodeSniffer/Standards/IncorrectPatternException.php",
1404 | "CodeSniffer/Standards/Generic/Sniffs/",
1405 | "CodeSniffer/Standards/MySource/Sniffs/",
1406 | "CodeSniffer/Standards/PEAR/Sniffs/",
1407 | "CodeSniffer/Standards/PSR1/Sniffs/",
1408 | "CodeSniffer/Standards/PSR2/Sniffs/",
1409 | "CodeSniffer/Standards/Squiz/Sniffs/",
1410 | "CodeSniffer/Standards/Zend/Sniffs/"
1411 | ]
1412 | },
1413 | "notification-url": "https://packagist.org/downloads/",
1414 | "license": [
1415 | "BSD-3-Clause"
1416 | ],
1417 | "authors": [
1418 | {
1419 | "name": "Greg Sherwood",
1420 | "role": "lead"
1421 | }
1422 | ],
1423 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
1424 | "homepage": "http://www.squizlabs.com/php-codesniffer",
1425 | "keywords": [
1426 | "phpcs",
1427 | "standards"
1428 | ],
1429 | "time": "2017-05-22T02:43:20+00:00"
1430 | },
1431 | {
1432 | "name": "symfony/yaml",
1433 | "version": "v2.8.37",
1434 | "source": {
1435 | "type": "git",
1436 | "url": "https://github.com/symfony/yaml.git",
1437 | "reference": "be720fcfae4614df204190d57795351059946a77"
1438 | },
1439 | "dist": {
1440 | "type": "zip",
1441 | "url": "https://api.github.com/repos/symfony/yaml/zipball/be720fcfae4614df204190d57795351059946a77",
1442 | "reference": "be720fcfae4614df204190d57795351059946a77",
1443 | "shasum": ""
1444 | },
1445 | "require": {
1446 | "php": ">=5.3.9"
1447 | },
1448 | "type": "library",
1449 | "extra": {
1450 | "branch-alias": {
1451 | "dev-master": "2.8-dev"
1452 | }
1453 | },
1454 | "autoload": {
1455 | "psr-4": {
1456 | "Symfony\\Component\\Yaml\\": ""
1457 | },
1458 | "exclude-from-classmap": [
1459 | "/Tests/"
1460 | ]
1461 | },
1462 | "notification-url": "https://packagist.org/downloads/",
1463 | "license": [
1464 | "MIT"
1465 | ],
1466 | "authors": [
1467 | {
1468 | "name": "Fabien Potencier",
1469 | "email": "fabien@symfony.com"
1470 | },
1471 | {
1472 | "name": "Symfony Community",
1473 | "homepage": "https://symfony.com/contributors"
1474 | }
1475 | ],
1476 | "description": "Symfony Yaml Component",
1477 | "homepage": "https://symfony.com",
1478 | "time": "2018-01-03T07:36:31+00:00"
1479 | },
1480 | {
1481 | "name": "yiisoft/yii2-coding-standards",
1482 | "version": "2.0.3",
1483 | "source": {
1484 | "type": "git",
1485 | "url": "https://github.com/yiisoft/yii2-coding-standards.git",
1486 | "reference": "1047aaefcce4cfb83e4987110a573d19706bc50d"
1487 | },
1488 | "dist": {
1489 | "type": "zip",
1490 | "url": "https://api.github.com/repos/yiisoft/yii2-coding-standards/zipball/1047aaefcce4cfb83e4987110a573d19706bc50d",
1491 | "reference": "1047aaefcce4cfb83e4987110a573d19706bc50d",
1492 | "shasum": ""
1493 | },
1494 | "require": {
1495 | "php": ">=5.4.0",
1496 | "squizlabs/php_codesniffer": ">=2.3.1 <3.0"
1497 | },
1498 | "type": "phpcodesniffer-standard",
1499 | "notification-url": "https://packagist.org/downloads/",
1500 | "license": [
1501 | "BSD-3-Clause"
1502 | ],
1503 | "authors": [
1504 | {
1505 | "name": "Qiang Xue",
1506 | "email": "qiang.xue@gmail.com",
1507 | "homepage": "http://www.yiiframework.com/",
1508 | "role": "Founder and project lead"
1509 | },
1510 | {
1511 | "name": "Alexander Makarov",
1512 | "email": "sam@rmcreative.ru",
1513 | "homepage": "http://rmcreative.ru/",
1514 | "role": "Core framework development"
1515 | },
1516 | {
1517 | "name": "Maurizio Domba",
1518 | "homepage": "http://mdomba.info/",
1519 | "role": "Core framework development"
1520 | },
1521 | {
1522 | "name": "Carsten Brandt",
1523 | "email": "mail@cebe.cc",
1524 | "homepage": "http://cebe.cc/",
1525 | "role": "Core framework development"
1526 | },
1527 | {
1528 | "name": "Timur Ruziev",
1529 | "email": "resurtm@gmail.com",
1530 | "homepage": "http://resurtm.com/",
1531 | "role": "Core framework development"
1532 | },
1533 | {
1534 | "name": "Paul Klimov",
1535 | "email": "klimov.paul@gmail.com",
1536 | "role": "Core framework development"
1537 | }
1538 | ],
1539 | "description": "Yii PHP Framework Version 2 - Coding standard tools",
1540 | "homepage": "http://www.yiiframework.com/",
1541 | "keywords": [
1542 | "codesniffer",
1543 | "framework",
1544 | "yii"
1545 | ],
1546 | "time": "2017-05-12T10:30:45+00:00"
1547 | }
1548 | ],
1549 | "aliases": [],
1550 | "minimum-stability": "stable",
1551 | "stability-flags": [],
1552 | "prefer-stable": false,
1553 | "prefer-lowest": false,
1554 | "platform": [],
1555 | "platform-dev": [],
1556 | "platform-overrides": {
1557 | "php": "5.4"
1558 | }
1559 | }
1560 |
--------------------------------------------------------------------------------