Commit e4448bec by Gevik Babakhani

Merge branch 'pgsql-driver' of github.com:gevik/yii2 into pgsql-driver

parents eebdfd25 5a587d16
......@@ -79,6 +79,21 @@ php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-a
This is not currently available. We will provide it when Yii 2 is formally released.
### Install from development repository
If you've cloned the [Yii 2 framework main development repository](https://github.com/yiisoft/yii2) you
can bootstrap your application with:
~~~
cd yii2/apps/advanced
php composer.phar create-project
~~~
*Note: If the above command fails with `[RuntimeException] Not enough arguments.` run
`php composer.phar self-update` to obtain an updated version of composer which supports creating projects
from local packages.*
GETTING STARTED
---------------
......
......@@ -19,10 +19,7 @@
"yiisoft/yii2-composer": "dev-master"
},
"scripts": {
"post-install-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
],
"post-update-cmd": [
"post-create-project-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
]
},
......
......@@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "05f7bcd0e99931b52415eaeb62d54daf",
"hash": "2d1053fbaaf2044054f273a71d0ccde0",
"packages": [
{
"name": "yiisoft/yii2",
......@@ -11,12 +11,12 @@
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-framework.git",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d"
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"shasum": ""
},
"require": {
......@@ -97,7 +97,7 @@
"framework",
"yii"
],
"time": "2013-05-29 02:55:14"
"time": "2013-06-02 19:19:29"
},
{
"name": "yiisoft/yii2-composer",
......
......@@ -59,3 +59,18 @@ assuming `yii-basic` is directly under the document root of your Web server.
### Install from an Archive File
This is not currently available. We will provide it when Yii 2 is formally released.
### Install from development repository
If you've cloned the [Yii 2 framework main development repository](https://github.com/yiisoft/yii2) you
can bootstrap your application with:
~~~
cd yii2/apps/basic
php composer.phar create-project
~~~
*Note: If the above command fails with `[RuntimeException] Not enough arguments.` run
`php composer.phar self-update` to obtain an updated version of composer which supports creating projects
from local packages.*
......@@ -19,10 +19,7 @@
"yiisoft/yii2-composer": "dev-master"
},
"scripts": {
"post-install-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
],
"post-update-cmd": [
"post-create-project-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
]
},
......
......@@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "0411dbbd774aa1c89256c77c68023940",
"hash": "91ba258de768b93025f86071f3bb4b84",
"packages": [
{
"name": "yiisoft/yii2",
......@@ -11,12 +11,12 @@
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-framework.git",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d"
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"shasum": ""
},
"require": {
......@@ -97,7 +97,7 @@
"framework",
"yii"
],
"time": "2013-05-29 02:55:14"
"time": "2013-06-02 19:19:29"
},
{
"name": "yiisoft/yii2-composer",
......
......@@ -4,7 +4,6 @@ return array(
'id' => 'bootstrap',
'basePath' => dirname(__DIR__),
'preload' => array('log'),
'controllerNamespace' => 'app\controllers',
'modules' => array(
// 'debug' => array(
// 'class' => 'yii\debug\Module',
......
......@@ -26,12 +26,12 @@ class ViewRenderer extends BaseViewRenderer
/**
* @var string the directory or path alias pointing to where Smarty cache will be stored.
*/
public $cachePath = '@app/runtime/Smarty/cache';
public $cachePath = '@runtime/Smarty/cache';
/**
* @var string the directory or path alias pointing to where Smarty compiled templates will be stored.
*/
public $compilePath = '@app/runtime/Smarty/compile';
public $compilePath = '@runtime/Smarty/compile';
/**
* @var Smarty
......
......@@ -25,7 +25,7 @@ class ViewRenderer extends BaseViewRenderer
/**
* @var string the directory or path alias pointing to where Twig cache will be stored.
*/
public $cachePath = '@app/runtime/Twig/cache';
public $cachePath = '@runtime/Twig/cache';
/**
* @var array Twig options
......
......@@ -72,25 +72,17 @@ class Application extends Module
public function __construct($config = array())
{
Yii::$app = $this;
if (!isset($config['id'])) {
throw new InvalidConfigException('The "id" configuration is required.');
}
if (isset($config['basePath'])) {
$this->setBasePath($config['basePath']);
Yii::setAlias('@app', $this->getBasePath());
unset($config['basePath']);
} else {
throw new InvalidConfigException('The "basePath" configuration is required.');
}
if (isset($config['timeZone'])) {
$this->setTimeZone($config['timeZone']);
unset($config['timeZone']);
} elseif (!ini_get('date.timezone')) {
$this->setTimeZone('UTC');
}
$this->preInit($config);
$this->registerErrorHandlers();
$this->registerCoreComponents();
......@@ -99,6 +91,35 @@ class Application extends Module
}
/**
* Pre-initializes the application.
* This method is called at the beginning of the application constructor.
* @param array $config the application configuration
*/
public function preInit(&$config)
{
if (isset($config['vendorPath'])) {
$this->setVendorPath($config['vendorPath']);
unset($config['vendorPath']);
} else {
// set "@vendor"
$this->getVendorPath();
}
if (isset($config['runtimePath'])) {
$this->setRuntimePath($config['runtimePath']);
unset($config['runtimePath']);
} else {
// set "@runtime"
$this->getRuntimePath();
}
if (isset($config['timeZone'])) {
$this->setTimeZone($config['timeZone']);
unset($config['timeZone']);
} elseif (!ini_get('date.timezone')) {
$this->setTimeZone('UTC');
}
}
/**
* Registers error handlers.
*/
public function registerErrorHandlers()
......@@ -178,7 +199,8 @@ class Application extends Module
/**
* Returns the directory that stores runtime files.
* @return string the directory that stores runtime files. Defaults to 'protected/runtime'.
* @return string the directory that stores runtime files.
* Defaults to the "runtime" subdirectory under [[basePath]].
*/
public function getRuntimePath()
{
......@@ -191,16 +213,11 @@ class Application extends Module
/**
* Sets the directory that stores runtime files.
* @param string $path the directory that stores runtime files.
* @throws InvalidConfigException if the directory does not exist or is not writable
*/
public function setRuntimePath($path)
{
$path = Yii::getAlias($path);
if (is_dir($path) && is_writable($path)) {
$this->_runtimePath = $path;
} else {
throw new InvalidConfigException("Runtime path must be a directory writable by the Web server process: $path");
}
$this->_runtimePath = Yii::getAlias($path);
Yii::setAlias('@runtime', $this->_runtimePath);
}
private $_vendorPath;
......@@ -208,7 +225,7 @@ class Application extends Module
/**
* Returns the directory that stores vendor files.
* @return string the directory that stores vendor files.
* Defaults to 'vendor' directory under applications [[basePath]].
* Defaults to "vendor" directory under [[basePath]].
*/
public function getVendorPath()
{
......@@ -225,6 +242,7 @@ class Application extends Module
public function setVendorPath($path)
{
$this->_vendorPath = Yii::getAlias($path);
Yii::setAlias('@vendor', $this->_vendorPath);
}
/**
......
......@@ -39,17 +39,19 @@ class Formatter extends Component
public $datetimeFormat = 'Y/m/d h:i:s A';
/**
* @var array the text to be displayed when formatting a boolean value. The first element corresponds
* to the text display for false, the second element for true. Defaults to <code>array('No', 'Yes')</code>.
* to the text display for false, the second element for true. Defaults to `array('No', 'Yes')`.
*/
public $booleanFormat;
/**
* @var string the character displayed as the decimal point when formatting a number.
* If not set, "." will be used.
*/
public $decimalSeparator = '.';
public $decimalSeparator;
/**
* @var string the character displayed as the thousands separator character when formatting a number.
* If not set, "," will be used.
*/
public $thousandSeparator = ',';
public $thousandSeparator;
/**
......@@ -273,7 +275,11 @@ class Formatter extends Component
*/
public function asDouble($value, $decimals = 2)
{
return str_replace('.', $this->decimalSeparator, sprintf("%.{$decimals}f", $value));
if ($this->decimalSeparator === null) {
return sprintf("%.{$decimals}f", $value);
} else {
return str_replace('.', $this->decimalSeparator, sprintf("%.{$decimals}f", $value));
}
}
/**
......@@ -287,6 +293,8 @@ class Formatter extends Component
*/
public function asNumber($value, $decimals = 0)
{
return number_format($value, $decimals, $this->decimalSeparator, $this->thousandSeparator);
$ds = isset($this->decimalSeparator) ? $this->decimalSeparator: '.';
$ts = isset($this->thousandSeparator) ? $this->thousandSeparator: ',';
return number_format($value, $decimals, $ds, $ts);
}
}
......@@ -88,7 +88,11 @@ abstract class Module extends Component
*/
public $controllerMap = array();
/**
* @var string the namespace that controller classes are in. Default is to use global namespace.
* @var string the namespace that controller classes are in. If not set,
* it will use the "controllers" sub-namespace under the namespace of this module.
* For example, if the namespace of this module is "foo\bar", then the default
* controller namespace would be "foo\bar\controllers".
* If the module is an application, it will default to "app\controllers".
*/
public $controllerNamespace;
/**
......@@ -178,6 +182,16 @@ abstract class Module extends Component
public function init()
{
$this->preloadComponents();
if ($this->controllerNamespace === null) {
if ($this instanceof Application) {
$this->controllerNamespace = 'app\\controllers';
} else {
$class = get_class($this);
if (($pos = strrpos($class, '\\')) !== false) {
$this->controllerNamespace = substr($class, 0, $pos) . '\\controllers';
}
}
}
}
/**
......@@ -222,6 +236,9 @@ abstract class Module extends Component
$p = realpath($path);
if ($p !== false && is_dir($p)) {
$this->_basePath = $p;
if ($this instanceof Application) {
Yii::setAlias('@app', $p);
}
} else {
throw new InvalidParamException("The directory does not exist: $path");
}
......@@ -409,11 +426,11 @@ abstract class Module extends Component
* ~~~
* array(
* 'comment' => array(
* 'class' => 'app\modules\CommentModule',
* 'class' => 'app\modules\comment\CommentModule',
* 'db' => 'db',
* ),
* 'booking' => array(
* 'class' => 'app\modules\BookingModule',
* 'class' => 'app\modules\booking\BookingModule',
* ),
* )
* ~~~
......
......@@ -27,7 +27,7 @@ use yii\helpers\Html;
* ),
* array(
* 'label' => 'Dropdown',
* 'items' => array(
* 'dropdown' => array(
* array(
* 'label' => 'DropdownA',
* 'url' => '#',
......@@ -128,8 +128,10 @@ class Nav extends Widget
$this->addCssClass($urlOptions, 'dropdown-toggle');
$label .= ' ' . Html::tag('b', '', array('class' => 'caret'));
if (is_array($dropdown)) {
$dropdown['clientOptions'] = false;
$dropdown = Dropdown::widget($dropdown);
$dropdown = Dropdown::widget(array(
'items' => $dropdown,
'clientOptions' => false,
));
}
}
......
......@@ -25,8 +25,9 @@ class FileCache extends Cache
{
/**
* @var string the directory to store cache files. You may use path alias here.
* If not set, it will use the "cache" subdirectory under the application runtime path.
*/
public $cachePath = '@app/runtime/cache';
public $cachePath = '@runtime/cache';
/**
* @var string cache file suffix. Defaults to '.bin'.
*/
......
......@@ -14,6 +14,20 @@ use yii\console\Controller;
/**
* This command allows you to combine and compress your JavaScript and CSS files.
*
* Usage:
* 1. Create a configuration file using 'template' action:
* yii asset/template /path/to/myapp/config.php
* 2. Edit the created config file, adjusting it for your web application needs.
* 3. Run the 'compress' action, using created config:
* yii asset /path/to/myapp/config.php /path/to/myapp/config/assets_compressed.php
* 4. Adjust your web application config to use compressed assets.
*
* Note: in the console environment some path aliases like '@wwwroot' and '@www' may not exist,
* so corresponding paths inside the configuration should be specified directly.
*
* Note: by default this command relies on an external tools to perform actual files compression,
* check [[jsCompressor]] and [[cssCompressor]] for more details.
*
* @property array|\yii\web\AssetManager $assetManager asset manager, which will be used for assets processing.
*
* @author Qiang Xue <qiang.xue@gmail.com>
......@@ -43,7 +57,7 @@ class AssetController extends Controller
* ~~~
* 'all' => array(
* 'css' => 'all.css',
* 'js' => 'js.css',
* 'js' => 'all.js',
* 'depends' => array( ... ),
* )
* ~~~
......@@ -57,7 +71,7 @@ class AssetController extends Controller
*/
private $_assetManager = array();
/**
* @var string|callback Java Script file compressor.
* @var string|callback JavaScript file compressor.
* If a string, it is treated as shell command template, which should contain
* placeholders {from} - source file name - and {to} - output file name.
* Otherwise, it is treated as PHP callback, which should perform the compression.
......@@ -159,7 +173,7 @@ class AssetController extends Controller
}
}
$this->getAssetManager(); // check asset manager configuration
$this->getAssetManager(); // check if asset manager configuration is correct
}
/**
......@@ -308,7 +322,7 @@ class AssetController extends Controller
/**
* Builds output asset bundle.
* @param \yii\web\AssetBundle $target output asset bundle
* @param string $type either "js" or "css".
* @param string $type either 'js' or 'css'.
* @param \yii\web\AssetBundle[] $bundles source asset bundles.
* @param integer $timestamp current timestamp.
* @throws Exception on failure.
......@@ -420,24 +434,23 @@ class AssetController extends Controller
}
$array = var_export($array, true);
$version = date('Y-m-d H:i:s', time());
$bytesWritten = file_put_contents($bundleFile, <<<EOD
$bundleFileContent = <<<EOD
<?php
/**
* This file is generated by the "yii script" command.
* This file is generated by the "yii {$this->id}" command.
* DO NOT MODIFY THIS FILE DIRECTLY.
* @version $version
* @version {$version}
*/
return $array;
EOD
);
if ($bytesWritten <= 0) {
return {$array};
EOD;
if (!file_put_contents($bundleFile, $bundleFileContent)) {
throw new Exception("Unable to write output bundle configuration at '{$bundleFile}'.");
}
echo "Output bundle configuration created at '{$bundleFile}'.\n";
}
/**
* Compresses given Java Script files and combines them into the single one.
* Compresses given JavaScript files and combines them into the single one.
* @param array $inputFiles list of source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure
......@@ -495,9 +508,10 @@ EOD
}
/**
* Combines Java Script files into a single one.
* Combines JavaScript files into a single one.
* @param array $inputFiles source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure.
*/
public function combineJsFiles($inputFiles, $outputFile)
{
......@@ -507,13 +521,16 @@ EOD
. file_get_contents($file)
. "/*** END FILE: $file ***/\n";
}
file_put_contents($outputFile, $content);
if (!file_put_contents($outputFile, $content)) {
throw new Exception("Unable to write output JavaScript file '{$outputFile}'.");
}
}
/**
* Combines CSS files into a single one.
* @param array $inputFiles source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure.
*/
public function combineCssFiles($inputFiles, $outputFile)
{
......@@ -523,7 +540,9 @@ EOD
. $this->adjustCssUrl(file_get_contents($file), dirname($file), dirname($outputFile))
. "/*** END FILE: $file ***/\n";
}
file_put_contents($outputFile, $content);
if (!file_put_contents($outputFile, $content)) {
throw new Exception("Unable to write output CSS file '{$outputFile}'.");
}
}
/**
......@@ -590,18 +609,23 @@ EOD
/**
* Creates template of configuration file for [[actionCompress]].
* @param string $configFile output file name.
* @throws \yii\console\Exception on failure.
*/
public function actionTemplate($configFile)
{
$template = <<<EOD
<?php
/**
* Configuration file for the "yii asset" console command.
* Note: in the console environment some path aliases like '@wwwroot' and '@www' may not exist,
* so corresponding paths should be specified directly.
*/
return array(
//
// The list of asset bundles to compress:
'bundles' => require('path/to/bundles.php'),
//
// The list of extensions to compress:
'extensions' => require('path/to/namespaces.php'),
//
// Asset bundle for compression output:
'targets' => array(
'all' => array(
'basePath' => __DIR__,
......@@ -610,7 +634,7 @@ return array(
'css' => 'all-{ts}.css',
),
),
// Asset manager configuration:
'assetManager' => array(
'basePath' => __DIR__,
'baseUrl' => '/test',
......@@ -622,9 +646,8 @@ EOD;
return;
}
}
$bytesWritten = file_put_contents($configFile, $template);
if ($bytesWritten<=0) {
echo "Error: unable to write file '{$configFile}'!\n\n";
if (!file_put_contents($configFile, $template)) {
throw new Exception("Unable to write template file '{$configFile}'.");
} else {
echo "Configuration file template created at '{$configFile}'.\n\n";
}
......
......@@ -275,10 +275,16 @@ class ActiveRecord extends Model
/**
* Returns the schema information of the DB table associated with this AR class.
* @return TableSchema the schema information of the DB table associated with this AR class.
* @throws InvalidConfigException if the table for the AR class does not exist.
*/
public static function getTableSchema()
{
return static::getDb()->getTableSchema(static::tableName());
$schema = static::getDb()->getTableSchema(static::tableName());
if ($schema !== null) {
return $schema;
} else {
throw new InvalidConfigException("The table does not exist: " . static::tableName());
}
}
/**
......
......@@ -464,6 +464,12 @@ class QueryBuilder extends \yii\base\Object
* the first part will be converted, and the rest of the parts will be appended to the converted result.
* For example, 'string NOT NULL' is converted to 'varchar(255) NOT NULL'.
*
* For some of the abstract types you can also specify a length or precision constraint
* by prepending it in round brackets directly to the type.
* For example `string(32)` will be converted into "varchar(32)" on a MySQL database.
* If the underlying DBMS does not support these kind of constraints for a type it will
* be ignored.
*
* If a type cannot be found in [[typeMap]], it will be returned without any change.
* @param string $type abstract column type
* @return string physical column type.
......@@ -472,6 +478,10 @@ class QueryBuilder extends \yii\base\Object
{
if (isset($this->typeMap[$type])) {
return $this->typeMap[$type];
} elseif (preg_match('/^(\w+)\((.+?)\)(.*)$/', $type, $matches)) {
if (isset($this->typeMap[$matches[1]])) {
return preg_replace('/\(.+\)/', '(' . $matches[2] . ')', $this->typeMap[$matches[1]]) . $matches[3];
}
} elseif (preg_match('/^(\w+)\s+/', $type, $matches)) {
if (isset($this->typeMap[$matches[1]])) {
return preg_replace('/^\w+/', $this->typeMap[$matches[1]], $type);
......
......@@ -28,7 +28,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_INTEGER => 'int(11)',
Schema::TYPE_BIGINT => 'bigint(20)',
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DECIMAL => 'decimal',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
......
......@@ -29,7 +29,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_INTEGER => 'int(11)',
Schema::TYPE_BIGINT => 'bigint(20)',
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DECIMAL => 'decimal',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
......
......@@ -178,6 +178,7 @@ class Schema extends \yii\db\Schema
* Collects the metadata of table columns.
* @param TableSchema $table the table metadata
* @return boolean whether the table exists in the database
* @throws \Exception if DB query fails
*/
protected function findColumns($table)
{
......@@ -185,7 +186,12 @@ class Schema extends \yii\db\Schema
try {
$columns = $this->db->createCommand($sql)->queryAll();
} catch (\Exception $e) {
return false;
$previous = $e->getPrevious();
if ($previous instanceof \PDOException && $previous->getCode() == '42S02') {
// table does not exist
return false;
}
throw $e;
}
foreach ($columns as $info) {
$column = $this->loadColumnSchema($info);
......
......@@ -16,13 +16,14 @@ namespace yii\db\pgsql;
* @author Gevik babakhani <gevikb@gmail.com>
* @since 2.0
*/
class PDO extends \PDO {
class PDO extends \PDO
{
const OPT_SEARCH_PATH = 'search_path';
const OPT_DEFAULT_SCHEMA = 'default_schema';
const DEFAULT_SCHEMA = 'public';
private $_currentDatabase = null;
private $_currentDatabase;
/**
* Returns value of the last inserted ID.
......@@ -53,11 +54,11 @@ class PDO extends \PDO {
}
if (isset($options[self::OPT_DEFAULT_SCHEMA])) {
$schema = trim($options[self::OPT_DEFAULT_SCHEMA]);
if ($schema !== '') {
if (!empty($schema)) {
Schema::$DEFAULT_SCHEMA = $schema;
}
}
if (Schema::$DEFAULT_SCHEMA === null || Schema::$DEFAULT_SCHEMA === '') {
if (is_null(Schema::$DEFAULT_SCHEMA) || empty(Schema::$DEFAULT_SCHEMA)) {
Schema::$DEFAULT_SCHEMA = self::DEFAULT_SCHEMA;
}
}
......
......@@ -8,23 +8,21 @@
namespace yii\db\pgsql;
use yii\db\Exception;
use yii\base\InvalidParamException;
/**
* QueryBuilder is the query builder for PostgreSQL databases.
*
* @author Gevik Babakhani <gevikb@gmail.com>
* @since 2.0
*/
class QueryBuilder extends \yii\db\QueryBuilder {
class QueryBuilder extends \yii\db\QueryBuilder
{
/**
* @var array mapping from abstract column types (keys) to physical column types (values).
*/
public $typeMap = array(
Schema::TYPE_PK => 'bigserial not null primary key',
Schema::TYPE_STRING => 'varchar(255)',
Schema::TYPE_STRING => 'varchar',
Schema::TYPE_TEXT => 'text',
Schema::TYPE_SMALLINT => 'smallint',
Schema::TYPE_INTEGER => 'integer',
......@@ -40,9 +38,4 @@ class QueryBuilder extends \yii\db\QueryBuilder {
Schema::TYPE_MONEY => 'numeric(19,4)',
);
public function insert($table, $columns, &$params) {
$sql = parent::insert($table, $columns, $params);
return $sql . ' RETURNING *';
}
}
......@@ -18,7 +18,8 @@ use yii\db\ColumnSchema;
* @author Gevik Babakhani <gevikb@gmail.com>
* @since 2.0
*/
class Schema extends \yii\db\Schema {
class Schema extends \yii\db\Schema
{
/**
* The default schema used for the current session. This value is
......@@ -33,31 +34,24 @@ class Schema extends \yii\db\Schema {
*/
public $typeMap = array(
'abstime' => self::TYPE_TIMESTAMP,
//'aclitem' => self::TYPE_STRING,
'bit' => self::TYPE_STRING,
'boolean' => self::TYPE_BOOLEAN,
'box' => self::TYPE_STRING,
'character' => self::TYPE_STRING,
'bytea' => self::TYPE_BINARY,
'char' => self::TYPE_STRING,
//'cid' => self::TYPE_STRING,
'cidr' => self::TYPE_STRING,
'circle' => self::TYPE_STRING,
'date' => self::TYPE_DATE,
//'daterange' => self::TYPE_STRING,
'real' => self::TYPE_FLOAT,
'double precision' => self::TYPE_DECIMAL,
//'gtsvector' => self::TYPE_STRING,
'inet' => self::TYPE_STRING,
'smallint' => self::TYPE_SMALLINT,
'integer' => self::TYPE_INTEGER,
//'int4range' => self::TYPE_STRING, //unknown
'bigint' => self::TYPE_BIGINT,
//'int8range' => self::TYPE_STRING, // unknown
'interval' => self::TYPE_STRING,
'json' => self::TYPE_STRING,
'line' => self::TYPE_STRING,
//'lseg' => self::TYPE_STRING,
'macaddr' => self::TYPE_STRING,
'money' => self::TYPE_MONEY,
'name' => self::TYPE_STRING,
......@@ -65,38 +59,49 @@ class Schema extends \yii\db\Schema {
'numrange' => self::TYPE_DECIMAL,
'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal!
'path' => self::TYPE_STRING,
//'pg_node_tree' => self::TYPE_STRING,
'point' => self::TYPE_STRING,
'polygon' => self::TYPE_STRING,
//'refcursor' => self::TYPE_STRING,
//'regclass' => self::TYPE_STRING,
//'regconfig' => self::TYPE_STRING,
//'regdictionary' => self::TYPE_STRING,
//'regoper' => self::TYPE_STRING,
//'regoperator' => self::TYPE_STRING,
//'regproc' => self::TYPE_STRING,
//'regprocedure' => self::TYPE_STRING,
//'regtype' => self::TYPE_STRING,
//'reltime' => self::TYPE_STRING,
//'smgr' => self::TYPE_STRING,
'text' => self::TYPE_TEXT,
//'tid' => self::TYPE_STRING,
'time without time zone' => self::TYPE_TIME,
'timestamp without time zone' => self::TYPE_TIMESTAMP,
'timestamp with time zone' => self::TYPE_TIMESTAMP,
'time with time zone' => self::TYPE_TIMESTAMP,
//'tinterval' => self::TYPE_STRING,
//'tsquery' => self::TYPE_STRING,
//'tsrange' => self::TYPE_STRING,
//'tstzrange' => self::TYPE_STRING,
//'tsvector' => self::TYPE_STRING,
//'txid_snapshot' => self::TYPE_STRING,
'unknown' => self::TYPE_STRING,
'uuid' => self::TYPE_STRING,
'bit varying' => self::TYPE_STRING,
'character varying' => self::TYPE_STRING,
//'xid' => self::TYPE_STRING,
'xml' => self::TYPE_STRING
/*
* internal PG types
* 'aclitem' => self::TYPE_STRING,
* 'cid' => self::TYPE_STRING,
* 'daterange' => self::TYPE_STRING,
* 'gtsvector' => self::TYPE_STRING,
* 'int4range' => self::TYPE_STRING, //unknown
* 'lseg' => self::TYPE_STRING,
* 'int8range' => self::TYPE_STRING, // unknown
* 'pg_node_tree' => self::TYPE_STRING,
* 'refcursor' => self::TYPE_STRING,
* 'regclass' => self::TYPE_STRING,
* 'regconfig' => self::TYPE_STRING,
* 'regdictionary' => self::TYPE_STRING,
* 'regoper' => self::TYPE_STRING,
* 'regoperator' => self::TYPE_STRING,
* 'regproc' => self::TYPE_STRING,
* 'regprocedure' => self::TYPE_STRING,
* 'regtype' => self::TYPE_STRING,
* 'reltime' => self::TYPE_STRING,
* 'smgr' => self::TYPE_STRING,
* 'tid' => self::TYPE_STRING,
* 'xid' => self::TYPE_STRING,
* 'tinterval' => self::TYPE_STRING,
* 'tsquery' => self::TYPE_STRING,
* 'tsrange' => self::TYPE_STRING,
* 'tstzrange' => self::TYPE_STRING,
* 'tsvector' => self::TYPE_STRING,
* 'txid_snapshot' => self::TYPE_STRING
*/
);
/**
......@@ -155,14 +160,51 @@ class Schema extends \yii\db\Schema {
*/
protected function findConstraints($table) {
$tableName = $this->quoteValue($table->name);
$tableSchema = $this->quoteValue($table->schemaName);
$database = $this->quoteValue($this->db->pdo->getCurrentDatabase());
//We need to extract the constraints de hard way since:
//http://www.postgresql.org/message-id/26677.1086673982@sss.pgh.pa.us
$sql = <<<SQL
select
ct.conname as containst,
c.relname as table_name,
ns.nspname as table_schema,
current_database() as table_catalog,
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.conrelid and attnum = any(ct.conkey)) as columns,
fc.relname as foreign_table_name,
fns.nspname as foreign_table_schema,
current_database() as foreign_table_catalog,
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.confrelid and attnum = any(ct.confkey)) as foreign_columns
from
pg_constraint ct
inner join pg_class c on c.oid=ct.conrelid
inner join pg_namespace ns on c.relnamespace=ns.oid
left join pg_class fc on fc.oid=ct.confrelid
left join pg_namespace fns on fc.relnamespace=fns.oid
where
ct.contype='f'
and c.relname={$tableName}
and ns.nspname={$tableSchema}
and current_database() = {$database}
SQL;
try {
$constraints = $this->db->createCommand($sql)->queryAll();
} catch (\Exception $e) {
return false;
}
foreach ($constraints as $constraint) {
$column = $this->loadColumnSchema($column);
$table->columns[$column->name] = $column;
$columns = explode(',', $constraint['columns']);
$fcolumns = explode(',', $constraint['foreign_columns']);
$citem = array($constraint['foreign_table_name']);
foreach ($columns as $idx => $column) {
$citem[] = array($fcolumns[$idx] => $column);
}
$table->foreignKeys[] = $citem;
}
return true;
}
......
......@@ -30,13 +30,13 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_INTEGER => 'integer',
Schema::TYPE_BIGINT => 'bigint',
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DECIMAL => 'decimal',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
Schema::TYPE_DATE => 'date',
Schema::TYPE_BINARY => 'blob',
Schema::TYPE_BOOLEAN => 'tinyint(1)',
Schema::TYPE_BOOLEAN => 'boolean',
Schema::TYPE_MONEY => 'decimal(19,4)',
);
......
......@@ -131,15 +131,30 @@ class SecurityHelper
$keys = is_file($keyFile) ? require($keyFile) : array();
}
if (!isset($keys[$name])) {
// generate a 32-char random key
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$keys[$name] = substr(str_shuffle(str_repeat($chars, 5)), 0, $length);
$keys[$name] = static::generateRandomKey($length);
file_put_contents($keyFile, "<?php\nreturn " . var_export($keys, true) . ";\n");
}
return $keys[$name];
}
/**
* Generates a random key.
* @param integer $length the length of the key that should be generated
* @return string the generated random key
*/
public static function generateRandomKey($length = 32)
{
if (function_exists('openssl_random_pseudo_bytes')) {
$key = base64_encode(openssl_random_pseudo_bytes($length, $strong));
if ($strong) {
return substr($key, 0, $length);
}
}
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
return substr(str_shuffle(str_repeat($chars, 5)), 0, $length);
}
/**
* Opens the mcrypt module.
* @return resource the mcrypt module handle.
* @throws InvalidConfigException if mcrypt extension is not installed
......
......@@ -30,21 +30,40 @@ class Formatter extends \yii\base\Formatter
*/
public $locale;
/**
* @var string the default format string to be used to format a date using PHP date() function.
* @var string the default format string to be used to format a date.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*/
public $dateFormat = 'short';
/**
* @var string the default format string to be used to format a time using PHP date() function.
* @var string the default format string to be used to format a time.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*/
public $timeFormat = 'short';
/**
* @var string the default format string to be used to format a date and time using PHP date() function.
* @var string the default format string to be used to format a date and time.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*/
public $datetimeFormat = 'short';
/**
* @var array the options to be set for the NumberFormatter objects. Please refer to
* [PHP manual](http://php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants.unumberformatattribute)
* for the possible options. This property is used by [[createNumberFormatter]] when
* creating a new number formatter to format decimals, currencies, etc.
*/
public $numberFormatOptions = array();
/**
* @var string the character displayed as the decimal point when formatting a number.
* If not set, the decimal separator corresponding to [[locale]] will be used.
*/
public $decimalSeparator;
/**
* @var string the character displayed as the thousands separator character when formatting a number.
* If not set, the thousand separator corresponding to [[locale]] will be used.
*/
public $thousandSeparator;
/**
......@@ -61,6 +80,16 @@ class Formatter extends \yii\base\Formatter
if ($this->locale === null) {
$this->locale = Yii::$app->language;
}
if ($this->decimalSeparator === null || $this->thousandSeparator === null) {
$formatter = new NumberFormatter($this->locale, NumberFormatter::DECIMAL);
if ($this->decimalSeparator === null) {
$this->decimalSeparator = $formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
}
if ($this->thousandSeparator === null) {
$this->thousandSeparator = $formatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
}
}
parent::init();
}
......@@ -81,8 +110,11 @@ class Formatter extends \yii\base\Formatter
* - a PHP DateTime object
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used. The format string should be the one
* that can be recognized by the PHP `date()` function.
* If null, [[dateFormat]] will be used.
*
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* @return string the formatted result
* @see dateFormat
*/
......@@ -111,8 +143,11 @@ class Formatter extends \yii\base\Formatter
* - a PHP DateTime object
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used. The format string should be the one
* that can be recognized by the PHP `date()` function.
* If null, [[dateFormat]] will be used.
*
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* @return string the formatted result
* @see timeFormat
*/
......@@ -141,8 +176,11 @@ class Formatter extends \yii\base\Formatter
* - a PHP DateTime object
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used. The format string should be the one
* that can be recognized by the PHP `date()` function.
* If null, [[dateFormat]] will be used.
*
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* @return string the formatted result
* @see datetimeFormat
*/
......@@ -213,7 +251,7 @@ class Formatter extends \yii\base\Formatter
/**
* Creates a number formatter based on the given type and format.
* @param integer $type the type of the number formatter
* @param string $format the format to be used
* @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
* @return NumberFormatter the created formatter instance
*/
protected function createNumberFormatter($type, $format)
......
......@@ -204,11 +204,9 @@ abstract class Target extends Component
if ($matched) {
foreach ($this->except as $category) {
$prefix = rtrim($category, '*');
foreach ($messages as $i => $message) {
if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) {
$matched = false;
break;
}
if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) {
$matched = false;
break;
}
}
}
......
......@@ -58,7 +58,7 @@ class DateValidator extends Validator
$date = DateTime::createFromFormat($this->format, $value);
if ($date === false) {
$this->addError($object, $attribute, $this->message);
} elseif ($this->timestampAttribute !== false) {
} elseif ($this->timestampAttribute !== null) {
$object->{$this->timestampAttribute} = $date->getTimestamp();
}
}
......
......@@ -99,7 +99,7 @@ class AccessRule extends Component
if ($this->matchAction($action)
&& $this->matchRole($user)
&& $this->matchIP($request->getUserIP())
&& $this->matchVerb($request->getRequestMethod())
&& $this->matchVerb($request->getMethod())
&& $this->matchController($action->controller)
&& $this->matchCustom($action)
) {
......
......@@ -60,7 +60,7 @@ class HttpCache extends ActionFilter
*/
public function beforeAction($action)
{
$verb = Yii::$app->request->getRequestMethod();
$verb = Yii::$app->request->getMethod();
if ($verb !== 'GET' && $verb !== 'HEAD' || $this->lastModified === null && $this->etagSeed === null) {
return true;
}
......
......@@ -49,7 +49,7 @@ class Request extends \yii\base\Request
/**
* @var string|boolean the name of the POST parameter that is used to indicate if a request is a PUT or DELETE
* request tunneled through POST. Default to '_method'.
* @see getRequestMethod
* @see getMethod
* @see getRestParams
*/
public $restVar = '_method';
......@@ -81,7 +81,7 @@ class Request extends \yii\base\Request
* @return string request method, such as GET, POST, HEAD, PUT, DELETE.
* The value returned is turned into upper case.
*/
public function getRequestMethod()
public function getMethod()
{
if (isset($_POST[$this->restVar])) {
return strtoupper($_POST[$this->restVar]);
......@@ -96,7 +96,7 @@ class Request extends \yii\base\Request
*/
public function getIsPostRequest()
{
return $this->getRequestMethod() === 'POST';
return $this->getMethod() === 'POST';
}
/**
......@@ -105,7 +105,7 @@ class Request extends \yii\base\Request
*/
public function getIsDeleteRequest()
{
return $this->getRequestMethod() === 'DELETE';
return $this->getMethod() === 'DELETE';
}
/**
......@@ -114,7 +114,7 @@ class Request extends \yii\base\Request
*/
public function getIsPutRequest()
{
return $this->getRequestMethod() === 'PUT';
return $this->getMethod() === 'PUT';
}
/**
......@@ -141,7 +141,7 @@ class Request extends \yii\base\Request
/**
* Returns the request parameters for the RESTful request.
* @return array the RESTful request parameters
* @see getRequestMethod
* @see getMethod
*/
public function getRestParams()
{
......@@ -772,7 +772,7 @@ class Request extends \yii\base\Request
if (!$this->enableCsrfValidation) {
return;
}
$method = $this->getRequestMethod();
$method = $this->getMethod();
if ($method === 'POST' || $method === 'PUT' || $method === 'DELETE') {
$cookies = $this->getCookies();
switch ($method) {
......
......@@ -43,6 +43,31 @@ class UrlManager extends Component
* array, one can use the key to represent the pattern and the value the corresponding route.
* For example, `'post/<id:\d+>' => 'post/view'`.
*
* For RESTful routing the mentioned shortcut format also allows you to specify the
* [[UrlRule::verb|HTTP verb]] that the rule should apply for.
* You can do that by prepending it to the pattern, separated by space.
* For example, `'PUT post/<id:\d+>' => 'post/update'`.
* You may specify multiple verbs by separating them with comma
* like this: `'POST,PUT post/index' => 'post/create'`.
* The supported verbs in the shortcut format are: GET, HEAD, POST, PUT and DELETE.
* Note that [[UrlRule::mode|mode]] will be set to PARSING_ONLY when specifying verb in this way
* so you normally would not specify a verb for normal GET request.
*
* Here is an example configuration for RESTful CRUD controller:
*
* ~~~php
* array(
* 'dashboard' => 'site/index',
*
* 'POST <controller:\w+>s' => '<controller>/create',
* '<controller:\w+>s' => '<controller>/index',
*
* 'PUT <controller:\w+>/<id:\d+>' => '<controller>/update',
* 'DELETE <controller:\w+>/<id:\d+>' => '<controller>/delete',
* '<controller:\w+>/<id:\d+>' => '<controller>/view',
* );
* ~~~
*
* Note that if you modify this property after the UrlManager object is created, make sure
* you populate the array with rule objects instead of rule configurations.
*/
......@@ -115,9 +140,14 @@ class UrlManager extends Component
foreach ($this->rules as $key => $rule) {
if (!is_array($rule)) {
$rule = array(
'pattern' => $key,
'route' => $rule,
);
if (preg_match('/^((?:(GET|HEAD|POST|PUT|DELETE),)*(GET|HEAD|POST|PUT|DELETE))\s+(.*)$/', $key, $matches)) {
$rule['verb'] = explode(',', $matches[1]);
$rule['mode'] = UrlRule::PARSING_ONLY;
$key = $matches[4];
}
$rule['pattern'] = $key;
}
$rules[] = Yii::createObject(array_merge($this->ruleConfig, $rule));
}
......
......@@ -171,7 +171,7 @@ class UrlRule extends Object
return false;
}
if ($this->verb !== null && !in_array($request->getRequestMethod(), $this->verb, true)) {
if ($this->verb !== null && !in_array($request->getMethod(), $this->verb, true)) {
return false;
}
......
......@@ -76,7 +76,7 @@ class VerbFilter extends Behavior
{
$action = $event->action->id;
if (isset($this->actions[$action])) {
$verb = Yii::$app->getRequest()->getRequestMethod();
$verb = Yii::$app->getRequest()->getMethod();
$allowed = array_map('strtoupper', $this->actions[$action]);
if (!in_array($verb, $allowed)) {
$event->isValid = false;
......
......@@ -38,14 +38,13 @@ abstract class TestCase extends \yii\test\TestCase
* The application will be destroyed on tearDown() automatically.
* @param array $config The application configuration, if needed
*/
protected function mockApplication($config=array())
protected function mockApplication($config = array(), $appClass = '\yii\console\Application')
{
static $defaultConfig = array(
'id' => 'testapp',
'basePath' => __DIR__,
);
$appClass = $this->getParam( 'appClass', '\yii\web\Application' );
new $appClass(array_merge($defaultConfig,$config));
}
......
<?php
return array(
//'appClass' => '\yii\web\Application',
'appClass' => '\yii\console\Application',
'databases' => array(
'mysql' => array(
'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest',
......
......@@ -239,6 +239,7 @@ class AssetControllerTest extends TestCase
// Then :
$this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!');
$this->assertTrue(is_array(require($bundleFile)), 'Output bundle file has incorrect format!');
$compressedCssFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.css';
$this->assertTrue(file_exists($compressedCssFileName), 'Unable to compress CSS files!');
......
<?php
namespace yiiunit\framework\db;
use yii\db\QueryBuilder;
use yii\db\Schema;
use yii\db\mysql\QueryBuilder as MysqlQueryBuilder;
use yii\db\sqlite\QueryBuilder as SqliteQueryBuilder;
use yii\db\mssql\QueryBuilder as MssqlQueryBuilder;
class QueryBuilderTest extends DatabaseTestCase
{
/**
* @throws \Exception
* @return QueryBuilder
*/
protected function getQueryBuilder()
{
switch($this->driverName)
{
case 'mysql':
return new MysqlQueryBuilder($this->getConnection());
case 'sqlite':
return new SqliteQueryBuilder($this->getConnection());
case 'mssql':
return new MssqlQueryBuilder($this->getConnection());
}
throw new \Exception('Test is not implemented for ' . $this->driverName);
}
/**
* this is not used as a dataprovider for testGetColumnType to speed up the test
* when used as dataprovider every single line will cause a reconnect with the database which is not needed here
*/
public function columnTypes()
{
return array(
array(Schema::TYPE_PK, 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'),
array(Schema::TYPE_PK . '(8)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY'),
array(Schema::TYPE_PK . ' CHECK (value > 5)', 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'),
array(Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'),
array(Schema::TYPE_STRING, 'varchar(255)'),
array(Schema::TYPE_STRING . '(32)', 'varchar(32)'),
array(Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'),
array(Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'),
array(Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'),
array(Schema::TYPE_TEXT, 'text'),
array(Schema::TYPE_TEXT . '(255)', 'text'),
array(Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'),
array(Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'),
array(Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'),
array(Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'),
array(Schema::TYPE_SMALLINT, 'smallint(6)'),
array(Schema::TYPE_SMALLINT . '(8)', 'smallint(8)'),
array(Schema::TYPE_INTEGER, 'int(11)'),
array(Schema::TYPE_INTEGER . '(8)', 'int(8)'),
array(Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int(11) CHECK (value > 5)'),
array(Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int(8) CHECK (value > 5)'),
array(Schema::TYPE_INTEGER . ' NOT NULL', 'int(11) NOT NULL'),
array(Schema::TYPE_BIGINT, 'bigint(20)'),
array(Schema::TYPE_BIGINT . '(8)', 'bigint(8)'),
array(Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint(20) CHECK (value > 5)'),
array(Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint(8) CHECK (value > 5)'),
array(Schema::TYPE_BIGINT . ' NOT NULL', 'bigint(20) NOT NULL'),
array(Schema::TYPE_FLOAT, 'float'),
array(Schema::TYPE_FLOAT . '(16,5)', 'float'),
array(Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'),
array(Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'),
array(Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'),
array(Schema::TYPE_DECIMAL, 'decimal(10,0)'),
array(Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'),
array(Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'),
array(Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'),
array(Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'),
array(Schema::TYPE_DATETIME, 'datetime'),
array(Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
array(Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'),
array(Schema::TYPE_TIMESTAMP, 'timestamp'),
array(Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
array(Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'),
array(Schema::TYPE_TIME, 'time'),
array(Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"),
array(Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'),
array(Schema::TYPE_DATE, 'date'),
array(Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
array(Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'),
array(Schema::TYPE_BINARY, 'blob'),
array(Schema::TYPE_BOOLEAN, 'tinyint(1)'),
array(Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'tinyint(1) NOT NULL DEFAULT 1'),
array(Schema::TYPE_MONEY, 'decimal(19,4)'),
array(Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'),
array(Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'),
array(Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'),
array(Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'),
);
}
/**
*
*/
public function testGetColumnType()
{
$qb = $this->getQueryBuilder();
foreach($this->columnTypes() as $item) {
list ($column, $expected) = $item;
$this->assertEquals($expected, $qb->getColumnType($column));
}
}
}
<?php
namespace yiiunit\framework\db\sqlite;
use yii\db\sqlite\Schema;
use yiiunit\framework\db\QueryBuilderTest;
class SqliteQueryBuilderTest extends QueryBuilderTest
{
public $driverName = 'sqlite';
public function columnTypes()
{
return array(
array(Schema::TYPE_PK, 'integer PRIMARY KEY AUTOINCREMENT NOT NULL'),
array(Schema::TYPE_PK . '(8)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL'),
array(Schema::TYPE_PK . ' CHECK (value > 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'),
array(Schema::TYPE_PK . '(8) CHECK (value > 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'),
array(Schema::TYPE_STRING, 'varchar(255)'),
array(Schema::TYPE_STRING . '(32)', 'varchar(32)'),
array(Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'),
array(Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'),
array(Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'),
array(Schema::TYPE_TEXT, 'text'),
array(Schema::TYPE_TEXT . '(255)', 'text'),
array(Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'),
array(Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'),
array(Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'),
array(Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'),
array(Schema::TYPE_SMALLINT, 'smallint'),
array(Schema::TYPE_SMALLINT . '(8)', 'smallint'),
array(Schema::TYPE_INTEGER, 'integer'),
array(Schema::TYPE_INTEGER . '(8)', 'integer'),
array(Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'),
array(Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'),
array(Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'),
array(Schema::TYPE_BIGINT, 'bigint'),
array(Schema::TYPE_BIGINT . '(8)', 'bigint'),
array(Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'),
array(Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'),
array(Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'),
array(Schema::TYPE_FLOAT, 'float'),
array(Schema::TYPE_FLOAT . '(16,5)', 'float'),
array(Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'),
array(Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'),
array(Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'),
array(Schema::TYPE_DECIMAL, 'decimal(10,0)'),
array(Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'),
array(Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'),
array(Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'),
array(Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'),
array(Schema::TYPE_DATETIME, 'datetime'),
array(Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
array(Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'),
array(Schema::TYPE_TIMESTAMP, 'timestamp'),
array(Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
array(Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'),
array(Schema::TYPE_TIME, 'time'),
array(Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"),
array(Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'),
array(Schema::TYPE_DATE, 'date'),
array(Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
array(Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'),
array(Schema::TYPE_BINARY, 'blob'),
array(Schema::TYPE_BOOLEAN, 'boolean'),
array(Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'boolean NOT NULL DEFAULT 1'),
array(Schema::TYPE_MONEY, 'decimal(19,4)'),
array(Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'),
array(Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'),
array(Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'),
array(Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'),
);
}
}
\ No newline at end of file
......@@ -248,4 +248,58 @@ class UrlManagerTest extends TestCase
$result = $manager->parseRequest($request);
$this->assertFalse($result);
}
public function testParseRESTRequest()
{
$manager = new UrlManager(array(
'cache' => null,
));
$request = new Request;
// pretty URL rules
$manager = new UrlManager(array(
'enablePrettyUrl' => true,
'cache' => null,
'rules' => array(
'PUT,POST post/<id>/<title>' => 'post/create',
'DELETE post/<id>' => 'post/delete',
'post/<id>/<title>' => 'post/view',
'POST/GET' => 'post/get',
),
));
// matching pathinfo GET request
$_SERVER['REQUEST_METHOD'] = 'GET';
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(array('post/view', array('id' => '123', 'title' => 'this+is+sample')), $result);
// matching pathinfo PUT/POST request
$_SERVER['REQUEST_METHOD'] = 'PUT';
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(array('post/create', array('id' => '123', 'title' => 'this+is+sample')), $result);
$_SERVER['REQUEST_METHOD'] = 'POST';
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(array('post/create', array('id' => '123', 'title' => 'this+is+sample')), $result);
// no wrong matching
$_SERVER['REQUEST_METHOD'] = 'POST';
$request->pathInfo = 'POST/GET';
$result = $manager->parseRequest($request);
$this->assertEquals(array('post/get', array()), $result);
// createUrl should ignore REST rules
$this->mockApplication(array(
'components' => array(
'request' => array(
'hostInfo' => 'http://localhost/',
'baseUrl' => '/app'
)
)
), \yii\web\Application::className());
$this->assertEquals('/app/post/delete?id=123', $manager->createUrl('post/delete', array('id' => 123)));
$this->destroyApplication();
unset($_SERVER['REQUEST_METHOD']);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment