Commit 5892b265 by resurtm

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

parents 80bc6811 94fd8f61
Controller
==========
Controller is one of the key parts of the application. It determines how to handle incoming request and creates a response.
Most often a controller takes HTTP request data and returns HTML, JSON or XML as a response.
Basics
------
Controller resides in application's `controllers` directory is is named like `SiteController.php` where `Site`
part could be anything describing a set of actions it contains.
The basic web controller is a class that extends [[\yii\web\Controller]] and could be very simple:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionIndex()
{
// will render view from "views/site/index.php"
return $this->render('index');
}
public function actionTest()
{
// will just print "test" to the browser
return 'test';
}
}
```
As you can see, typical controller contains actions that are public class methods named as `actionSomething`.
Routes
------
Each controller action has a corresponding internal route. In our example above `actionIndex` has `site/index` route
and `actionTest` has `site/test` route. In this route `site` is referred to as controller ID while `test` is referred to
as action ID.
By default you can access specific controller and action using the `http://example.com/?r=controller/action` URL. This
behavior is fully customizable. For details refer to [URL Management](url.md).
If controller is located inside a module its action internal route will be `module/controller/action`.
In case module, controller or action specified isn't found Yii will return "not found" page and HTTP status code 404.
### Defaults
If user isn't specifying any route i.e. using URL like `http://example.com/`, Yii assumes that default route should be
used. It is determined by [[\yii\web\Application::defaultRoute]] method and is `site` by default meaning that `SiteController`
will be loaded.
A controller has a default action. When the user request does not specify which action to execute by usign an URL such as
`http://example.com/?r=site`, the default action will be executed. By default, the default action is named as `index`.
It can be changed by setting the [[\yii\base\Controller::defaultAction]] property.
Action parameters
-----------------
It was already mentioned that a simple action is just a public method named as `actionSomething`. Now we'll review
ways that an action can get parameters from HTTP.
### Action parameters
You can define named arguments for an action and these will be automatically populated from corresponding values from
`$_GET`. This is very convenient both because of the short syntax and an ability to specify defaults:
```php
namespace app\controllers;
use yii\web\Controller;
class BlogController extends Controller
{
public function actionView($id, $version = null)
{
$post = Post::find($id);
$text = $post->text;
if($version) {
$text = $post->getHistory($version);
}
return $this->render('view', array(
'post' => $post,
'text' => $text,
));
}
}
```
The action above can be accessed using either `http://example.com/?r=blog/view&id=42` or
`http://example.com/?r=blog/view&id=42&version=3`. In the first case `version` isn't specified and default parameter
value is used instead.
### Getting data from request
If your action is working with data from HTTP POST or has too many GET parameters you can rely on request object that
is accessible via `\Yii::$app->request`:
```php
namespace app\controllers;
use yii\web\Controller;
use yii\web\HttpException;
class BlogController extends Controller
{
public function actionUpdate($id)
{
$post = Post::find($id);
if(!$post) {
throw new HttpException(404);
}
if(\Yii::$app->request->isPost)) {
$post->load($_POST);
if($post->save()) {
$this->redirect(array('view', 'id' => $post->id));
}
}
return $this->render('update', array(
'post' => $post,
));
}
}
```
Standalone actions
------------------
If action is generic enough it makes sense to implement it in a separate class to be able to reuse it.
Create `actions/Page.php`
```php
namespace \app\actions;
class Page extends \yii\base\Action
{
public $view = 'index';
public function run()
{
$this->controller->render($view);
}
}
```
The following code is too simple to implement as a separate action but gives an idea of how it works. Action implemented
can be used in your controller as following:
```php
public SiteController extends \yii\web\Controller
{
public function actions()
{
return array(
'about' => array(
'class' => '@app/actions/Page',
'view' => 'about',
),
),
);
}
}
```
After doing so you can access your action as `http://example.com/?r=site/about`.
Filters
-------
Catching all incoming requests
------------------------------
See also
--------
- [Console](console.md)
\ No newline at end of file
...@@ -133,27 +133,26 @@ $connection->createCommand()->delete('tbl_user', 'status = 0')->execute(); ...@@ -133,27 +133,26 @@ $connection->createCommand()->delete('tbl_user', 'status = 0')->execute();
Quoting table and column names Quoting table and column names
------------------------------ ------------------------------
If you are building query string dynamically make sure you're properly quoting table and column names using Most of the time you would use the following syntax for quoting table and column names:
[[\yii\db\Connection::quoteTableName()]] and [[\yii\db\Connection::quoteColumnName()]]:
```php ```php
$column = $connection->quoteColumnName($column); $sql = "SELECT COUNT([[$column]]) FROM {{$table}}";
$table = $connection->quoteTableName($table);
$sql = "SELECT COUNT($column) FROM $table";
$rowCount = $connection->createCommand($sql)->queryScalar(); $rowCount = $connection->createCommand($sql)->queryScalar();
``` ```
Alternatively you can use special syntax when writing SQL: In the code above `[[X]]` will be converted to properly quoted column name while `{{Y}}` will be converted to properly
quoted table name.
The alternative is to quote table and column names manually using [[\yii\db\Connection::quoteTableName()]] and
[[\yii\db\Connection::quoteColumnName()]]:
```php ```php
$sql = "SELECT COUNT({{$column}}) FROM [[$table]]"; $column = $connection->quoteColumnName($column);
$table = $connection->quoteTableName($table);
$sql = "SELECT COUNT($column) FROM $table";
$rowCount = $connection->createCommand($sql)->queryScalar(); $rowCount = $connection->createCommand($sql)->queryScalar();
``` ```
In the code above `{{X}}` will be converted to properly quoted column name while `[[Y]]` will be converted to properly
quoted table name.
Prepared statements Prepared statements
------------------- -------------------
......
...@@ -163,6 +163,26 @@ A model is now associated with a form name returned by its `formName()` method. ...@@ -163,6 +163,26 @@ A model is now associated with a form name returned by its `formName()` method.
mainly used when using HTML forms to collect user inputs for a model. Previously in 1.1, 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. this is usually hardcoded as the class name of the model.
A new methods called `load()` and `Model::loadMultiple()` is introduced to simplify the data population from user inputs
to a model. For example,
```php
$model = new Post;
if ($model->load($_POST)) {...}
// which is equivalent to:
if (isset($_POST['Post'])) {
$model->attributes = $_POST['Post'];
}
$model->save();
$postTags = array();
$tagsCount = count($_POST['PostTag']);
while($tagsCount-- > 0){
$postTags[] = new PostTag(array('post_id' => $model->id));
}
Model::loadMultiple($postTags, $_POST);
```
Yii 2.0 introduces a new method called `scenarios()` to declare which attributes require 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 validation under which scenario. Child classes should overwrite `scenarios()` to return
...@@ -196,18 +216,6 @@ Controllers ...@@ -196,18 +216,6 @@ Controllers
The `render()` and `renderPartial()` methods now return the rendering results instead of directly 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(...);`. 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 ($model->load($_POST)) {...}
// which is equivalent to:
if (isset($_POST['Post'])) {
$model->attributes = $_POST['Post'];
}
```
Widgets Widgets
------- -------
......
...@@ -71,6 +71,26 @@ class Formatter extends Component ...@@ -71,6 +71,26 @@ class Formatter extends Component
} }
/** /**
* Formats the value based on the give type.
* This method will call one of the "as" methods available in this class to do the formatting.
* For type "xyz", the method "asXyz" will be used. For example, if the type is "html",
* then [[asHtml()]] will be used. Type names are case insensitive.
* @param mixed $value the value to be formatted
* @param string $type the type of the value, e.g., "html", "text".
* @return string the formatting result
* @throws InvalidParamException if the type is not supported by this class.
*/
public function format($value, $type)
{
$method = 'as' . $type;
if (method_exists($this, $method)) {
return $this->$method($value);
} else {
throw new InvalidParamException("Unknown type: $type");
}
}
/**
* Formats the value as is without any formatting. * Formats the value as is without any formatting.
* This method simply returns back the parameter without any format. * This method simply returns back the parameter without any format.
* @param mixed $value the value to be formatted * @param mixed $value the value to be formatted
......
...@@ -694,7 +694,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess ...@@ -694,7 +694,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
$success = true; $success = true;
} }
} elseif (isset($data[$scope][$i])) { } elseif (isset($data[$scope][$i])) {
$model->setAttributes($data[$scope[$i]]); $model->setAttributes($data[$scope][$i]);
$success = true; $success = true;
} }
} }
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\widgets;
use Yii;
use yii\base\Arrayable;
use yii\base\Formatter;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\base\Widget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\Inflector;
/**
* DetailView displays the detail of a single data [[model]].
*
* DetailView is best used for displaying a model in a regular format (e.g. each model attribute
* is displayed as a row in a table.) The model can be either an instance of [[Model]] or
* or an associative array.
*
* DetailView uses the [[attributes]] property to determines which model attributes
* should be displayed and how they should be formatted.
*
* A typical usage of DetailView is as follows:
*
* ~~~
* \yii\widgets\DetailView::widget(array(
* 'data' => $model,
* 'attributes' => array(
* 'title', // title attribute (in plain text)
* 'description:html', // description attribute in HTML
* array( // the owner name of the model
* 'label' => 'Owner',
* 'value' => $model->owner->name,
* ),
* ),
* ));
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class DetailView extends Widget
{
/**
* @var array|object the data model whose details are to be displayed. This can be either a [[Model]] instance
* or an associative array.
*/
public $model;
/**
* @var array a list of attributes to be displayed in the detail view. Each array element
* represents the specification for displaying one particular attribute.
*
* An attribute can be specified as a string in the format of "Name" or "Name:Type", where "Name" refers to
* the attribute name, and "Type" represents the type of the attribute. The "Type" is passed to the [[Formatter::format()]]
* method to format an attribute value into a displayable text. Please refer to [[Formatter]] for the supported types.
*
* An attribute can also be specified in terms of an array with the following elements:
*
* - name: the attribute name. This is required if either "label" or "value" is not specified.
* - label: the label associated with the attribute. If this is not specified, it will be generated from the attribute name.
* - value: the value to be displayed. If this is not specified, it will be retrieved from [[model]] using the attribute name
* by calling [[ArrayHelper::getValue()]]. Note that this value will be formatted into a displayable text
* according to the "type" option.
* - type: the type of the value that determines how the value would be formatted into a displayable text.
* Please refer to [[Formatter]] for supported types.
* - visible: whether the attribute is visible. If set to `false`, the attribute will be displayed.
*/
public $attributes;
/**
* @var string|\Closure the template used to render a single attribute. If a string, the token `{label}`
* and `{value}` will be replaced with the label and the value of the corresponding attribute.
* If an anonymous function, the signature must be as follows:
*
* ~~~
* function ($attribute, $index, $widget)
* ~~~
*
* where `$attribute` refer to the specification of the attribute being rendered, `$index` is the zero-based
* index of the attribute in the [[attributes]] array, and `$widget` refers to this widget instance.
*/
public $template = "<tr><th>{label}</th><td>{value}</td></tr>";
/**
* @var array the HTML attributes for the container tag of this widget. The "tag" option specifies
* what container tag should be used. It defaults to "table" if not set.
*/
public $options = array('class' => 'table table-striped');
/**
* @var array|Formatter the formatter used to format model attribute values into displayable texts.
* This can be either an instance of [[Formatter]] or an configuration array for creating the [[Formatter]]
* instance. If this property is not set, the "formatter" application component will be used.
*/
public $formatter;
/**
* Initializes the detail view.
* This method will initialize required property values.
*/
public function init()
{
if ($this->model === null) {
throw new InvalidConfigException('Please specify the "data" property.');
}
if ($this->formatter == null) {
$this->formatter = Yii::$app->getFormatter();
} elseif (is_array($this->formatter)) {
$this->formatter = Yii::createObject($this->formatter);
} elseif (!$this->formatter instanceof Formatter) {
throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.');
}
$this->normalizeAttributes();
}
/**
* Renders the detail view.
* This is the main entry of the whole detail view rendering.
*/
public function run()
{
$rows = array();
$i = 0;
foreach ($this->attributes as $attribute) {
$rows[] = $this->renderAttribute($attribute, $i++);
}
$tag = ArrayHelper::remove($this->options, 'tag', 'table');
echo Html::tag($tag, implode("\n", $rows), $this->options);
}
/**
* Renders a single attribute.
* @param array $attribute the specification of the attribute to be rendered.
* @param integer $index the zero-based index of the attribute in the [[attributes]] array
* @return string the rendering result
*/
protected function renderAttribute($attribute, $index)
{
if (is_string($this->template)) {
return strtr($this->template, array(
'{label}' => $attribute['label'],
'{value}' => $this->formatter->format($attribute['value'], $attribute['type']),
));
} else {
return call_user_func($this->template, $attribute, $index, $this);
}
}
/**
* Normalizes the attribute specifications.
* @throws InvalidConfigException
*/
protected function normalizeAttributes()
{
if ($this->attributes === null) {
if ($this->model instanceof Model) {
$this->attributes = $this->model->attributes();
} elseif (is_object($this->model)) {
$this->attributes = $this->model instanceof Arrayable ? $this->model->toArray() : array_keys(get_object_vars($this->model));
} elseif (is_array($this->model)) {
$this->attributes = array_keys($this->model);
} else {
throw new InvalidConfigException('The "data" property must be either an array or an object.');
}
sort($this->attributes);
}
foreach ($this->attributes as $i => $attribute) {
if (is_string($attribute)) {
if (!preg_match('/^(\w+)(\s*:\s*(\w+))?$/', $attribute, $matches)) {
throw new InvalidConfigException('The attribute must be in the format of "Name" or "Name:Type"');
}
$attribute = array(
'name' => $matches[1],
'type' => isset($matches[3]) ? $matches[3] : 'text',
);
}
if (!is_array($attribute)) {
throw new InvalidConfigException('The attribute configuration must be an array.');
}
if (!isset($attribute['type'])) {
$attribute['type'] = 'text';
}
if (isset($attribute['name'])) {
$name = $attribute['name'];
if (!isset($attribute['label'])) {
$attribute['label'] = $this->model instanceof Model ? $this->model->getAttributeLabel($name) : Inflector::camel2words($name, true);
}
if (!array_key_exists('value', $attribute)) {
$attribute['value'] = ArrayHelper::getValue($this->model, $name);
}
} elseif (!isset($attribute['label']) || !array_key_exists('value', $attribute)) {
throw new InvalidConfigException('The attribute configuration requires the "name" element to determine the value and display label.');
}
$this->attributes[$i] = $attribute;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment