Browse Source

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

tags/2.0.0-beta
resurtm 12 years ago
parent
commit
5892b265fa
  1. 187
      docs/guide/controller.md
  2. 21
      docs/guide/database-basics.md
  3. 32
      docs/guide/upgrade-from-v1.md
  4. 0
      docs/internals/autoloader.md
  5. 20
      framework/yii/base/Formatter.php
  6. 2
      framework/yii/base/Model.php
  7. 206
      framework/yii/widgets/DetailView.php

187
docs/guide/controller.md

@ -0,0 +1,187 @@
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)

21
docs/guide/database-basics.md

@ -133,27 +133,26 @@ $connection->createCommand()->delete('tbl_user', 'status = 0')->execute();
Quoting table and column names
------------------------------
If you are building query string dynamically make sure you're properly quoting table and column names using
[[\yii\db\Connection::quoteTableName()]] and [[\yii\db\Connection::quoteColumnName()]]:
Most of the time you would use the following syntax for quoting table and column names:
```php
$column = $connection->quoteColumnName($column);
$table = $connection->quoteTableName($table);
$sql = "SELECT COUNT($column) FROM $table";
$sql = "SELECT COUNT([[$column]]) FROM {{$table}}";
$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
$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();
```
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
-------------------

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

@ -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,
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
validation under which scenario. Child classes should overwrite `scenarios()` to return
@ -196,18 +216,6 @@ 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,
```php
$model = new Post;
if ($model->load($_POST)) {...}
// which is equivalent to:
if (isset($_POST['Post'])) {
$model->attributes = $_POST['Post'];
}
```
Widgets
-------

0
docs/autoloader.md → docs/internals/autoloader.md

20
framework/yii/base/Formatter.php

@ -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.
* This method simply returns back the parameter without any format.
* @param mixed $value the value to be formatted

2
framework/yii/base/Model.php

@ -694,7 +694,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
$success = true;
}
} elseif (isset($data[$scope][$i])) {
$model->setAttributes($data[$scope[$i]]);
$model->setAttributes($data[$scope][$i]);
$success = true;
}
}

206
framework/yii/widgets/DetailView.php

@ -0,0 +1,206 @@
<?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;
}
}
}
Loading…
Cancel
Save