Browse Source

Merge branch 'master' of https://github.com/yiisoft/yii2

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
82a2476e48
  1. 2
      apps/bootstrap/commands/HelloController.php
  2. 4
      apps/bootstrap/composer.json
  3. 8
      docs/guide/upgrade-from-v1.md
  4. 2
      extensions/composer/composer.json
  5. 52
      extensions/composer/yii/composer/InstallHandler.php
  6. 2
      framework/composer.json
  7. 1
      framework/yii/YiiBase.php
  8. 133
      framework/yii/bootstrap/Collapse.php
  9. 31
      framework/yii/console/Request.php
  10. 4
      framework/yii/console/controllers/HelpController.php
  11. 24
      framework/yii/db/mssql/Schema.php
  12. 2
      framework/yii/helpers/base/Html.php
  13. 96
      framework/yii/jui/Accordion.php
  14. 86
      framework/yii/jui/Menu.php
  15. 116
      framework/yii/jui/Tabs.php
  16. 23
      framework/yii/jui/assets.php
  17. 4
      framework/yii/requirements/requirements.php
  18. 7
      framework/yii/web/Application.php
  19. 10
      framework/yii/web/UrlManager.php
  20. 1
      framework/yii/widgets/Menu.php
  21. 2
      tests/unit/data/mssql.sql
  22. 55
      tests/unit/framework/db/mssql/MssqlCommandTest.php
  23. 22
      tests/unit/framework/web/UrlManagerTest.php

2
apps/bootstrap/commands/HelloController.php

@ -24,6 +24,6 @@ class HelloController extends Controller
*/ */
public function actionIndex($message = 'hello world') public function actionIndex($message = 'hello world')
{ {
echo $message; echo $message."\n";
} }
} }

4
apps/bootstrap/composer.json

@ -27,11 +27,11 @@
] ]
}, },
"extra": { "extra": {
"writable": [ "yii-install-writable": [
"runtime", "runtime",
"www/assets" "www/assets"
], ],
"executable": [ "yii-install-executable": [
"yii" "yii"
] ]
} }

8
docs/guide/upgrade-from-v1.md

@ -216,12 +216,14 @@ Using a widget is more straightforward in 2.0. You mainly use the `begin()`, `en
methods of the `Widget` class. For example, methods of the `Widget` class. For example,
```php ```php
// $this refers to the View object
// Note that you have to "echo" the result to display it // Note that you have to "echo" the result to display it
echo \yii\widgets\Menu::widget(array('items' => $items)); echo \yii\widgets\Menu::widget(array('items' => $items));
// $this refers to the View object // Passing an array to initialize the object properties
$form = \yii\widgets\ActiveForm::begin($this); $form = \yii\widgets\ActiveForm::begin(array(
'options' => array('class' => 'form-horizontal'),
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
));
... form inputs here ... ... form inputs here ...
\yii\widgets\ActiveForm::end(); \yii\widgets\ActiveForm::end();
``` ```

2
extensions/composer/composer.json

@ -19,7 +19,7 @@
], ],
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"yiisoft/yii2": "dev-master" "yiisoft/yii2": "*"
}, },
"autoload": { "autoload": {
"psr-0": { "yii\\composer": "" } "psr-0": { "yii\\composer": "" }

52
extensions/composer/yii/composer/InstallHandler.php

@ -8,15 +8,28 @@
namespace yii\composer; namespace yii\composer;
use Composer\Script\CommandEvent; use Composer\Script\CommandEvent;
use yii\console\Application;
use yii\console\Exception;
defined('YII_DEBUG') or define('YII_DEBUG', true);
// fcgi doesn't have STDIN defined by default
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
/** /**
* InstallHandler is called by Composer after it installs/updates the current package. * InstallHandler is called by Composer after it installs/updates the current package.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Tobias Munk <schmunk@usrbin.de>
* @since 2.0 * @since 2.0
*/ */
class InstallHandler class InstallHandler
{ {
const PARAM_WRITABLE = 'yii-install-writable';
const PARAM_EXECUTABLE = 'yii-install-executable';
const PARAM_CONFIG = 'yii-install-config';
const PARAM_COMMANDS = 'yii-install-commands';
/** /**
* Sets the correct permissions of files and directories. * Sets the correct permissions of files and directories.
* @param CommandEvent $event * @param CommandEvent $event
@ -24,11 +37,11 @@ class InstallHandler
public static function setPermissions($event) public static function setPermissions($event)
{ {
$options = array_merge(array( $options = array_merge(array(
'writable' => array(), self::PARAM_WRITABLE => array(),
'executable' => array(), self::PARAM_EXECUTABLE => array(),
), $event->getComposer()->getPackage()->getExtra()); ), $event->getComposer()->getPackage()->getExtra());
foreach ((array)$options['writable'] as $path) { foreach ((array)$options[self::PARAM_WRITABLE] as $path) {
echo "Setting writable: $path ..."; echo "Setting writable: $path ...";
if (is_dir($path)) { if (is_dir($path)) {
chmod($path, 0777); chmod($path, 0777);
@ -39,7 +52,7 @@ class InstallHandler
} }
} }
foreach ((array)$options['executable'] as $path) { foreach ((array)$options[self::PARAM_EXECUTABLE] as $path) {
echo "Setting executable: $path ..."; echo "Setting executable: $path ...";
if (is_file($path)) { if (is_file($path)) {
chmod($path, 0755); chmod($path, 0755);
@ -50,4 +63,35 @@ class InstallHandler
} }
} }
} }
/**
* Executes a yii command.
* @param CommandEvent $event
*/
public static function run($event)
{
$options = array_merge(array(
self::PARAM_COMMANDS => array(),
), $event->getComposer()->getPackage()->getExtra());
if (!isset($options[self::PARAM_CONFIG])) {
throw new Exception('Please specify the "' . self::PARAM_CONFIG . '" parameter in composer.json.');
}
$configFile = getcwd() . '/' . $options[self::PARAM_CONFIG];
if (!is_file($configFile)) {
throw new Exception("Config file does not exist: $configFile");
}
require(__DIR__ . '/../../../yii2/yii/Yii.php');
$application = new Application(require($configFile));
$request = $application->getRequest();
foreach ((array)$options[self::PARAM_COMMANDS] as $command) {
$params = str_getcsv($command, ' '); // see http://stackoverflow.com/a/6609509/291573
$request->setParams($params);
list($route, $params) = $request->resolve();
echo "Running command: yii {$command}\n";
$application->runAction($route, $params);
}
}
} }

2
framework/composer.json

@ -64,7 +64,7 @@
"source": "https://github.com/yiisoft/yii2" "source": "https://github.com/yiisoft/yii2"
}, },
"require": { "require": {
"php": ">=5.3.11", "php": ">=5.3.7",
"ext-mbstring": "*", "ext-mbstring": "*",
"lib-pcre": "*" "lib-pcre": "*"
}, },

1
framework/yii/YiiBase.php

@ -616,6 +616,7 @@ class YiiBase
YiiBase::$aliases = array( YiiBase::$aliases = array(
'@yii' => array( '@yii' => array(
'@yii/bootstrap' => __DIR__ . '/bootstrap', '@yii/bootstrap' => __DIR__ . '/bootstrap',
'@yii/jui' => __DIR__ . '/jui',
'@yii' => __DIR__, '@yii' => __DIR__,
), ),
); );

133
framework/yii/bootstrap/Collapse.php

@ -0,0 +1,133 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\bootstrap;
use yii\base\InvalidConfigException;
use yii\helpers\base\ArrayHelper;
use yii\helpers\Html;
/**
* Collapse renders an accordion bootstrap javascript component.
*
* For example:
*
* ```php
* echo Collapse::widget(array(
* 'items' => array(
* // equivalent to the above
* 'Collapsible Group Item #1' => array(
* 'content' => 'Anim pariatur cliche...',
* // open its content by default
* 'contentOptions' => array('class'=>'in')
* ),
* // another group item
* 'Collapsible Group Item #2' => array(
* 'content' => 'Anim pariatur cliche...',
* 'contentOptions' => array(...),
* 'options' => array(...),
* ),
* )
* ));
* ```
*
* @see http://twitter.github.io/bootstrap/javascript.html#collapse
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @since 2.0
*/
class Collapse extends Widget
{
/**
* @var array list of groups in the collapse widget. Each array element represents a single
* group with the following structure:
*
* ```php
* // item key is the actual group header
* 'Collapsible Group Item #1' => array(
* // required, the content (HTML) of the group
* 'content' => 'Anim pariatur cliche...',
* // optional the HTML attributes of the content group
* 'contentOptions'=> array(),
* // optional the HTML attributes of the group
* 'options'=> array(),
* )
* ```
*/
public $items = array();
/**
* Initializes the widget.
*/
public function init()
{
parent::init();
$this->addCssClass($this->options, 'accordion');
}
/**
* Renders the widget.
*/
public function run()
{
echo Html::beginTag('div', $this->options) . "\n";
echo $this->renderItems() . "\n";
echo Html::endTag('div') . "\n";
$this->registerPlugin('collapse');
}
/**
* Renders collapsible items as specified on [[items]].
* @return string the rendering result
*/
public function renderItems()
{
$items = array();
$index = 0;
foreach ($this->items as $header => $item) {
$options = ArrayHelper::getValue($item, 'options', array());
$this->addCssClass($options, 'accordion-group');
$items[] = Html::tag('div', $this->renderItem($header, $item, ++$index), $options);
}
return implode("\n", $items);
}
/**
* Renders a single collapsible item group
* @param string $header a label of the item group [[items]]
* @param array $item a single item from [[items]]
* @param integer $index the item index as each item group content must have an id
* @return string the rendering result
* @throws InvalidConfigException
*/
public function renderItem($header, $item, $index)
{
if (isset($item['content'])) {
$id = $this->options['id'] . '-collapse' . $index;
$options = ArrayHelper::getValue($item, 'contentOptions', array());
$options['id'] = $id;
$this->addCssClass($options, 'accordion-body collapse');
$header = Html::a($header, '#' . $id, array(
'class' => 'accordion-toggle',
'data-toggle' => 'collapse',
'data-parent' => '#' . $this->options['id']
)) . "\n";
$content = Html::tag('div', $item['content'], array('class' => 'accordion-inner')) . "\n";
} else {
throw new InvalidConfigException('The "content" option is required.');
}
$group = array();
$group[] = Html::tag('div', $header, array('class' => 'accordion-heading'));
$group[] = Html::tag('div', $content, $options);
return implode("\n", $group);
}
}

31
framework/yii/console/Request.php

@ -15,9 +15,32 @@ class Request extends \yii\base\Request
{ {
const ANONYMOUS_PARAMS = '-args'; const ANONYMOUS_PARAMS = '-args';
public function getRawParams() private $_params;
/**
* Returns the command line arguments.
* @return array the command line arguments. It does not include the entry script name.
*/
public function getParams()
{
if (!isset($this->_params)) {
if (isset($_SERVER['argv'])) {
$this->_params = $_SERVER['argv'];
array_shift($this->_params);
} else {
$this->_params = array();
}
}
return $this->_params;
}
/**
* Sets the command line arguments.
* @param array $params the command line arguments
*/
public function setParams($params)
{ {
return isset($_SERVER['argv']) ? $_SERVER['argv'] : array(); $this->_params = $params;
} }
/** /**
@ -26,9 +49,7 @@ class Request extends \yii\base\Request
*/ */
public function resolve() public function resolve()
{ {
$rawParams = $this->getRawParams(); $rawParams = $this->getParams();
array_shift($rawParams); // the 1st argument is the yii script name
if (isset($rawParams[0])) { if (isset($rawParams[0])) {
$route = $rawParams[0]; $route = $rawParams[0];
array_shift($rawParams); array_shift($rawParams);

4
framework/yii/console/controllers/HelpController.php

@ -13,7 +13,7 @@ use yii\base\InlineAction;
use yii\console\Controller; use yii\console\Controller;
use yii\console\Exception; use yii\console\Exception;
use yii\console\Request; use yii\console\Request;
use yii\helpers\StringHelper; use yii\helpers\Inflector;
/** /**
* This command provides help information about console commands. * This command provides help information about console commands.
@ -96,7 +96,7 @@ class HelpController extends Controller
foreach ($class->getMethods() as $method) { foreach ($class->getMethods() as $method) {
$name = $method->getName(); $name = $method->getName();
if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') { if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') {
$actions[] = StringHelper::camel2id(substr($name, 6)); $actions[] = Inflector::camel2id(substr($name, 6));
} }
} }
sort($actions); sort($actions);

24
framework/yii/db/mssql/Schema.php

@ -156,14 +156,14 @@ class Schema extends \yii\db\Schema
{ {
$column = new ColumnSchema(); $column = new ColumnSchema();
$column->name = $info['COLUMN_NAME']; $column->name = $info['column_name'];
$column->allowNull = $info['IS_NULLABLE'] == 'YES'; $column->allowNull = $info['is_nullable'] == 'YES';
$column->dbType = $info['DATA_TYPE']; $column->dbType = $info['data_type'];
$column->enumValues = array(); // mssql has only vague equivalents to enum $column->enumValues = array(); // mssql has only vague equivalents to enum
$column->isPrimaryKey = null; // primary key will be determined in findColumns() method $column->isPrimaryKey = null; // primary key will be determined in findColumns() method
$column->autoIncrement = $info['IsIdentity'] == 1; $column->autoIncrement = $info['is_identity'] == 1;
$column->unsigned = stripos($column->dbType, 'unsigned') !== false; $column->unsigned = stripos($column->dbType, 'unsigned') !== false;
$column->comment = $info['Comment'] === null ? '' : $column['Comment']; $column->comment = $info['comment'] === null ? '' : $info['comment'];
$column->type = self::TYPE_STRING; $column->type = self::TYPE_STRING;
if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) {
@ -191,11 +191,11 @@ class Schema extends \yii\db\Schema
$column->phpType = $this->getColumnPhpType($column); $column->phpType = $this->getColumnPhpType($column);
if ($info['COLUMN_DEFAULT'] == '(NULL)') { if ($info['column_default'] == '(NULL)') {
$info['COLUMN_DEFAULT'] = null; $info['column_default'] = null;
} }
if ($column->type !== 'timestamp' || $info['COLUMN_DEFAULT'] !== 'CURRENT_TIMESTAMP') { if ($column->type !== 'timestamp' || $info['column_default'] !== 'CURRENT_TIMESTAMP') {
$column->defaultValue = $column->typecast($info['COLUMN_DEFAULT']); $column->defaultValue = $column->typecast($info['column_default']);
} }
return $column; return $column;
@ -221,9 +221,9 @@ class Schema extends \yii\db\Schema
$sql = <<<SQL $sql = <<<SQL
SELECT SELECT
[t1].*, [t1].[column_name], [t1].[is_nullable], [t1].[data_type], [t1].[column_default],
COLUMNPROPERTY(OBJECT_ID([t1].[table_schema] + '.' + [t1].[table_name]), [t1].[column_name], 'IsIdentity') AS IsIdentity, COLUMNPROPERTY(OBJECT_ID([t1].[table_schema] + '.' + [t1].[table_name]), [t1].[column_name], 'IsIdentity') AS is_identity,
CONVERT(VARCHAR, [t2].[value]) AS Comment CONVERT(VARCHAR, [t2].[value]) AS comment
FROM {$columnsTableName} AS [t1] FROM {$columnsTableName} AS [t1]
LEFT OUTER JOIN [sys].[extended_properties] AS [t2] ON LEFT OUTER JOIN [sys].[extended_properties] AS [t2] ON
[t1].[ordinal_position] = [t2].[minor_id] AND [t1].[ordinal_position] = [t2].[minor_id] AND

2
framework/yii/helpers/base/Html.php

@ -1364,7 +1364,7 @@ class Html
return Yii::$app->getRequest()->getUrl(); return Yii::$app->getRequest()->getUrl();
} else { } else {
$url = Yii::getAlias($url); $url = Yii::getAlias($url);
if ($url[0] === '/' || strpos($url, '://')) { if ($url[0] === '/' || $url[0] === '#' || strpos($url, '://')) {
return $url; return $url;
} else { } else {
return Yii::$app->getRequest()->getBaseUrl() . '/' . $url; return Yii::$app->getRequest()->getBaseUrl() . '/' . $url;

96
framework/yii/jui/Accordion.php

@ -0,0 +1,96 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\jui;
use yii\base\InvalidConfigException;
use yii\helpers\base\ArrayHelper;
use yii\helpers\Html;
/**
* Accordion renders an accordion jQuery UI widget.
*
* For example:
*
* ```php
* echo Accordion::widget(array(
* 'items' => array(
* array(
* 'header' => 'Section 1',
* 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...',
* ),
* array(
* 'header' => 'Section 2',
* 'headerOptions' => array(...),
* 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...',
* 'options' => array(...),
* ),
* ),
* ));
* ```
*
* @see http://api.jqueryui.com/accordion/
* @author Alexander Kochetov <creocoder@gmail.com>
* @since 2.0
*/
class Accordion extends Widget
{
/**
* @var array list of sections in the accordion widget. Each array element represents a single
* section with the following structure:
*
* ```php
* array(
* // required, the header (HTML) of the section
* 'header' => 'Section label',
* // required, the content (HTML) of the section
* 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...',
* // optional the HTML attributes of the section content container
* 'options'=> array(...),
* // optional the HTML attributes of the section header container
* 'headerOptions'=> array(...),
* )
* ```
*/
public $items = array();
/**
* Renders the widget.
*/
public function run()
{
echo Html::beginTag('div', $this->options) . "\n";
echo $this->renderSections() . "\n";
echo Html::endTag('div') . "\n";
$this->registerWidget('accordion');
}
/**
* Renders collapsible sections as specified on [[items]].
* @return string the rendering result.
* @throws InvalidConfigException.
*/
protected function renderSections()
{
$sections = array();
foreach ($this->items as $item) {
if (!isset($item['header'])) {
throw new InvalidConfigException("The 'header' option is required.");
}
if (!isset($item['content'])) {
throw new InvalidConfigException("The 'content' option is required.");
}
$headerOptions = ArrayHelper::getValue($item, 'headerOptions', array());
$sections[] = Html::tag('h3', $item['header'], $headerOptions);
$options = ArrayHelper::getValue($item, 'options', array());
$sections[] = Html::tag('div', $item['content'], $options);;
}
return implode("\n", $sections);
}
}

86
framework/yii/jui/Menu.php

@ -0,0 +1,86 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\jui;
use Yii;
use yii\base\View;
use yii\helpers\Json;
/**
* Menu renders a menu jQuery UI widget.
*
* @see http://api.jqueryui.com/menu/
* @author Alexander Kochetov <creocoder@gmail.com>
* @since 2.0
*/
class Menu extends \yii\widgets\Menu
{
/**
* @var array the options for the underlying jQuery UI widget.
* Please refer to the corresponding jQuery UI widget Web page for possible options.
* For example, [this page](http://api.jqueryui.com/accordion/) shows
* how to use the "Accordion" widget and the supported options (e.g. "header").
*/
public $clientOptions = array();
/**
* @var array the event handlers for the underlying jQuery UI widget.
* Please refer to the corresponding jQuery UI widget Web page for possible events.
* For example, [this page](http://api.jqueryui.com/accordion/) shows
* how to use the "Accordion" widget and the supported events (e.g. "create").
*/
public $clientEvents = array();
/**
* Initializes the widget.
* If you override this method, make sure you call the parent implementation first.
*/
public function init()
{
parent::init();
if (!isset($this->options['id'])) {
$this->options['id'] = $this->getId();
}
}
/**
* Renders the widget.
*/
public function run()
{
parent::run();
$this->registerWidget('menu');
}
/**
* Registers a specific jQuery UI widget and the related events
* @param string $name the name of the jQuery UI widget
*/
protected function registerWidget($name)
{
$id = $this->options['id'];
$view = $this->getView();
$view->registerAssetBundle("yii/jui/$name");
$view->registerAssetBundle(Widget::$theme . "/$name");
if ($this->clientOptions !== false) {
$options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions);
$js = "jQuery('#$id').$name($options);";
$view->registerJs($js);
}
if (!empty($this->clientEvents)) {
$js = array();
foreach ($this->clientEvents as $event => $handler) {
$js[] = "jQuery('#$id').on('$name$event', $handler);";
}
$view->registerJs(implode("\n", $js));
}
}
}

116
framework/yii/jui/Tabs.php

@ -0,0 +1,116 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\jui;
use yii\base\InvalidConfigException;
use yii\helpers\base\ArrayHelper;
use yii\helpers\Html;
/**
* Tabs renders a tabs jQuery UI widget.
*
* For example:
*
* ```php
* echo Tabs::widget(array(
* 'items' => array(
* array(
* 'header' => 'One',
* 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...',
* ),
* array(
* 'header' => 'Two',
* 'headerOptions' => array(...),
* 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...',
* 'options' => array(...),
* ),
* ),
* ));
* ```
*
* @see http://api.jqueryui.com/tabs/
* @author Alexander Kochetov <creocoder@gmail.com>
* @since 2.0
*/
class Tabs extends Widget
{
/**
* @var array list of tabs in the tabs widget. Each array element represents a single
* tab with the following structure:
*
* ```php
* array(
* // required, the header (HTML) of the tab
* 'header' => 'Tab label',
* // required, the content (HTML) of the tab
* 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...',
* // optional the HTML attributes of the tab content container
* 'options'=> array(...),
* // optional the HTML attributes of the tab header container
* 'headerOptions'=> array(...),
* )
* ```
*/
public $items = array();
/**
* Renders the widget.
*/
public function run()
{
echo Html::beginTag('div', $this->options) . "\n";
echo $this->renderHeaders() . "\n";
echo $this->renderContents() . "\n";
echo Html::endTag('div') . "\n";
$this->registerWidget('tabs');
}
/**
* Renders tabs headers as specified on [[items]].
* @return string the rendering result.
* @throws InvalidConfigException.
*/
protected function renderHeaders()
{
$headers = array();
foreach ($this->items as $n => $item) {
if (!isset($item['header'])) {
throw new InvalidConfigException("The 'header' option is required.");
}
$options = ArrayHelper::getValue($item, 'options', array());
$id = isset($options['id']) ? $options['id'] : $this->options['id'] . '-tab' . $n;
$headerOptions = ArrayHelper::getValue($item, 'headerOptions', array());
$headers[] = Html::tag('li', Html::a($item['header'], "#$id"), $headerOptions);
}
return Html::tag('ul', implode("\n", $headers));
}
/**
* Renders tabs contents as specified on [[items]].
* @return string the rendering result.
* @throws InvalidConfigException.
*/
protected function renderContents()
{
$contents = array();
foreach ($this->items as $n => $item) {
if (!isset($item['content'])) {
throw new InvalidConfigException("The 'content' option is required.");
}
$options = ArrayHelper::getValue($item, 'options', array());
if (!isset($options['id'])) {
$options['id'] = $this->options['id'] . '-tab' . $n;
}
$contents[] = Html::tag('div', $item['content'], $options);
}
return implode("\n", $contents);
}
}

23
framework/yii/jui/assets.php

@ -20,7 +20,7 @@ return array(
'js' => array( 'js' => array(
'jquery.ui.accordion.js', 'jquery.ui.accordion.js',
), ),
'depends' => array('yii/jui/core', 'yii/jui/widget'), 'depends' => array('yii/jui/core', 'yii/jui/widget', 'yii/jui/effect/all'),
), ),
'yii/jui/autocomplete' => array( 'yii/jui/autocomplete' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
@ -41,7 +41,7 @@ return array(
'js' => array( 'js' => array(
'jquery.ui.datepicker.js', 'jquery.ui.datepicker.js',
), ),
'depends' => array('yii/jui/core'), 'depends' => array('yii/jui/core', 'yii/jui/effect/all'),
), ),
'yii/jui/datepicker/i18n/af' => array( 'yii/jui/datepicker/i18n/af' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
@ -559,7 +559,7 @@ return array(
'js' => array( 'js' => array(
'jquery.ui.dialog.js', 'jquery.ui.dialog.js',
), ),
'depends' => array('yii/jui/core', 'yii/jui/widget', 'yii/jui/button', 'yii/jui/draggable', 'yii/jui/mouse', 'yii/jui/position', 'yii/jui/resizeable'), 'depends' => array('yii/jui/core', 'yii/jui/widget', 'yii/jui/button', 'yii/jui/draggable', 'yii/jui/mouse', 'yii/jui/position', 'yii/jui/resizeable', 'yii/jui/effect/all'),
), ),
'yii/jui/draggable' => array( 'yii/jui/draggable' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
@ -582,6 +582,13 @@ return array(
), ),
'depends' => array('yii/jquery'), 'depends' => array('yii/jquery'),
), ),
'yii/jui/effect/all' => array(
'sourcePath' => __DIR__ . '/assets',
'js' => array(
'jquery.ui.effect.js',
),
'depends' => array('yii/jui/effect/blind', 'yii/jui/effect/bounce', 'yii/jui/effect/clip', 'yii/jui/effect/drop', 'yii/jui/effect/explode', 'yii/jui/effect/fade', 'yii/jui/effect/fold', 'yii/jui/effect/highlight', 'yii/jui/effect/pulsate', 'yii/jui/effect/scale', 'yii/jui/effect/shake', 'yii/jui/effect/slide', 'yii/jui/effect/transfer'),
),
'yii/jui/effect/blind' => array( 'yii/jui/effect/blind' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
'js' => array( 'js' => array(
@ -741,14 +748,14 @@ return array(
'js' => array( 'js' => array(
'jquery.ui.tabs.js', 'jquery.ui.tabs.js',
), ),
'depends' => array('yii/jui/core', 'yii/jui/widget'), 'depends' => array('yii/jui/core', 'yii/jui/widget', 'yii/jui/effect/all'),
), ),
'yii/jui/tooltip' => array( 'yii/jui/tooltip' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
'js' => array( 'js' => array(
'jquery.ui.tooltip.js', 'jquery.ui.tooltip.js',
), ),
'depends' => array('yii/jui/core', 'yii/jui/widget', 'yii/jui/position'), 'depends' => array('yii/jui/core', 'yii/jui/widget', 'yii/jui/position', 'yii/jui/effect/all'),
), ),
'yii/jui/theme/base' => array( 'yii/jui/theme/base' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
@ -775,7 +782,7 @@ return array(
'css' => array( 'css' => array(
'themes/base/jquery.ui.autocomplete.css', 'themes/base/jquery.ui.autocomplete.css',
), ),
'depends' => array('yii/jui/theme/base/core'), 'depends' => array('yii/jui/theme/base/core', 'yii/jui/theme/base/menu'),
), ),
'yii/jui/theme/base/button' => array( 'yii/jui/theme/base/button' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
@ -796,7 +803,7 @@ return array(
'css' => array( 'css' => array(
'themes/base/jquery.ui.dialog.css', 'themes/base/jquery.ui.dialog.css',
), ),
'depends' => array('yii/jui/theme/base/core'), 'depends' => array('yii/jui/theme/base/core', 'yii/jui/theme/base/button', 'yii/jui/theme/base/resizeable'),
), ),
'yii/jui/theme/base/menu' => array( 'yii/jui/theme/base/menu' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',
@ -838,7 +845,7 @@ return array(
'css' => array( 'css' => array(
'themes/base/jquery.ui.spinner.css', 'themes/base/jquery.ui.spinner.css',
), ),
'depends' => array('yii/jui/theme/base/core'), 'depends' => array('yii/jui/theme/base/core', 'yii/jui/theme/base/button'),
), ),
'yii/jui/theme/base/tabs' => array( 'yii/jui/theme/base/tabs' => array(
'sourcePath' => __DIR__ . '/assets', 'sourcePath' => __DIR__ . '/assets',

4
framework/yii/requirements/requirements.php

@ -9,9 +9,9 @@ return array(
array( array(
'name' => 'PHP version', 'name' => 'PHP version',
'mandatory' => true, 'mandatory' => true,
'condition' => version_compare(PHP_VERSION, '5.3.11', '>='), 'condition' => version_compare(PHP_VERSION, '5.3.7', '>='),
'by' => '<a href="http://www.yiiframework.com">Yii Framework</a>', 'by' => '<a href="http://www.yiiframework.com">Yii Framework</a>',
'memo' => 'PHP 5.3.11 or higher is required.', 'memo' => 'PHP 5.3.7 or higher is required.',
), ),
array( array(
'name' => 'Reflection extension', 'name' => 'Reflection extension',

7
framework/yii/web/Application.php

@ -8,6 +8,8 @@
namespace yii\web; namespace yii\web;
use Yii; use Yii;
use yii\base\HttpException;
use yii\base\InvalidRouteException;
/** /**
* Application is the base class for all application classes. * Application is the base class for all application classes.
@ -25,6 +27,7 @@ class Application extends \yii\base\Application
/** /**
* Processes the request. * Processes the request.
* @return integer the exit status of the controller action (0 means normal, non-zero values mean abnormal) * @return integer the exit status of the controller action (0 means normal, non-zero values mean abnormal)
* @throws HttpException if the request cannot be resolved.
*/ */
public function processRequest() public function processRequest()
{ {
@ -32,7 +35,11 @@ class Application extends \yii\base\Application
Yii::setAlias('@wwwroot', dirname($request->getScriptFile())); Yii::setAlias('@wwwroot', dirname($request->getScriptFile()));
Yii::setAlias('@www', $request->getBaseUrl()); Yii::setAlias('@www', $request->getBaseUrl());
list ($route, $params) = $request->resolve(); list ($route, $params) = $request->resolve();
try {
return $this->runAction($route, $params); return $this->runAction($route, $params);
} catch (InvalidRouteException $e) {
throw new HttpException(404, $e->getMessage(), $e->getCode(), $e);
}
} }
private $_homeUrl; private $_homeUrl;

10
framework/yii/web/UrlManager.php

@ -27,6 +27,12 @@ class UrlManager extends Component
*/ */
public $enablePrettyUrl = false; public $enablePrettyUrl = false;
/** /**
* @var boolean whether to enable strict parsing. If strict parsing is enabled, the incoming
* requested URL must match at least one of the [[rules]] in order to be treated as a valid request.
* This property is used only when [[enablePrettyUrl]] is true.
*/
public $enableStrictParsing = false;
/**
* @var array the rules for creating and parsing URLs when [[enablePrettyUrl]] is true. * @var array the rules for creating and parsing URLs when [[enablePrettyUrl]] is true.
* This property is used only if [[enablePrettyUrl]] is true. Each element in the array * This property is used only if [[enablePrettyUrl]] is true. Each element in the array
* is the configuration array for creating a single URL rule. The configuration will * is the configuration array for creating a single URL rule. The configuration will
@ -139,6 +145,10 @@ class UrlManager extends Component
} }
} }
if ($this->enableStrictParsing) {
return false;
}
$suffix = (string)$this->suffix; $suffix = (string)$this->suffix;
if ($suffix !== '' && $suffix !== '/' && $pathInfo !== '') { if ($suffix !== '' && $suffix !== '/' && $pathInfo !== '') {
$n = strlen($this->suffix); $n = strlen($this->suffix);

1
framework/yii/widgets/Menu.php

@ -26,7 +26,6 @@ use yii\helpers\Html;
* The following example shows how to use Menu: * The following example shows how to use Menu:
* *
* ~~~ * ~~~
* // $this is the view object currently being used
* echo Menu::widget(array( * echo Menu::widget(array(
* 'items' => array( * 'items' => array(
* // Important: you need to specify url as 'controller/action', * // Important: you need to specify url as 'controller/action',

2
tests/unit/data/mssql.sql

@ -62,7 +62,7 @@ CREATE TABLE [dbo].[tbl_type] (
[char_col3] [text], [char_col3] [text],
[float_col] [decimal](4,3) NOT NULL, [float_col] [decimal](4,3) NOT NULL,
[float_col2] [float] DEFAULT '1.23', [float_col2] [float] DEFAULT '1.23',
[blob_col] [binary], [blob_col] [varbinary](MAX),
[numeric_col] [decimal](5,2) DEFAULT '33.22', [numeric_col] [decimal](5,2) DEFAULT '33.22',
[time] [datetime] NOT NULL DEFAULT '2002-01-01 00:00:00', [time] [datetime] NOT NULL DEFAULT '2002-01-01 00:00:00',
[bool_col] [tinyint] NOT NULL, [bool_col] [tinyint] NOT NULL,

55
tests/unit/framework/db/mssql/MssqlCommandTest.php

@ -21,11 +21,62 @@ class MssqlCommandTest extends \yiiunit\framework\db\CommandTest
function testPrepareCancel() function testPrepareCancel()
{ {
$this->markTestIncomplete(); $this->markTestSkipped('MSSQL driver does not support this feature.');
} }
function testBindParamValue() function testBindParamValue()
{ {
$this->markTestIncomplete(); $db = $this->getConnection();
// bindParam
$sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, :name, :address)';
$command = $db->createCommand($sql);
$email = 'user4@example.com';
$name = 'user4';
$address = 'address4';
$command->bindParam(':email', $email);
$command->bindParam(':name', $name);
$command->bindParam(':address', $address);
$command->execute();
$sql = 'SELECT name FROM tbl_customer WHERE email=:email';
$command = $db->createCommand($sql);
$command->bindParam(':email', $email);
$this->assertEquals($name, $command->queryScalar());
$sql = 'INSERT INTO tbl_type (int_col, char_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, :char_col, :float_col, CONVERT([varbinary], :blob_col), :numeric_col, :bool_col)';
$command = $db->createCommand($sql);
$intCol = 123;
$charCol = 'abc';
$floatCol = 1.23;
$blobCol = "\x10\x11\x12";
$numericCol = '1.23';
$boolCol = false;
$command->bindParam(':int_col', $intCol);
$command->bindParam(':char_col', $charCol);
$command->bindParam(':float_col', $floatCol);
$command->bindParam(':blob_col', $blobCol);
$command->bindParam(':numeric_col', $numericCol);
$command->bindParam(':bool_col', $boolCol);
$this->assertEquals(1, $command->execute());
$sql = 'SELECT int_col, char_col, float_col, CONVERT([nvarchar], blob_col) AS blob_col, numeric_col FROM tbl_type';
$row = $db->createCommand($sql)->queryRow();
$this->assertEquals($intCol, $row['int_col']);
$this->assertEquals($charCol, trim($row['char_col']));
$this->assertEquals($floatCol, $row['float_col']);
$this->assertEquals($blobCol, $row['blob_col']);
$this->assertEquals($numericCol, $row['numeric_col']);
// bindValue
$sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, \'user5\', \'address5\')';
$command = $db->createCommand($sql);
$command->bindValue(':email', 'user5@example.com');
$command->execute();
$sql = 'SELECT email FROM tbl_customer WHERE name=:name';
$command = $db->createCommand($sql);
$command->bindValue(':name', 'user5');
$this->assertEquals('user5@example.com', $command->queryScalar());
} }
} }

22
tests/unit/framework/web/UrlManagerTest.php

@ -224,5 +224,27 @@ class UrlManagerTest extends \yiiunit\TestCase
$request->pathInfo = 'site/index'; $request->pathInfo = 'site/index';
$result = $manager->parseRequest($request); $result = $manager->parseRequest($request);
$this->assertFalse($result); $this->assertFalse($result);
// strict parsing
$manager = new UrlManager(array(
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'suffix' => '.html',
'cache' => null,
'rules' => array(
array(
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
),
),
));
// matching pathinfo
$request->pathInfo = 'post/123/this+is+sample.html';
$result = $manager->parseRequest($request);
$this->assertEquals(array('post/view', array('id' => '123', 'title' => 'this+is+sample')), $result);
// unmatching pathinfo
$request->pathInfo = 'site/index.html';
$result = $manager->parseRequest($request);
$this->assertFalse($result);
} }
} }

Loading…
Cancel
Save