From b19f640b66b373751a0b1679a2e37811bc24402b Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 11:14:25 -0400 Subject: [PATCH 01/23] Added Breadcrumbs.php --- framework/widgets/Breadcrumbs.php | 100 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 framework/widgets/Breadcrumbs.php diff --git a/framework/widgets/Breadcrumbs.php b/framework/widgets/Breadcrumbs.php new file mode 100644 index 0000000..f60908f --- /dev/null +++ b/framework/widgets/Breadcrumbs.php @@ -0,0 +1,100 @@ + + * @since 2.0 + */ +class Breadcrumbs extends Widget +{ + /** + * @var array the HTML attributes for the breadcrumb container tag. The "tag" element is + * specially handled which specifies the tag name of the container element. If not set, it will default to "ul". + */ + public $options = array('tag' => 'ul', 'class' => 'breadcrumb'); + /** + * @var boolean whether to HTML encode the link labels. Defaults to true. + */ + public $encodeLabels = true; + /** + * @var string the first hyperlink in the breadcrumbs (called home link). + * If this property is not set, it defaults to a link pointing to {@link CWebApplication::homeUrl} with label 'Home'. + * If this property is false, the home link will not be rendered. + */ + public $homeLink; + /** + * @var array list of hyperlinks to appear in the breadcrumbs. If this property is empty, + * the widget will not render anything. Each key-value pair in the array + * will be used to generate a hyperlink by calling CHtml::link(key, value). For this reason, the key + * refers to the label of the link while the value can be a string or an array (used to + * create a URL). For more details, please refer to {@link CHtml::link}. + * If an element's key is an integer, it means the element will be rendered as a label only (meaning the current page). + * + * The following example will generate breadcrumbs as "Home > Sample post > Edit", where "Home" points to the homepage, + * "Sample post" points to the "index.php?r=post/view&id=12" page, and "Edit" is a label. Note that the "Home" link + * is specified via {@link homeLink} separately. + * + *
+	 * array(
+	 *     'Sample post'=>array('post/view', 'id'=>12),
+	 *     'Edit',
+	 * )
+	 * 
+ */ + public $links = array(); + /** + * @var string String, specifies how each active item is rendered. Defaults to + * "{label}", where "{label}" will be replaced by the corresponding item + * label while "{url}" will be replaced by the URL of the item. + * @since 1.1.11 + */ + public $itemTemplate = "
  • {link} /
  • \n"; + /** + * @var string String, specifies how each inactive item is rendered. Defaults to + * "{label}", where "{label}" will be replaced by the corresponding item label. + * Note that inactive template does not have "{url}" parameter. + * @since 1.1.11 + */ + public $activeItemTemplate = "
  • {link}
  • \n"; + /** + * @var string the separator between links in the breadcrumbs. Defaults to ' » '. + */ + public $separator = ' » '; + + /** + * Renders the content of the portlet. + */ + public function run() + { + if (!empty($this->links)) { + return; + } + $links = array(); + if ($this->homeLink === null) { + $links[] = Html::a(Html::encode('yii|Home'), Yii::$app->homeUrl); + } elseif ($this->homeLink !== false) { + $links[] = $this->homeLink; + } + foreach ($this->links as $link) { + if (strpos($link, 'itemTemplate, array('{link}' => $link)); + } else { + $links[] = strtr($this->activeItemTemplate, array('{link}' => $link)); + } + } + $tagName = isset($this->options['tag']) ? $this->options['tag'] : 'ul'; + unset($this->options['tag']); + echo Html::tag($tagName, implode('', $this->links), $this->options); + } +} \ No newline at end of file From 02319b99a075ad2cccad5b846b526755bc0da755 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 12:14:40 -0400 Subject: [PATCH 02/23] Fixes issue #54: Implemented Breadcrumbs. --- apps/bootstrap/protected/views/layouts/main.php | 3 + apps/bootstrap/protected/views/site/about.php | 1 + apps/bootstrap/protected/views/site/contact.php | 1 + apps/bootstrap/protected/views/site/login.php | 1 + framework/widgets/Breadcrumbs.php | 99 +++++++++++++++---------- 5 files changed, 67 insertions(+), 38 deletions(-) diff --git a/apps/bootstrap/protected/views/layouts/main.php b/apps/bootstrap/protected/views/layouts/main.php index 8fb915a..1240053 100644 --- a/apps/bootstrap/protected/views/layouts/main.php +++ b/apps/bootstrap/protected/views/layouts/main.php @@ -39,6 +39,9 @@ $this->registerAssetBundle('app'); + widget('yii\widgets\Breadcrumbs', array( + 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), + )); ?>
    diff --git a/apps/bootstrap/protected/views/site/about.php b/apps/bootstrap/protected/views/site/about.php index 7ebc5d5..86e19e1 100644 --- a/apps/bootstrap/protected/views/site/about.php +++ b/apps/bootstrap/protected/views/site/about.php @@ -4,6 +4,7 @@ use yii\helpers\Html; * @var yii\base\View $this */ $this->title = 'About'; +$this->params['breadcrumbs'][] = $this->title; ?>

    title); ?>

    diff --git a/apps/bootstrap/protected/views/site/contact.php b/apps/bootstrap/protected/views/site/contact.php index 4ca40f1..5cb5a8e 100644 --- a/apps/bootstrap/protected/views/site/contact.php +++ b/apps/bootstrap/protected/views/site/contact.php @@ -6,6 +6,7 @@ use yii\helpers\Html; * @var app\models\ContactForm $model */ $this->title = 'Contact'; +$this->params['breadcrumbs'][] = $this->title; ?>

    title); ?>

    diff --git a/apps/bootstrap/protected/views/site/login.php b/apps/bootstrap/protected/views/site/login.php index 8672eeb..f7f842e 100644 --- a/apps/bootstrap/protected/views/site/login.php +++ b/apps/bootstrap/protected/views/site/login.php @@ -6,6 +6,7 @@ use yii\helpers\Html; * @var app\models\LoginForm $model */ $this->title = 'Login'; +$this->params['breadcrumbs'][] = $this->title; ?>

    title); ?>

    diff --git a/framework/widgets/Breadcrumbs.php b/framework/widgets/Breadcrumbs.php index f60908f..a55d00f 100644 --- a/framework/widgets/Breadcrumbs.php +++ b/framework/widgets/Breadcrumbs.php @@ -5,13 +5,40 @@ * @license http://www.yiiframework.com/license/ */ -namespace yii\web; +namespace yii\widgets; use Yii; use yii\base\Widget; +use yii\base\InvalidConfigException; use yii\helpers\Html; /** + * Breadcrumbs displays a list of links indicating the position of the current page in the whole site hierarchy. + * + * For example, breadcrumbs like "Home / Sample Post / Edit" means the user is viewing an edit page + * for the "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home" + * to return to the homepage. + * + * To use Breadcrumbs, you need to configure its [[links]] property, which specifiesthe links to be displayed. For example, + * + * ~~~ + * $this->widget('yii\widgets\Breadcrumbs', array( + * 'links' => array( + * array('label' => 'Sample Post', 'url' => array('post/edit', 'id' => 1)), + * 'Edit', + * ), + * )); + * ~~~ + * + * Because breadcrumbs usually appears in nearly every page of a website, you may consider place it in a layout view. + * You can then use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different + * views. In the layout view, you assign this view parameter to the [[links]] property like the following: + * + * ~~~ + * $this->widget('yii\widgets\Breadcrumbs', array( + * 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), + * )); + * ~~~ * * @author Qiang Xue * @since 2.0 @@ -24,77 +51,73 @@ class Breadcrumbs extends Widget */ public $options = array('tag' => 'ul', 'class' => 'breadcrumb'); /** - * @var boolean whether to HTML encode the link labels. Defaults to true. + * @var boolean whether to HTML-encode the link labels. */ public $encodeLabels = true; /** * @var string the first hyperlink in the breadcrumbs (called home link). - * If this property is not set, it defaults to a link pointing to {@link CWebApplication::homeUrl} with label 'Home'. - * If this property is false, the home link will not be rendered. + * If this property is not set, it will default to a link pointing to [[\yii\web\Application::homeUrl]] + * with the label 'Home'. If this property is false, the home link will not be rendered. */ public $homeLink; /** - * @var array list of hyperlinks to appear in the breadcrumbs. If this property is empty, - * the widget will not render anything. Each key-value pair in the array - * will be used to generate a hyperlink by calling CHtml::link(key, value). For this reason, the key - * refers to the label of the link while the value can be a string or an array (used to - * create a URL). For more details, please refer to {@link CHtml::link}. - * If an element's key is an integer, it means the element will be rendered as a label only (meaning the current page). - * - * The following example will generate breadcrumbs as "Home > Sample post > Edit", where "Home" points to the homepage, - * "Sample post" points to the "index.php?r=post/view&id=12" page, and "Edit" is a label. Note that the "Home" link - * is specified via {@link homeLink} separately. + * @var array list of links to appear in the breadcrumbs. If this property is empty, + * the widget will not render anything. Each array element represents a single link in the breadcrumbs + * with the following structure: * - *
    +	 * ~~~
     	 * array(
    -	 *     'Sample post'=>array('post/view', 'id'=>12),
    -	 *     'Edit',
    +	 *     'label' => 'label of the link',  // required
    +	 *     'url' => 'url of the link',      // optional, will be processed by Html::url()
     	 * )
    -	 * 
    + * ~~~ + * + * If a link is active, you only need to specify its "label", and instead of writing `array('label' => $label)`, + * you should simply use `$label`. */ public $links = array(); /** - * @var string String, specifies how each active item is rendered. Defaults to - * "{label}", where "{label}" will be replaced by the corresponding item - * label while "{url}" will be replaced by the URL of the item. - * @since 1.1.11 + * @var string the template used to render each inactive item in the breadcrumbs. The token `{link}` + * will be replaced with the actual HTML link for each inactive item. */ public $itemTemplate = "
  • {link} /
  • \n"; /** - * @var string String, specifies how each inactive item is rendered. Defaults to - * "{label}", where "{label}" will be replaced by the corresponding item label. - * Note that inactive template does not have "{url}" parameter. - * @since 1.1.11 + * @var string the template used to render each active item in the breadcrumbs. The token `{link}` + * will be replaced with the actual HTML link for each active item. */ public $activeItemTemplate = "
  • {link}
  • \n"; - /** - * @var string the separator between links in the breadcrumbs. Defaults to ' » '. - */ - public $separator = ' » '; /** - * Renders the content of the portlet. + * Renders the widget. */ public function run() { - if (!empty($this->links)) { + if (empty($this->links)) { return; } $links = array(); if ($this->homeLink === null) { - $links[] = Html::a(Html::encode('yii|Home'), Yii::$app->homeUrl); + $links[] = strtr($this->itemTemplate, array('{link}' => Html::a(Yii::t('yii|Home'), Yii::$app->homeUrl))); } elseif ($this->homeLink !== false) { - $links[] = $this->homeLink; + $links[] = strtr($this->itemTemplate, array('{link}' => $this->homeLink)); } foreach ($this->links as $link) { - if (strpos($link, 'itemTemplate, array('{link}' => $link)); + if (!is_array($link)) { + $link = array('label' => $link); + } + if (isset($link['label'])) { + $label = $this->encodeLabels ? Html::encode($link['label']) : $link['label']; + } else { + throw new InvalidConfigException('The "label" element is required for each link.'); + } + if (isset($link['url'])) { + $links[] = strtr($this->itemTemplate, array('{link}' => Html::a($label, $link['url']))); } else { - $links[] = strtr($this->activeItemTemplate, array('{link}' => $link)); + $links[] = strtr($this->activeItemTemplate, array('{link}' => $label)); } } $tagName = isset($this->options['tag']) ? $this->options['tag'] : 'ul'; unset($this->options['tag']); - echo Html::tag($tagName, implode('', $this->links), $this->options); + echo Html::tag($tagName, implode('', $links), $this->options); } } \ No newline at end of file From f01414fff2a888123e90d13143036147929456ef Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 13:34:28 -0400 Subject: [PATCH 03/23] Refactored Breadcrumbs. --- framework/widgets/ActiveForm.php | 1 - framework/widgets/Breadcrumbs.php | 54 +++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/framework/widgets/ActiveForm.php b/framework/widgets/ActiveForm.php index c11bceb..61416e2 100644 --- a/framework/widgets/ActiveForm.php +++ b/framework/widgets/ActiveForm.php @@ -12,7 +12,6 @@ use yii\base\Widget; use yii\base\Model; use yii\helpers\Html; use yii\helpers\Json; -use yii\helpers\JsExpression; /** * ActiveForm ... diff --git a/framework/widgets/Breadcrumbs.php b/framework/widgets/Breadcrumbs.php index a55d00f..22d09b3 100644 --- a/framework/widgets/Breadcrumbs.php +++ b/framework/widgets/Breadcrumbs.php @@ -46,10 +46,13 @@ use yii\helpers\Html; class Breadcrumbs extends Widget { /** - * @var array the HTML attributes for the breadcrumb container tag. The "tag" element is - * specially handled which specifies the tag name of the container element. If not set, it will default to "ul". + * @var string the name of the breadcrumb container tag. */ - public $options = array('tag' => 'ul', 'class' => 'breadcrumb'); + public $tag = 'ul'; + /** + * @var array the HTML attributes for the breadcrumb container tag. + */ + public $options = array('class' => 'breadcrumb'); /** * @var boolean whether to HTML-encode the link labels. */ @@ -97,27 +100,40 @@ class Breadcrumbs extends Widget } $links = array(); if ($this->homeLink === null) { - $links[] = strtr($this->itemTemplate, array('{link}' => Html::a(Yii::t('yii|Home'), Yii::$app->homeUrl))); + $links[] = $this->renderItem(array( + 'label' => Yii::t('yii|Home'), + 'url' => Yii::$app->homeUrl, + ), $this->itemTemplate); } elseif ($this->homeLink !== false) { - $links[] = strtr($this->itemTemplate, array('{link}' => $this->homeLink)); + $links[] = $this->renderItem($this->homeLink, $this->itemTemplate); } foreach ($this->links as $link) { if (!is_array($link)) { $link = array('label' => $link); } - if (isset($link['label'])) { - $label = $this->encodeLabels ? Html::encode($link['label']) : $link['label']; - } else { - throw new InvalidConfigException('The "label" element is required for each link.'); - } - if (isset($link['url'])) { - $links[] = strtr($this->itemTemplate, array('{link}' => Html::a($label, $link['url']))); - } else { - $links[] = strtr($this->activeItemTemplate, array('{link}' => $label)); - } + $links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate); + } + echo Html::tag($this->tag, implode('', $links), $this->options); + } + + /** + * Renders a single breadcrumb item. + * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional. + * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the link. + * @return string the rendering result + * @throws InvalidConfigException if `$link` does not have "label" element. + */ + protected function renderItem($link, $template) + { + if (isset($link['label'])) { + $label = $this->encodeLabels ? Html::encode($link['label']) : $link['label']; + } else { + throw new InvalidConfigException('The "label" element is required for each link.'); + } + if (isset($link['url'])) { + return strtr($template, array('{link}' => Html::a($label, $link['url']))); + } else { + return strtr($template, array('{link}' => $label)); } - $tagName = isset($this->options['tag']) ? $this->options['tag'] : 'ul'; - unset($this->options['tag']); - echo Html::tag($tagName, implode('', $links), $this->options); } -} \ No newline at end of file +} From c6642a3d65336ebe0550d0d282e61b07ab140c68 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 14:50:16 -0400 Subject: [PATCH 04/23] upgrading instructions WIP --- docs/guide/index.md | 2 +- docs/guide/upgrade-from-v1.md | 163 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 docs/guide/upgrade-from-v1.md diff --git a/docs/guide/index.md b/docs/guide/index.md index 6ad733c..dd72ca3 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -27,4 +27,4 @@ * [Performance Tuning](performance.md) * [Testing](testing.md) * [Automatic Code Generation](gii.md) -* [Upgrading from 1.1 to 2.0](upgrade.md) +* [Upgrading from 1.1 to 2.0](upgrade-from-v1.md) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md new file mode 100644 index 0000000..af3c9ca --- /dev/null +++ b/docs/guide/upgrade-from-v1.md @@ -0,0 +1,163 @@ +Upgrading from Yii 1.1 +====================== + +In this chapter, we list the major changes introduced in Yii 2.0 since version 1.1. +We hope this list will make it easier for you to upgrade from Yii 1.1 and quickly +master Yii 2.0 based on your existing Yii knowledge. + + +Component and Object +-------------------- + +Yii 2.0 breaks the `CComponent` class in 1.1 into two classes: `Object` and `Component`. +The `Object` class is a lightweight base class that allows defining class properties +via getters and setters. The `Component` class extends from `Object` and supports +the event feature and the behavior feature. + +If your class does not need the event or behavior feature, you should consider using +`Object` as the based class. This is usually the case for classes that represent basic +data structures. + + +Object Configuration +-------------------- + +The `Object` class introduces a convention for configuring objects. In general, any +descendant class of `Object` should follow this convention when declaring a constructor: + +~~~ +class MyClass extends \yii\Object +{ + public function __construct($param1, $param2, $config = array()) + { + // ... + parent::__construct($config); + } + + public function init() + { + parent::init(); + // ... at this point, all configurations have been applied ... + } +} +~~~ + +In descendant classes, you can override the `init()` method to do initialization work +that should be done after all configurations are applied. + +By following this convention, you will be able to use the powerful object creation method via: + +~~~ +$object = Yii::createObject(array( + 'class' => 'MyClass', + 'property1' => 'abc', + 'property2' => 'cde', +), $param1, $param2); +~~~ + + +Events +------ + +There is no longer the need to define an `on`-method in order to define an event in Yii 2.0. +Instead, you can use whatever event names. To attach a handler to an event, you should +use the `on` method now: + +~~~ +$component->on($eventName, $handler); +// To detach the handler, use: +// $component->off($eventName, $handler); +~~~ + +When you attach a handler, you can now associate it with some parameters which can be later +accessed via the event parameter by the handler: + +~~~ +$component->on($eventName, $handler, $params); +~~~ + +Because of this change, you can now use "global" events. Simply trigger and attach handlers to +an event of the application instance: + +~~~ +Yii::$app->on($eventName, $handler); +.... +// this will trigger the event and cause $handler to be invoked. +Yii::$app->trigger($eventName); +~~~ + + +View +---- + +Yii 2.0 introduces a `View` class to represent the view part in the MVC pattern. +It can be configured globally through the "view" application component. It is also +accessible in any view file via `$this`. This is one of the biggest changes compared to 1.1: +**`$this` in a view file no longer refers to the controller or widget object.** +It refers to the view object that is used to render the view file. To access the controller +or the widget object, you have to use `$this->context` now. + +Because you can access the view object through the "view" application component, +you can now render a view file like the following anywhere in your code, not necessarily +in controllers or widgets: + +~~~ +$content = Yii::$app->view->renderFile($viewFile, $params); +// You can also explicitly create a new View instance to do the rendering +// $view = new View; +// $view->renderFile($viewFile, $params); +~~~ + +Also, there is no more `CClientScript` in Yii 2.0. The `View` class has taken over its role +with significant improvements. For more details, please see the "assets" subsection. + +TBD: built-in renderers + +Models +------ + +Controllers +----------- + +Themes +------ + +Console Applications +-------------------- + +I18N +---- + +Behaviors +--------- + +TBD + +Action filters are replaced by behaviors (`ActiionFilter`). + + +Assets +------ + +Static Helpers +-------------- + +`ActiveForm` +------------ + + +Query Builder +------------- + + +ActiveRecord +------------ + +User and Identity +----------------- + +URL Management +-------------- + +Response +-------- \ No newline at end of file From 235ad40c2bee853ae225642d9d241323a4e1bd67 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 14:52:26 -0400 Subject: [PATCH 05/23] Menu WIP --- framework/widgets/Menu.php | 282 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 framework/widgets/Menu.php diff --git a/framework/widgets/Menu.php b/framework/widgets/Menu.php new file mode 100644 index 0000000..3af620d --- /dev/null +++ b/framework/widgets/Menu.php @@ -0,0 +1,282 @@ + + * @since 2.0 + */ +class Menu extends Widget +{ + /** + * @var array list of menu items. Each menu item is specified as an array of name-value pairs. + * Possible option names include the following: + *
      + *
    • label: string, optional, specifies the menu item label. When {@link encodeLabel} is true, the label + * will be HTML-encoded. If the label is not specified, it defaults to an empty string.
    • + *
    • url: string or array, optional, specifies the URL of the menu item. It is passed to {@link Html::normalizeUrl} + * to generate a valid URL. If this is not set, the menu item will be rendered as a span text.
    • + *
    • visible: boolean, optional, whether this menu item is visible. Defaults to true. + * This can be used to control the visibility of menu items based on user permissions.
    • + *
    • items: array, optional, specifies the sub-menu items. Its format is the same as the parent items.
    • + *
    • active: boolean, optional, whether this menu item is in active state (currently selected). + * If a menu item is active and {@link activeClass} is not empty, its CSS class will be appended with {@link activeClass}. + * If this option is not set, the menu item will be set active automatically when the current request + * is triggered by {@link url}. Note that the GET parameters not specified in the 'url' option will be ignored.
    • + *
    • template: string, optional, the template used to render this menu item. + * When this option is set, it will override the global setting {@link itemTemplate}. + * Please see {@link itemTemplate} for more details. This option has been available since version 1.1.1.
    • + *
    • linkOptions: array, optional, additional HTML attributes to be rendered for the link or span tag of the menu item.
    • + *
    • itemOptions: array, optional, additional HTML attributes to be rendered for the container tag of the menu item.
    • + *
    • submenuOptions: array, optional, additional HTML attributes to be rendered for the container of the submenu if this menu item has one. + * When this option is set, the {@link submenuHtmlOptions} property will be ignored for this particular submenu. + * This option has been available since version 1.1.6.
    • + *
    + */ + public $items = array(); + /** + * @var string the template used to render an individual menu item. In this template, + * the token "{menu}" will be replaced with the corresponding menu link or text. + * If this property is not set, each menu will be rendered without any decoration. + * This property will be overridden by the 'template' option set in individual menu items via {@items}. + * @since 1.1.1 + */ + public $itemTemplate; + /** + * @var boolean whether the labels for menu items should be HTML-encoded. Defaults to true. + */ + public $encodeLabel = true; + /** + * @var string the CSS class to be appended to the active menu item. Defaults to 'active'. + * If empty, the CSS class of menu items will not be changed. + */ + public $activeCssClass = 'active'; + /** + * @var boolean whether to automatically activate items according to whether their route setting + * matches the currently requested route. Defaults to true. + * @since 1.1.3 + */ + public $activateItems = true; + /** + * @var boolean whether to activate parent menu items when one of the corresponding child menu items is active. + * The activated parent menu items will also have its CSS classes appended with {@link activeCssClass}. + * Defaults to false. + */ + public $activateParents = false; + /** + * @var boolean whether to hide empty menu items. An empty menu item is one whose 'url' option is not + * set and which doesn't contain visible child menu items. Defaults to true. + */ + public $hideEmptyItems = true; + /** + * @var array HTML attributes for the menu's root container tag + */ + public $options = array(); + /** + * @var array HTML attributes for the submenu's container tag. + */ + public $submenuHtmlOptions = array(); + /** + * @var string the HTML element name that will be used to wrap the label of all menu links. + * For example, if this property is set as 'span', a menu item may be rendered as + * <li><a href="url"><span>label</span></a></li> + * This is useful when implementing menu items using the sliding window technique. + * Defaults to null, meaning no wrapper tag will be generated. + * @since 1.1.4 + */ + public $linkLabelWrapper; + /** + * @var array HTML attributes for the links' wrap element specified in + * {@link linkLabelWrapper}. + * @since 1.1.13 + */ + public $linkLabelWrapperHtmlOptions = array(); + /** + * @var string the CSS class that will be assigned to the first item in the main menu or each submenu. + * Defaults to null, meaning no such CSS class will be assigned. + * @since 1.1.4 + */ + public $firstItemCssClass; + /** + * @var string the CSS class that will be assigned to the last item in the main menu or each submenu. + * Defaults to null, meaning no such CSS class will be assigned. + * @since 1.1.4 + */ + public $lastItemCssClass; + /** + * @var string the CSS class that will be assigned to every item. + * Defaults to null, meaning no such CSS class will be assigned. + * @since 1.1.9 + */ + public $itemCssClass; + + /** + * Initializes the menu widget. + * This method mainly normalizes the {@link items} property. + * If this method is overridden, make sure the parent implementation is invoked. + */ + public function init() + { + $route = $this->getController()->getRoute(); + $this->items = $this->normalizeItems($this->items, $route, $hasActiveChild); + } + + /** + * Calls {@link renderMenu} to render the menu. + */ + public function run() + { + if (count($this->items)) { + echo Html::beginTag('ul', $this->options) . "\n"; + $this->renderItems($this->items); + echo Html::endTag('ul'); + } + } + + /** + * Recursively renders the menu items. + * @param array $items the menu items to be rendered recursively + */ + protected function renderItems($items) + { + $count = 0; + $n = count($items); + foreach ($items as $item) { + $count++; + $options = isset($item['itemOptions']) ? $item['itemOptions'] : array(); + $class = array(); + if ($item['active'] && $this->activeCssClass != '') { + $class[] = $this->activeCssClass; + } + if ($count === 1 && $this->firstItemCssClass !== null) { + $class[] = $this->firstItemCssClass; + } + if ($count === $n && $this->lastItemCssClass !== null) { + $class[] = $this->lastItemCssClass; + } + if ($this->itemCssClass !== null) { + $class[] = $this->itemCssClass; + } + if ($class !== array()) { + if (empty($options['class'])) { + $options['class'] = implode(' ', $class); + } else { + $options['class'] .= ' ' . implode(' ', $class); + } + } + + echo Html::beginTag('li', $options); + + $menu = $this->renderItem($item); + if (isset($this->itemTemplate) || isset($item['template'])) { + $template = isset($item['template']) ? $item['template'] : $this->itemTemplate; + echo strtr($template, array('{menu}' => $menu)); + } else { + echo $menu; + } + + if (isset($item['items']) && count($item['items'])) { + echo "\n" . Html::beginTag('ul', isset($item['submenuOptions']) ? $item['submenuOptions'] : $this->submenuHtmlOptions) . "\n"; + $this->renderItems($item['items']); + echo Html::endTag('ul') . "\n"; + } + + echo Html::endTag('li') . "\n"; + } + } + + /** + * Renders the content of a menu item. + * Note that the container and the sub-menus are not rendered here. + * @param array $item the menu item to be rendered. Please see {@link items} on what data might be in the item. + * @return string + * @since 1.1.6 + */ + protected function renderItem($item) + { + if (isset($item['url'])) { + $label = $this->linkLabelWrapper === null ? $item['label'] : Html::tag($this->linkLabelWrapper, $this->linkLabelWrapperHtmlOptions, $item['label']); + return Html::a($label, $item['url'], isset($item['linkOptions']) ? $item['linkOptions'] : array()); + } else { + return Html::tag('span', isset($item['linkOptions']) ? $item['linkOptions'] : array(), $item['label']); + } + } + + /** + * Normalizes the {@link items} property so that the 'active' state is properly identified for every menu item. + * @param array $items the items to be normalized. + * @param string $route the route of the current request. + * @param boolean $active whether there is an active child menu item. + * @return array the normalized menu items + */ + protected function normalizeItems($items, $route, &$active) + { + foreach ($items as $i => $item) { + if (isset($item['visible']) && !$item['visible']) { + unset($items[$i]); + continue; + } + if (!isset($item['label'])) { + $item['label'] = ''; + } + if ($this->encodeLabel) { + $items[$i]['label'] = Html::encode($item['label']); + } + $hasActiveChild = false; + if (isset($item['items'])) { + $items[$i]['items'] = $this->normalizeItems($item['items'], $route, $hasActiveChild); + if (empty($items[$i]['items']) && $this->hideEmptyItems) { + unset($items[$i]['items']); + if (!isset($item['url'])) { + unset($items[$i]); + continue; + } + } + } + if (!isset($item['active'])) { + if ($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item, $route)) { + $active = $items[$i]['active'] = true; + } else { + $items[$i]['active'] = false; + } + } elseif ($item['active']) { + $active = true; + } + } + return array_values($items); + } + + /** + * Checks whether a menu item is active. + * This is done by checking if the currently requested URL is generated by the 'url' option + * of the menu item. Note that the GET parameters not specified in the 'url' option will be ignored. + * @param array $item the menu item to be checked + * @param string $route the route of the current request + * @return boolean whether the menu item is active + */ + protected function isItemActive($item, $route) + { + if (isset($item['url']) && is_array($item['url']) && !strcasecmp(trim($item['url'][0], '/'), $route)) { + unset($item['url']['#']); + if (count($item['url']) > 1) { + foreach (array_splice($item['url'], 1) as $name => $value) { + if (!isset($_GET[$name]) || $_GET[$name] != $value) { + return false; + } + } + } + return true; + } + return false; + } + +} From 3d40b171e077e051db6e277afe5634d149095716 Mon Sep 17 00:00:00 2001 From: slavcopost Date: Mon, 6 May 2013 23:27:11 +0300 Subject: [PATCH 06/23] Fix attaching behavior via config --- framework/base/Component.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/base/Component.php b/framework/base/Component.php index 582cf03..e2520d1 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -8,6 +8,7 @@ namespace yii\base; use Yii; +use yii\helpers\base\VarDumper; /** * @include @yii/base/Component.md @@ -90,6 +91,7 @@ class Component extends Object // as behavior: attach behavior $name = trim(substr($name, 3)); $this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value)); + return; } else { // behavior property $this->ensureBehaviors(); From 1415c12c5a90f553f55a31d8a07b58c7e2adfa2c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 16:34:20 -0400 Subject: [PATCH 07/23] Changed default value of View::renderers. --- framework/base/View.php | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/framework/base/View.php b/framework/base/View.php index 4718d90..af1f0d5 100644 --- a/framework/base/View.php +++ b/framework/base/View.php @@ -72,23 +72,21 @@ class View extends Component /** * @var array a list of available renderers indexed by their corresponding supported file extensions. * Each renderer may be a view renderer object or the configuration for creating the renderer object. - * For example, - * - * ~~~ - * array( - * 'tpl' => array( - * 'class' => 'yii\renderers\SmartyRenderer', - * ), - * 'twig' => array( - * 'class' => 'yii\renderers\TwigRenderer', - * ), - * ) - * ~~~ + * The default setting supports both Smarty and Twig (their corresponding file extension is "tpl" + * and "twig" respectively. Please refer to [[SmartyRenderer]] and [[TwigRenderer]] on how to install + * the needed libraries for these template engines. * * If no renderer is available for the given view file, the view file will be treated as a normal PHP * and rendered via [[renderPhpFile()]]. */ - public $renderers = array(); + public $renderers = array( + 'tpl' => array( + 'class' => 'yii\renderers\SmartyRenderer', + ), + 'twig' => array( + 'class' => 'yii\renderers\TwigRenderer', + ), + ); /** * @var Theme|array the theme object or the configuration array for creating the theme object. * If not set, it means theming is not enabled. From a94c43231165e101e2c7273a8d4e459bbf737675 Mon Sep 17 00:00:00 2001 From: slavcopost Date: Mon, 6 May 2013 23:40:32 +0300 Subject: [PATCH 08/23] Fix attaching behavior via config --- framework/base/Component.php | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/base/Component.php b/framework/base/Component.php index e2520d1..8e75835 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -8,7 +8,6 @@ namespace yii\base; use Yii; -use yii\helpers\base\VarDumper; /** * @include @yii/base/Component.md From 36d452ae167f0aa1a798e4049ad8cc216ca79f19 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 19:20:20 -0400 Subject: [PATCH 09/23] Finished the initial draft of upgrading instructions --- docs/guide/upgrade-from-v1.md | 309 ++++++++++++++++++++++++++++++++++++++++-- readme.md | 13 +- 2 files changed, 308 insertions(+), 14 deletions(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index af3c9ca..1aab3d1 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -22,30 +22,36 @@ data structures. Object Configuration -------------------- -The `Object` class introduces a convention for configuring objects. In general, any -descendant class of `Object` should follow this convention when declaring a constructor: +The `Object` class introduces a uniform way of configuring objects. Any descendant class +of `Object` should declare its constructor (if needed) in the following way so that +it can be properly configured: ~~~ class MyClass extends \yii\Object { public function __construct($param1, $param2, $config = array()) { - // ... + // ... initialization before configuration is applied + parent::__construct($config); } public function init() { parent::init(); - // ... at this point, all configurations have been applied ... + + // ... initialization after configuration is applied } } ~~~ -In descendant classes, you can override the `init()` method to do initialization work -that should be done after all configurations are applied. +In the above, the last parameter of the constructor must take a configuration array +which contains name-value pairs for initializing the properties at the end of the constructor. +You can override the `init()` method to do initialization work that should be done after +the configuration is applied. -By following this convention, you will be able to use the powerful object creation method via: +By following this convention, you will be able to create and configure a new object +using a configuration array like the following: ~~~ $object = Yii::createObject(array( @@ -87,6 +93,23 @@ Yii::$app->trigger($eventName); ~~~ +Path Alias +---------- + +Yii 2.0 expands the usage of path aliases to both file/directory paths and URLs. An alias +must start with a `@` character so that it can be differentiated from file/directory paths and URLs. +For example, the alias `@yii` refers to the Yii installation directory. Path aliases are +supported in most places in the Yii core code. For example, `FileCache::cachePath` can take +both a path alias and a normal directory path. + +Path alias is also closely related with class namespaces. It is recommended that a path +alias defined for each root namespace so that you can use Yii class autoloader without +any further configuration. For example, because `@yii` refers to the Yii installation directory, +a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library +such as Zend Framework, you may define a path alias `@Zend` which refers to its installation directory. +And Yii will be able to autoload any class in this library. + + View ---- @@ -111,53 +134,313 @@ $content = Yii::$app->view->renderFile($viewFile, $params); Also, there is no more `CClientScript` in Yii 2.0. The `View` class has taken over its role with significant improvements. For more details, please see the "assets" subsection. -TBD: built-in renderers +While Yii 2.0 continues to use PHP as its main template language, it comes with built-in +support for two popular template engines: Smarty and Twig. The Prado template engine is +no longer supported. To use these template engines, simply configure the "view" application +component as follows, + +~~~ +'view' => array( + 'renders' => array( + array( + 'tpl' => array( + 'class' => 'yii\renderers\SmartyRenderer', + ), + 'twig' => array( + 'class' => 'yii\renderers\TwigRenderer', + ), + ) + ), +) +~~~ + Models ------ +A model is now associated with a form name returned its `formName()` method. This is +mainly used when using HTML forms to collect user inputs for a model. Previously in 1.1, +this is usually hardcoded as the class name of the model. + + +Yii 2.0 introduces a new method called `scenarios()` to declare which attributes require +validation under which scenario. Child classes should overwrite `scenarios()` to return +a list of scenarios and the corresponding attributes that need to be validated when +`validate()` is called. For example, + +~~~ +public function scenarios() +{ + return array( + 'backend' => array('email', 'role'), + 'frontend' => array('email', '!name'), + ); +} +~~~ + +This method also determines which attributes are safe and which are not. In particular, +given a scenario, if an attribute appears in the corresponding attribute list in `scenarios()` +and the name is not prefixed with `!`, it is considered *safe*. + +Because of the above change, Yii 2.0 no longer has "safe" and "unsafe" validators. + +If your model only has one scenario (very common), you do not have to overwrite `scenarios()`, +and everything will still work like the 1.1 way. + + Controllers ----------- +The `render()` and `renderPartial()` methods now return the rendering results instead of directly +sending them out. You have to `echo` them explicitly, e.g., `echo $this->render(...);`. + +A new method called `populate()` is introduced to simplify the data population from user inputs +to a model. For example, + +~~~ +$post = new Post; +if ($this->populate($_POST, $model)) {...} +// which is equivalent to: +if (isset($_POST['Post'])) { + $post->attributes = $_POST['Post']; +} +~~~ + + Themes ------ +Theme works completely different in 2.0. It is now based on a path map to "translate" a source +view into a themed view. For example, if the path map for a theme is +`array('/www/views' => '/www/themes/basic')`, then the themed version for a view file +`/www/views/site/index.php` will be `/www/themes/basic/site/index.php`. + +For this reason, theme can now be applied to any view file, even if a view rendered outside +of the context of a controller or a widget. + +There is no more `CThemeManager`. Instead, `theme` is a configurable property of the "view" +application component. + + Console Applications -------------------- +Console applications are now composed by controllers, too, like Web applications. In fact, +console controllers and Web controllers share the same base controller class. + +Each console controller is like `CConsoleCommand` in 1.1. It consists of one or several +actions. You use the `yiic ` command to execute a console command, where `` +stands for a controller route (e.g. `sitemap/index`). Additional anonymous arguments +are passed as the parameters to the corresponding controller action method, and named arguments +are treated as global options declared in `globalOptions()`. + +Yii 2.0 supports automatic generation of command help information from comment blocks. + + I18N ---- -Behaviors ---------- +Yii 2.0 removes date formatter and number formatter in favor of the PECL intl PHP module. -TBD +Message translation is still supported, but managed via the "i18n" application component. +The component manages a set of message sources, which allows you to use different message +sources based on message categories. For more information, see the class documentation for `I18N`. + +The message translation method is changed by merging the message category into the message being +translated. For example, `Yii::t('yii|message to be translated')`. -Action filters are replaced by behaviors (`ActiionFilter`). + + +Action Filters +-------------- + +Action filters are implemented via behaviors now. You should extend from `ActionFilter` to +define a new filter. To use a filter, you should attach the filter class to the controller +as a behavior. For example, to use the `AccessControl` filter, you should have the following +code in a controller: + +~~~ +public function behaviors() +{ + return array( + 'access' => array( + 'class' => 'yii\web\AccessControl', + 'rules' => array( + array('allow' => true, 'actions' => array('admin'), 'roles' => array('@')), + array('allow' => false), + ), + ), + ); +} +~~~ Assets ------ +Yii 2.0 introduces a new concept called *asset bundle*. It is a bit similar to script +packages (managed by `CClientScript`) in 1.1, but with better support. + +An asset bundle is a collection of asset files (e.g. JavaScript files, CSS files, image files, etc.) +under a directory. By registering an asset bundle via `View::registerAssetBundle()`, you +will be able to make the assets in that bundle accessible via Web, and the current page +will automatically contain references to the JavaScript and CSS files in that bundle. + + + Static Helpers -------------- +Yii 2.0 introduces many commonly used static helper classes, such as `Html`, `ArrayHelper`, +`StringHelper`. These classes are designed to be easily extended. Note that static classes +are usually hard to be extended because of the fixed class name references. But Yii 2.0 +introduces the class map (via `Yii::$classMap`) to overcome this difficulty. + + `ActiveForm` ------------ +Yii 2.0 introduces the *field* concept for building a form using `ActiveForm`. A field +is a container consisting of a label, an input, and an error message. It is represented +as an `ActiveField` object. Using fields, you can build a form more cleanly than before: + +~~~ +beginWidget('yii\widgets\ActiveForm'); ?> + field($model, 'username')->textInput(); ?> + field($model, 'password')->passwordInput(); ?> +
    + +
    +endWidget(); ?> +~~~ + Query Builder ------------- +In 1.1, query building is scattered among several classes, including `CDbCommand`, +`CDbCriteria`, and `CDbCommandBuilder`. Yii 2.0 uses `Query` to represent a DB query +and `QueryBuilder` to generate SQL statements from query objects. For example, + +~~~ +$query = new \yii\db\Query; +$query->select('id, name') + ->from('tbl_user') + ->limit(10); + +$command = $query->createCommand(); +$sql = $command->sql; +$rows = $command->queryAll(); +~~~ + +Best of all, such query building methods can be used together with `ActiveRecord`, +as explained in the next sub-section. + ActiveRecord ------------ +ActiveRecord has undergone significant changes in Yii 2.0. The most important one +is about relational ActiveRecord query. In 1.1, you have to declare the relations +in the `relations()` method. In 2.0, this is done via getter methods that return +an `ActiveQuery` object. For example, the following method declares an "orders" relation: + +~~~ +class Customer extends \yii\db\ActiveRecord +{ + public function getOrders() + { + return $this->hasMany('Order', array('customer_id' => 'id')); + } +} +~~~ + +You can use `$customer->orders` to access the customer's orders. You can also +use `$customer->getOrders()->andWhere('status=1')->all()` to perform on-the-fly +relational query with customized query conditions. + +When loading relational records in an eager way, Yii 2.0 does it differently from 1.1. +In particular, in 1.1 a JOIN query would be used to bring both the primary and the relational +records; while in 2.0, two SQL statements are executed without using JOIN: the first +statement brings back the primary records and the second brings back the relational records +by filtering with the primary keys of the primary records. + + +Yii 2.0 no longer uses the `model()` method when performing queries. Instead, you +use the `find()` method like the following: + +~~~ +// to retrieve all *active* customers and order them by their ID: +$customers = Customer::find() + ->where(array('status' => $active)) + ->orderBy('id') + ->all(); +// return the customer whose PK is 1 +$customer = Customer::find(1); +~~~ + +The `find()` method returns an instance of `ActiveQuery` which is a subclass of `Query`. +Therefore, you can use all query methods of `Query`. + +Instead of returning ActiveRecord objects, you may call `ActiveQuery::asArray()` to +return results in terms of arrays. This is more efficient and is especially useful +when you need to return large number of records. For example, + +~~~ +$customers = Customer::find()->asArray()->all(); +~~~ + + +Auto-quoting Table and Column Names +------------------------------------ + +Yii 2.0 supports automatic quoting of database table and column names. A name enclosed +within double curly brackets is treated as a table name, and a name enclosed within +double square brackets is treated as a column name. They will be quoted according to +the database driver being used. For example, + +~~~ +$command = $connection->createCommand('SELECT [[id]] FROM {{posts}}'); +echo $command->sql; // MySQL: SELECT `id` FROM `posts` +~~~ + +This feature is especially useful if you are developing an application that supports +different DBMS. + + User and Identity ----------------- +The `CWebUser` class in 1.1 is now replaced by `\yii\Web\User`, and there is no more +`CUserIdentity` class. Instead, you should implement the `Identity` interface which +is much more straightforward to implement. The bootstrap application provides such an example. + + URL Management -------------- +URL management is similar to 1.1. A major enhancement is that it now supports optional +parameters. For example, if you have rule declared as follows, then it will match +both `post/popular` and `post/1/popular`. In 1.1, you would have to use two rules to achieve +the same goal. + +~~~ +array( + 'pattern' => 'post//', + 'route' => 'post/index', + 'defaults' => array('page' => 1), +) +~~~ + + Response --------- \ No newline at end of file +-------- + +Extensions +---------- + +Integration with Composer +------------------------- + +TBD + diff --git a/readme.md b/readme.md index f395e95..178acd4 100644 --- a/readme.md +++ b/readme.md @@ -27,10 +27,21 @@ REQUIREMENTS The minimum requirement by Yii is that your Web server supports PHP 5.3.?. +DOCUMENTATION +------------- + +For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/upgrade-from-v1.md) +to have a general idea of what has changed in 2.0. + +We are writing more documentation to get you started and learn more in depth. + + HOW TO PARTICIPATE ------------------ -You are welcome to participate in Yii 2 development in the following ways: +**Your participation to Yii 2 development is very welcome!** + +You may participate in the following ways: * [Report issues](https://github.com/yiisoft/yii2/issues) * [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-design-discussions-for-yii-20/) From 881a85d463a4593d510aa2f907b01ce4ac167e31 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 20:24:22 -0300 Subject: [PATCH 10/23] Fixed doc about renderers. --- docs/guide/upgrade-from-v1.md | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index 1aab3d1..5da5254 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -136,23 +136,9 @@ with significant improvements. For more details, please see the "assets" subsect While Yii 2.0 continues to use PHP as its main template language, it comes with built-in support for two popular template engines: Smarty and Twig. The Prado template engine is -no longer supported. To use these template engines, simply configure the "view" application -component as follows, - -~~~ -'view' => array( - 'renders' => array( - array( - 'tpl' => array( - 'class' => 'yii\renderers\SmartyRenderer', - ), - 'twig' => array( - 'class' => 'yii\renderers\TwigRenderer', - ), - ) - ), -) -~~~ +no longer supported. To use these template engines, you just need to use `tpl` as the file +extension for your Smarty views, or `twig` for Twig views. You may also configure the +`View::renderers` property to use other template engines. Models From 647a80278277ba3bf3cc0f4dc19cdc44f88d8ae2 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 20:33:03 -0300 Subject: [PATCH 11/23] Added dirty attribute description. --- docs/guide/upgrade-from-v1.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index 5da5254..3b24201 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -377,6 +377,11 @@ $customers = Customer::find()->asArray()->all(); ~~~ +By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes +would be saved to database when you call `save()`, regardless they are changed or not, +unless you explicitly list the attributes to save. + + Auto-quoting Table and Column Names ------------------------------------ From ce1e725a6bba4ceb0795bac3ecc8c35052e4146c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 21:20:26 -0300 Subject: [PATCH 12/23] Added namespace section. --- docs/guide/upgrade-from-v1.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index 3b24201..b9365e5 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -6,6 +6,17 @@ We hope this list will make it easier for you to upgrade from Yii 1.1 and quickl master Yii 2.0 based on your existing Yii knowledge. +Namespace +--------- + +The most obvious change in Yii 2.0 is the use of namespaces. Almost every core class +is namespaced, e.g., `yii\web\Request`. The "C" prefix is no longer used in class names. +The naming of the namespaces follows the directory structure. For example, `yii\web\Request` +indicates the corresponding class file is `web/Request.php` under the Yii framework folder. +You can use any core class without explicitly include that class file, thanks to the Yii +class loader. + + Component and Object -------------------- From 50aa72467fe19e0b44b15f26427721fe0326a367 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 6 May 2013 20:24:19 -0400 Subject: [PATCH 13/23] Renamed YiiBase to \yii\YiiBase. --- framework/YiiBase.php | 4 +++- framework/yii.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/framework/YiiBase.php b/framework/YiiBase.php index ed975c9..c911f78 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -4,6 +4,8 @@ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ +namespace yii; + use yii\base\Exception; use yii\base\InvalidConfigException; use yii\base\InvalidParamException; @@ -60,7 +62,7 @@ class YiiBase */ public static $enableIncludePath = true; /** - * @var yii\console\Application|yii\web\Application the application instance + * @var \yii\console\Application|\yii\web\Application the application instance */ public static $app; /** diff --git a/framework/yii.php b/framework/yii.php index 828dc4f..109e2fd 100644 --- a/framework/yii.php +++ b/framework/yii.php @@ -18,7 +18,7 @@ require(__DIR__ . '/YiiBase.php'); * @author Qiang Xue * @since 2.0 */ -class Yii extends YiiBase +class Yii extends \yii\YiiBase { } From 6b9a0531b829598fce010b622638112c2e2d3e3b Mon Sep 17 00:00:00 2001 From: Luciano Baraglia Date: Tue, 7 May 2013 02:01:00 -0300 Subject: [PATCH 14/23] Controllers section example fix --- docs/guide/upgrade-from-v1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index b9365e5..ff9e5cf 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -195,7 +195,7 @@ A new method called `populate()` is introduced to simplify the data population f to a model. For example, ~~~ -$post = new Post; +$model = new Post; if ($this->populate($_POST, $model)) {...} // which is equivalent to: if (isset($_POST['Post'])) { From 9844c2e526e99e6953c9cd5be3d814bbfd6a8649 Mon Sep 17 00:00:00 2001 From: br0sk Date: Tue, 7 May 2013 08:41:33 +0200 Subject: [PATCH 15/23] Fixed typo --- docs/guide/upgrade-from-v1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index b9365e5..1e044cd 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -26,7 +26,7 @@ via getters and setters. The `Component` class extends from `Object` and support the event feature and the behavior feature. If your class does not need the event or behavior feature, you should consider using -`Object` as the based class. This is usually the case for classes that represent basic +`Object` as the base class. This is usually the case for classes that represent basic data structures. From 9a1221e7c45b60a1adba73386d488d8acb06d0ea Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 7 May 2013 12:25:00 +0400 Subject: [PATCH 16/23] Wrapped code with github-style blocks with PHP highlighting --- docs/guide/upgrade-from-v1.md | 53 ++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index d065a4d..a82be57 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -37,7 +37,7 @@ The `Object` class introduces a uniform way of configuring objects. Any descenda of `Object` should declare its constructor (if needed) in the following way so that it can be properly configured: -~~~ +```php class MyClass extends \yii\Object { public function __construct($param1, $param2, $config = array()) @@ -54,8 +54,8 @@ class MyClass extends \yii\Object // ... initialization after configuration is applied } } +``` ~~~ - In the above, the last parameter of the constructor must take a configuration array which contains name-value pairs for initializing the properties at the end of the constructor. You can override the `init()` method to do initialization work that should be done after @@ -64,12 +64,13 @@ the configuration is applied. By following this convention, you will be able to create and configure a new object using a configuration array like the following: -~~~ +```php $object = Yii::createObject(array( 'class' => 'MyClass', 'property1' => 'abc', 'property2' => 'cde', ), $param1, $param2); +``` ~~~ @@ -80,28 +81,30 @@ There is no longer the need to define an `on`-method in order to define an event Instead, you can use whatever event names. To attach a handler to an event, you should use the `on` method now: -~~~ +```php $component->on($eventName, $handler); // To detach the handler, use: // $component->off($eventName, $handler); +``` ~~~ When you attach a handler, you can now associate it with some parameters which can be later accessed via the event parameter by the handler: -~~~ +```php $component->on($eventName, $handler, $params); +``` ~~~ Because of this change, you can now use "global" events. Simply trigger and attach handlers to an event of the application instance: -~~~ +```php Yii::$app->on($eventName, $handler); .... // this will trigger the event and cause $handler to be invoked. Yii::$app->trigger($eventName); -~~~ +``` Path Alias @@ -135,11 +138,12 @@ Because you can access the view object through the "view" application component, you can now render a view file like the following anywhere in your code, not necessarily in controllers or widgets: -~~~ +```php $content = Yii::$app->view->renderFile($viewFile, $params); // You can also explicitly create a new View instance to do the rendering // $view = new View; // $view->renderFile($viewFile, $params); +``` ~~~ Also, there is no more `CClientScript` in Yii 2.0. The `View` class has taken over its role @@ -165,7 +169,7 @@ validation under which scenario. Child classes should overwrite `scenarios()` to a list of scenarios and the corresponding attributes that need to be validated when `validate()` is called. For example, -~~~ +```php public function scenarios() { return array( @@ -173,6 +177,7 @@ public function scenarios() 'frontend' => array('email', '!name'), ); } +``` ~~~ This method also determines which attributes are safe and which are not. In particular, @@ -194,13 +199,14 @@ sending them out. You have to `echo` them explicitly, e.g., `echo $this->render( A new method called `populate()` is introduced to simplify the data population from user inputs to a model. For example, -~~~ +```php $model = new Post; if ($this->populate($_POST, $model)) {...} // which is equivalent to: if (isset($_POST['Post'])) { $post->attributes = $_POST['Post']; } +``` ~~~ @@ -256,7 +262,7 @@ define a new filter. To use a filter, you should attach the filter class to the as a behavior. For example, to use the `AccessControl` filter, you should have the following code in a controller: -~~~ +```php public function behaviors() { return array( @@ -269,6 +275,7 @@ public function behaviors() ), ); } +``` ~~~ @@ -301,7 +308,7 @@ Yii 2.0 introduces the *field* concept for building a form using `ActiveForm`. A is a container consisting of a label, an input, and an error message. It is represented as an `ActiveField` object. Using fields, you can build a form more cleanly than before: -~~~ +```php beginWidget('yii\widgets\ActiveForm'); ?> field($model, 'username')->textInput(); ?> field($model, 'password')->passwordInput(); ?> @@ -309,6 +316,7 @@ as an `ActiveField` object. Using fields, you can build a form more cleanly than endWidget(); ?> +``` ~~~ @@ -319,7 +327,7 @@ In 1.1, query building is scattered among several classes, including `CDbCommand `CDbCriteria`, and `CDbCommandBuilder`. Yii 2.0 uses `Query` to represent a DB query and `QueryBuilder` to generate SQL statements from query objects. For example, -~~~ +```php $query = new \yii\db\Query; $query->select('id, name') ->from('tbl_user') @@ -328,6 +336,7 @@ $query->select('id, name') $command = $query->createCommand(); $sql = $command->sql; $rows = $command->queryAll(); +``` ~~~ Best of all, such query building methods can be used together with `ActiveRecord`, @@ -342,7 +351,7 @@ is about relational ActiveRecord query. In 1.1, you have to declare the relation in the `relations()` method. In 2.0, this is done via getter methods that return an `ActiveQuery` object. For example, the following method declares an "orders" relation: -~~~ +```php class Customer extends \yii\db\ActiveRecord { public function getOrders() @@ -350,6 +359,7 @@ class Customer extends \yii\db\ActiveRecord return $this->hasMany('Order', array('customer_id' => 'id')); } } +``` ~~~ You can use `$customer->orders` to access the customer's orders. You can also @@ -366,7 +376,7 @@ by filtering with the primary keys of the primary records. Yii 2.0 no longer uses the `model()` method when performing queries. Instead, you use the `find()` method like the following: -~~~ +```php // to retrieve all *active* customers and order them by their ID: $customers = Customer::find() ->where(array('status' => $active)) @@ -374,6 +384,7 @@ $customers = Customer::find() ->all(); // return the customer whose PK is 1 $customer = Customer::find(1); +``` ~~~ The `find()` method returns an instance of `ActiveQuery` which is a subclass of `Query`. @@ -383,10 +394,9 @@ Instead of returning ActiveRecord objects, you may call `ActiveQuery::asArray()` return results in terms of arrays. This is more efficient and is especially useful when you need to return large number of records. For example, -~~~ +```php $customers = Customer::find()->asArray()->all(); -~~~ - +``` By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes would be saved to database when you call `save()`, regardless they are changed or not, @@ -401,11 +411,11 @@ within double curly brackets is treated as a table name, and a name enclosed wit double square brackets is treated as a column name. They will be quoted according to the database driver being used. For example, -~~~ +```php $command = $connection->createCommand('SELECT [[id]] FROM {{posts}}'); echo $command->sql; // MySQL: SELECT `id` FROM `posts` +``` ~~~ - This feature is especially useful if you are developing an application that supports different DBMS. @@ -426,12 +436,13 @@ parameters. For example, if you have rule declared as follows, then it will matc both `post/popular` and `post/1/popular`. In 1.1, you would have to use two rules to achieve the same goal. -~~~ +```php array( 'pattern' => 'post//', 'route' => 'post/index', 'defaults' => array('page' => 1), ) +``` ~~~ From a5ab4aa22c47c60ab5fcf40429ab2a17f2149a02 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 7 May 2013 12:25:56 +0400 Subject: [PATCH 17/23] fix --- docs/guide/upgrade-from-v1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index a82be57..f241630 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -55,7 +55,7 @@ class MyClass extends \yii\Object } } ``` -~~~ + In the above, the last parameter of the constructor must take a configuration array which contains name-value pairs for initializing the properties at the end of the constructor. You can override the `init()` method to do initialization work that should be done after From 91e6f8220c07715a7a67d6672d73dd7fe18f2103 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 7 May 2013 12:27:07 +0400 Subject: [PATCH 18/23] fix --- docs/guide/upgrade-from-v1.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index f241630..b6e5d52 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -71,7 +71,7 @@ $object = Yii::createObject(array( 'property2' => 'cde', ), $param1, $param2); ``` -~~~ + Events @@ -86,7 +86,7 @@ $component->on($eventName, $handler); // To detach the handler, use: // $component->off($eventName, $handler); ``` -~~~ + When you attach a handler, you can now associate it with some parameters which can be later accessed via the event parameter by the handler: @@ -94,7 +94,7 @@ accessed via the event parameter by the handler: ```php $component->on($eventName, $handler, $params); ``` -~~~ + Because of this change, you can now use "global" events. Simply trigger and attach handlers to an event of the application instance: @@ -144,7 +144,7 @@ $content = Yii::$app->view->renderFile($viewFile, $params); // $view = new View; // $view->renderFile($viewFile, $params); ``` -~~~ + Also, there is no more `CClientScript` in Yii 2.0. The `View` class has taken over its role with significant improvements. For more details, please see the "assets" subsection. @@ -178,7 +178,7 @@ public function scenarios() ); } ``` -~~~ + This method also determines which attributes are safe and which are not. In particular, given a scenario, if an attribute appears in the corresponding attribute list in `scenarios()` @@ -207,7 +207,7 @@ if (isset($_POST['Post'])) { $post->attributes = $_POST['Post']; } ``` -~~~ + Themes @@ -276,7 +276,7 @@ public function behaviors() ); } ``` -~~~ + Assets @@ -317,7 +317,7 @@ as an `ActiveField` object. Using fields, you can build a form more cleanly than endWidget(); ?> ``` -~~~ + Query Builder @@ -337,7 +337,7 @@ $command = $query->createCommand(); $sql = $command->sql; $rows = $command->queryAll(); ``` -~~~ + Best of all, such query building methods can be used together with `ActiveRecord`, as explained in the next sub-section. @@ -360,7 +360,7 @@ class Customer extends \yii\db\ActiveRecord } } ``` -~~~ + You can use `$customer->orders` to access the customer's orders. You can also use `$customer->getOrders()->andWhere('status=1')->all()` to perform on-the-fly @@ -385,7 +385,7 @@ $customers = Customer::find() // return the customer whose PK is 1 $customer = Customer::find(1); ``` -~~~ + The `find()` method returns an instance of `ActiveQuery` which is a subclass of `Query`. Therefore, you can use all query methods of `Query`. @@ -415,7 +415,7 @@ the database driver being used. For example, $command = $connection->createCommand('SELECT [[id]] FROM {{posts}}'); echo $command->sql; // MySQL: SELECT `id` FROM `posts` ``` -~~~ + This feature is especially useful if you are developing an application that supports different DBMS. @@ -443,7 +443,7 @@ array( 'defaults' => array('page' => 1), ) ``` -~~~ + Response From 3ba55c1bb962c794cc33229892f4d38344d8a6b2 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 7 May 2013 14:19:53 +0400 Subject: [PATCH 19/23] added composer.json --- composer.json | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c6c97b8 --- /dev/null +++ b/composer.json @@ -0,0 +1,72 @@ +{ + "name": "yiisoft/yii2", + "description": "Yii2 Web Programming Framework", + "keywords": ["yii", "framework"], + "homepage": "http://www.yiiframework.com/", + "type": "library", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com", + "homepage": "http://www.yiiframework.com/", + "role": "Founder and project lead" + }, + { + "name": "Alexander Makarov", + "email": "sam@rmcreative.ru", + "homepage": "http://rmcreative.ru/", + "role": "Core framework development" + }, + { + "name": "Maurizio Domba", + "homepage": "http://mdomba.info/", + "role": "Core framework development" + }, + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Core framework development" + }, + { + "name": "Timur Ruziev", + "email": "resurtm@gmail.com", + "homepage": "http://resurtm.com/", + "role": "Core framework development" + }, + { + "name": "Paul Klimov", + "email": "klimov.paul@gmail.com", + "role": "Core framework development" + }, + { + "name": "Wei Zhuo", + "email": "weizhuo@gmail.com", + "role": "Project site maintenance and development" + }, + { + "name": "Sebastián Thierer", + "email": "sebas@artfos.com", + "role": "Component development" + }, + { + "name": "Jeffrey Winesett", + "email": "jefftulsa@gmail.com", + "role": "Documentation and marketing" + } + ], + "support": { + "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "forum": "http://www.yiiframework.com/forum/", + "wiki": "http://www.yiiframework.com/wiki/", + "irc": "irc://irc.freenode.net/yii", + "source": "https://github.com/yiisoft/yii2" + }, + "bin": [ + "framework/yiic" + ], + "require": { + "php": ">=5.3.0" + } +} From 34b0da0dc4ecfa9ac83d7deff6efad3b3b7aab12 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 7 May 2013 14:44:48 +0400 Subject: [PATCH 20/23] Added twig, smarty and php-markdown dependencies, vendor is gitignored now --- .gitignore | 5 ++++- composer.json | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 89fc2a8..9291d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ nbproject .settings # windows thumbnail cache -Thumbs.db \ No newline at end of file +Thumbs.db + +# composer vendor dir +vendor \ No newline at end of file diff --git a/composer.json b/composer.json index c6c97b8..6a5c383 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,9 @@ "framework/yiic" ], "require": { - "php": ">=5.3.0" + "php": ">=5.3.0", + "michelf/php-markdown": "1.3", + "twig/twig": "1.12.*", + "smarty/smarty": "3.1.*" } } From 8c18feb1b54ac2370a703c63f8c2335234d6d1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anderson=20M=C3=BCller?= Date: Tue, 7 May 2013 14:11:52 +0300 Subject: [PATCH 21/23] Fixes the variable name --- docs/guide/upgrade-from-v1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index b6e5d52..d35e6e0 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -204,7 +204,7 @@ $model = new Post; if ($this->populate($_POST, $model)) {...} // which is equivalent to: if (isset($_POST['Post'])) { - $post->attributes = $_POST['Post']; + $model->attributes = $_POST['Post']; } ``` From f3c17594c63b009f6568fc9126a0fc36c5a8c80b Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 7 May 2013 07:18:39 -0400 Subject: [PATCH 22/23] Fixes issue #155. --- framework/db/ActiveRecord.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/framework/db/ActiveRecord.php b/framework/db/ActiveRecord.php index 45c53fb..709d139 100644 --- a/framework/db/ActiveRecord.php +++ b/framework/db/ActiveRecord.php @@ -8,6 +8,7 @@ namespace yii\db; +use yii\base\InvalidConfigException; use yii\base\Model; use yii\base\InvalidParamException; use yii\base\ModelEvent; @@ -112,6 +113,7 @@ class ActiveRecord extends Model * @return ActiveQuery|ActiveRecord|null When `$q` is null, a new [[ActiveQuery]] instance * is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be * returned (null will be returned if there is no matching). + * @throws InvalidConfigException if the AR class does not have a primary key * @see createQuery() */ public static function find($q = null) @@ -122,7 +124,11 @@ class ActiveRecord extends Model } elseif ($q !== null) { // query by primary key $primaryKey = static::primaryKey(); - return $query->where(array($primaryKey[0] => $q))->one(); + if (isset($primaryKey[0])) { + return $query->where(array($primaryKey[0] => $q))->one(); + } else { + throw new InvalidConfigException(get_called_class() . ' must have a primary key.'); + } } return $query; } From dd5969147dd1ec392d3edba4fb03b0c55af8ede1 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 7 May 2013 07:39:24 -0400 Subject: [PATCH 23/23] move JsExpression to web. --- framework/helpers/JsExpression.php | 45 ---------------------- framework/helpers/base/Json.php | 2 +- framework/validators/EmailValidator.php | 2 +- framework/validators/NumberValidator.php | 2 +- .../validators/RegularExpressionValidator.php | 2 +- framework/validators/UrlValidator.php | 2 +- framework/web/JsExpression.php | 45 ++++++++++++++++++++++ framework/widgets/ActiveField.php | 2 +- tests/unit/framework/helpers/JsonTest.php | 2 +- 9 files changed, 52 insertions(+), 52 deletions(-) delete mode 100644 framework/helpers/JsExpression.php create mode 100644 framework/web/JsExpression.php diff --git a/framework/helpers/JsExpression.php b/framework/helpers/JsExpression.php deleted file mode 100644 index 5a1f9bd..0000000 --- a/framework/helpers/JsExpression.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @since 2.0 - */ -class JsExpression extends Object -{ - /** - * @var string the JavaScript expression represented by this object - */ - public $expression; - - /** - * Constructor. - * @param string $expression the JavaScript expression represented by this object - * @param array $config additional configurations for this object - */ - public function __construct($expression, $config = array()) - { - $this->expression = $expression; - parent::__construct($config); - } - - /** - * The PHP magic function converting an object into a string. - * @return string the JavaScript expression. - */ - public function __toString() - { - return $this->expression; - } -} diff --git a/framework/helpers/base/Json.php b/framework/helpers/base/Json.php index c92e208..262dd81 100644 --- a/framework/helpers/base/Json.php +++ b/framework/helpers/base/Json.php @@ -8,7 +8,7 @@ namespace yii\helpers\base; use yii\base\InvalidParamException; -use yii\helpers\JsExpression; +use yii\web\JsExpression; /** * Json is a helper class providing JSON data encoding and decoding. diff --git a/framework/validators/EmailValidator.php b/framework/validators/EmailValidator.php index ad74dd6..949b3f9 100644 --- a/framework/validators/EmailValidator.php +++ b/framework/validators/EmailValidator.php @@ -9,7 +9,7 @@ namespace yii\validators; use Yii; use yii\helpers\Html; -use yii\helpers\JsExpression; +use yii\web\JsExpression; use yii\helpers\Json; /** diff --git a/framework/validators/NumberValidator.php b/framework/validators/NumberValidator.php index c0f81cd..10f0e52 100644 --- a/framework/validators/NumberValidator.php +++ b/framework/validators/NumberValidator.php @@ -9,7 +9,7 @@ namespace yii\validators; use Yii; use yii\helpers\Html; -use yii\helpers\JsExpression; +use yii\web\JsExpression; use yii\helpers\Json; /** diff --git a/framework/validators/RegularExpressionValidator.php b/framework/validators/RegularExpressionValidator.php index 79a1a3c..23419b9 100644 --- a/framework/validators/RegularExpressionValidator.php +++ b/framework/validators/RegularExpressionValidator.php @@ -10,7 +10,7 @@ namespace yii\validators; use Yii; use yii\base\InvalidConfigException; use yii\helpers\Html; -use yii\helpers\JsExpression; +use yii\web\JsExpression; use yii\helpers\Json; /** diff --git a/framework/validators/UrlValidator.php b/framework/validators/UrlValidator.php index 0ed59bd..c418353 100644 --- a/framework/validators/UrlValidator.php +++ b/framework/validators/UrlValidator.php @@ -9,7 +9,7 @@ namespace yii\validators; use Yii; use yii\helpers\Html; -use yii\helpers\JsExpression; +use yii\web\JsExpression; use yii\helpers\Json; /** diff --git a/framework/web/JsExpression.php b/framework/web/JsExpression.php new file mode 100644 index 0000000..027c065 --- /dev/null +++ b/framework/web/JsExpression.php @@ -0,0 +1,45 @@ + + * @since 2.0 + */ +class JsExpression extends Object +{ + /** + * @var string the JavaScript expression represented by this object + */ + public $expression; + + /** + * Constructor. + * @param string $expression the JavaScript expression represented by this object + * @param array $config additional configurations for this object + */ + public function __construct($expression, $config = array()) + { + $this->expression = $expression; + parent::__construct($config); + } + + /** + * The PHP magic function converting an object into a string. + * @return string the JavaScript expression. + */ + public function __toString() + { + return $this->expression; + } +} diff --git a/framework/widgets/ActiveField.php b/framework/widgets/ActiveField.php index 336966f..0e0381f 100644 --- a/framework/widgets/ActiveField.php +++ b/framework/widgets/ActiveField.php @@ -10,7 +10,7 @@ use yii\base\Component; use yii\db\ActiveRecord; use yii\helpers\Html; use yii\base\Model; -use yii\helpers\JsExpression; +use yii\web\JsExpression; /** * @author Qiang Xue diff --git a/tests/unit/framework/helpers/JsonTest.php b/tests/unit/framework/helpers/JsonTest.php index 6a78cd1..1795ce6 100644 --- a/tests/unit/framework/helpers/JsonTest.php +++ b/tests/unit/framework/helpers/JsonTest.php @@ -4,7 +4,7 @@ namespace yiiunit\framework\helpers; use yii\helpers\Json; -use yii\helpers\JsExpression; +use yii\web\JsExpression; class JsonTest extends \yii\test\TestCase {