mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-18 23:43:19 +08:00
Merge commit '24e086deaf6336706624e77cc0f63a7062280821' into feature-restapi
This commit is contained in:
@@ -5,6 +5,7 @@ use Yii;
|
||||
use yii\web\AccessControl;
|
||||
use yii\web\Controller;
|
||||
use common\models\LoginForm;
|
||||
use yii\web\VerbFilter;
|
||||
|
||||
/**
|
||||
* Site controller
|
||||
@@ -31,6 +32,12 @@ class SiteController extends Controller
|
||||
],
|
||||
],
|
||||
],
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'logout' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use yii\base\InvalidParamException;
|
||||
use yii\web\BadRequestHttpException;
|
||||
use yii\web\Controller;
|
||||
use Yii;
|
||||
use yii\web\VerbFilter;
|
||||
|
||||
/**
|
||||
* Site controller
|
||||
@@ -38,6 +39,12 @@ class SiteController extends Controller
|
||||
],
|
||||
],
|
||||
],
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'logout' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class PropertyDoc extends BaseDoc
|
||||
$this->types = $tag->getTypes();
|
||||
$this->description = ucfirst($tag->getDescription());
|
||||
if (($pos = strpos($this->description, '.')) !== false) {
|
||||
$this->shortDescription = substr($this->description, 0, $pos);
|
||||
$this->shortDescription = substr($this->description, 0, $pos + 1);
|
||||
} else {
|
||||
$this->shortDescription = $this->description;
|
||||
}
|
||||
|
||||
@@ -50,3 +50,11 @@ body {
|
||||
background: #E6ECFF;
|
||||
border: 1px #BFCFFF solid;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
td p {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ ArrayHelper::multisort($events, 'name');
|
||||
<?php echo $event->trigger->signature; ?>
|
||||
</div>*/ ?>
|
||||
|
||||
<p><?= ApiMarkdown::process($event->description, $type); ?></p>
|
||||
<?= ApiMarkdown::process($event->description, $type); ?>
|
||||
|
||||
<?= $this->render('seeAlso', ['object' => $event]); ?>
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ ArrayHelper::multisort($methods, 'name');
|
||||
|
||||
<!-- --><?php //$this->renderPartial('sourceCode',array('object'=>$method)); ?>
|
||||
|
||||
<p><?= ApiMarkdown::process($method->shortDescription, $type, true) ?></strong></p>
|
||||
<p><?= ApiMarkdown::process($method->description, $type) ?></p>
|
||||
<p><strong><?= ApiMarkdown::process($method->shortDescription, $type, true) ?></strong></p>
|
||||
<?= ApiMarkdown::process($method->description, $type) ?>
|
||||
|
||||
<?= $this->render('seeAlso', ['object' => $method]); ?>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ ArrayHelper::multisort($properties, 'name');
|
||||
|
||||
<div class="signature"><?php echo $this->context->renderPropertySignature($property); ?></div>
|
||||
|
||||
<p><?= ApiMarkdown::process($property->description, $type) ?></p>
|
||||
<?= ApiMarkdown::process($property->description, $type) ?>
|
||||
|
||||
<?= $this->render('seeAlso', ['object' => $property]); ?>
|
||||
|
||||
|
||||
@@ -50,9 +50,6 @@ TBD
|
||||
|
||||
> **NOTE:** elasticsearch limits the number of records returned by any query to 10 records by default.
|
||||
> If you expect to get more records you should specify limit explicitly in relation definition.
|
||||
* This is also important for relations that use [[via()]] so that if via records are limited to 10
|
||||
* the relations records can also not be more than 10.
|
||||
*
|
||||
|
||||
|
||||
Using the ActiveRecord
|
||||
@@ -60,14 +57,15 @@ Using the ActiveRecord
|
||||
|
||||
For general information on how to use yii's ActiveRecord please refer to the [guide](https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md).
|
||||
|
||||
For defining an elasticsearch ActiveRecord class your record class needs to extend from `yii\elasticsearch\ActiveRecord` and
|
||||
implement at least the `attributes()` method to define the attributes of the record.
|
||||
For defining an elasticsearch ActiveRecord class your record class needs to extend from [[yii\elasticsearch\ActiveRecord]] and
|
||||
implement at least the [[yii\elasticsearch\ActiveRecord::attributes()|attributes()]] method to define the attributes of the record.
|
||||
The handling of primary keys is different in elasticsearch as the primary key (the `_id` field in elasticsearch terms)
|
||||
is not part of the attributes by default. However it is possible to define a [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html)
|
||||
for the `_id` field to be part of the attributes.
|
||||
See [elasticsearch docs](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) on how to define it.
|
||||
The `_id` field of a document/record can be accessed using [[ActiveRecord::getPrimaryKey()]] and [[ActiveRecord::setPrimaryKey()]].
|
||||
When path mapping is defined, the attribute name can be defined using the [[primaryKey()]] method.
|
||||
The `_id` field of a document/record can be accessed using [[yii\elasticsearch\ActiveRecord::getPrimaryKey()|getPrimaryKey()]] and
|
||||
[[yii\elasticsearch\ActiveRecord::setPrimaryKey()|setPrimaryKey()]].
|
||||
When path mapping is defined, the attribute name can be defined using the [[yii\elasticsearch\ActiveRecord::primaryKey()|primaryKey()]] method.
|
||||
|
||||
The following is an example model called `Customer`:
|
||||
|
||||
@@ -101,7 +99,8 @@ class Customer extends \yii\elasticsearch\ActiveRecord
|
||||
}
|
||||
```
|
||||
|
||||
You may override [[index()]] and [[type()]] to define the index and type this record represents.
|
||||
You may override [[yii\elasticsearch\ActiveRecord::index()|index()]] and [[yii\elasticsearch\ActiveRecord::type()|type()]]
|
||||
to define the index and type this record represents.
|
||||
|
||||
The general usage of elasticsearch ActiveRecord is very similar to the database ActiveRecord as described in the
|
||||
[guide](https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md).
|
||||
@@ -109,13 +108,18 @@ It supports the same interface and features except the following limitations and
|
||||
|
||||
- As elasticsearch does not support SQL, the query API does not support `join()`, `groupBy()`, `having()` and `union()`.
|
||||
Sorting, limit, offset and conditional where are all supported.
|
||||
- `from()` does not select the tables, but the [index](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/glossary.html#glossary-index)
|
||||
- [[yii\elasticsearch\ActiveQuery::from()|from()]] does not select the tables, but the
|
||||
[index](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/glossary.html#glossary-index)
|
||||
and [type](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/glossary.html#glossary-type) to query against.
|
||||
- `select()` has been replaced with `fields()` which basically does the same but `fields` is more elasticsearch terminology.
|
||||
- `select()` has been replaced with [[yii\elasticsearch\ActiveQuery::fields()|fields()]] which basically does the same but
|
||||
`fields` is more elasticsearch terminology.
|
||||
It defines the fields to retrieve from a document.
|
||||
- `via`-relations can not be defined via a table as there are no tables in elasticsearch. You can only define relations via other records.
|
||||
- As elasticsearch is not only a data storage but also a search engine there is of course support added for search your records.
|
||||
There are `query()`, `filter()` and `addFacets()` methods that allows to compose an elasticsearch query.
|
||||
- [[yii\elasticsearch\ActiveQuery::via()|via]]-relations can not be defined via a table as there are no tables in elasticsearch. You can only define relations via other records.
|
||||
- As elasticsearch is not only a data storage but also a search engine there is of course support added for searching your records.
|
||||
There are
|
||||
[[yii\elasticsearch\ActiveQuery::query()|query()]],
|
||||
[[yii\elasticsearch\ActiveQuery::filter()|filter()]] and
|
||||
[[yii\elasticsearch\ActiveQuery::addFacet()|addFacet()]] methods that allows to compose an elasticsearch query.
|
||||
See the usage example below on how they work and check out the [Query DSL](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html)
|
||||
on how to compose `query` and `filter` parts.
|
||||
- It is also possible to define relations from elasticsearch ActiveRecords to normal ActiveRecord classes and vice versa.
|
||||
|
||||
@@ -148,6 +148,8 @@ Yii Framework 2 Change Log
|
||||
- Enh: Added support for building SQLs with sub-queries (qiangxue)
|
||||
- Enh: Added `Pagination::getLinks()` (qiangxue)
|
||||
- Enh: Added support for reading page size from query parameters by `Pagination` (qiangxue)
|
||||
- Enh: LinkPager can now register relational link tags in the html header for prev, next, first and last page (cebe)
|
||||
- Enh: Added `yii\web\UrlRuleInterface` and `yii\web\CompositeUrlRule` (qiangxue)
|
||||
- Chg #1186: Changed `Sort` to use comma to separate multiple sort fields and use negative sign to indicate descending sort (qiangxue)
|
||||
- Chg #1519: `yii\web\User::loginRequired()` now returns the `Response` object instead of exiting the application (qiangxue)
|
||||
- Chg #1586: `QueryBuilder::buildLikeCondition()` will now escape special characters and use percentage characters by default (qiangxue)
|
||||
|
||||
73
framework/web/CompositeUrlRule.php
Normal file
73
framework/web/CompositeUrlRule.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\web;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Object;
|
||||
|
||||
/**
|
||||
* CompositeUrlRule represents a collection of related URL rules.
|
||||
*
|
||||
* These URL rules are typically created for a common purpose (e.g. RESTful API for a resource).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class CompositeUrlRule extends Object implements UrlRuleInterface
|
||||
{
|
||||
/**
|
||||
* @var UrlRuleInterface[] the URL rules contained in this composite rule.
|
||||
* This property is set in [[init()]] by the return value of [[createRules()]].
|
||||
*/
|
||||
protected $rules = [];
|
||||
|
||||
|
||||
/**
|
||||
* Creates the URL rules that should be contained within this composite rule.
|
||||
* @return UrlRuleInterface[] the URL rules
|
||||
*/
|
||||
abstract protected function createRules();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->rules = $this->createRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function parseRequest($manager, $request)
|
||||
{
|
||||
foreach ($this->rules as $rule) {
|
||||
/** @var \yii\web\UrlRule $rule */
|
||||
if (($result = $rule->parseRequest($manager, $request)) !== false) {
|
||||
Yii::trace("Request parsed with URL rule: {$rule->name}", __METHOD__);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function createUrl($manager, $route, $params)
|
||||
{
|
||||
foreach ($this->rules as $rule) {
|
||||
/** @var \yii\web\UrlRule $rule */
|
||||
if (($url = $rule->createUrl($manager, $route, $params)) !== false) {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ namespace yii\web;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Component;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\caching\Cache;
|
||||
|
||||
/**
|
||||
@@ -156,17 +157,22 @@ class UrlManager extends Component
|
||||
}
|
||||
|
||||
$rules = [];
|
||||
$verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS';
|
||||
foreach ($this->rules as $key => $rule) {
|
||||
if (!is_array($rule)) {
|
||||
$rule = ['route' => $rule];
|
||||
if (preg_match('/^((?:(GET|HEAD|POST|PUT|PATCH|DELETE),)*(GET|HEAD|POST|PUT|PATCH|DELETE))\s+(.*)$/', $key, $matches)) {
|
||||
if (preg_match("/^((?:($verbs),)*($verbs))\\s+(.*)$/", $key, $matches)) {
|
||||
$rule['verb'] = explode(',', $matches[1]);
|
||||
$rule['mode'] = UrlRule::PARSING_ONLY;
|
||||
$key = $matches[4];
|
||||
}
|
||||
$rule['pattern'] = $key;
|
||||
}
|
||||
$rules[] = Yii::createObject(array_merge($this->ruleConfig, $rule));
|
||||
$rule = Yii::createObject(array_merge($this->ruleConfig, $rule));
|
||||
if (!$rule instanceof UrlRuleInterface) {
|
||||
throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.');
|
||||
}
|
||||
$rules[] = $rule;
|
||||
}
|
||||
$this->rules = $rules;
|
||||
|
||||
@@ -188,7 +194,6 @@ class UrlManager extends Component
|
||||
/** @var UrlRule $rule */
|
||||
foreach ($this->rules as $rule) {
|
||||
if (($result = $rule->parseRequest($this, $request)) !== false) {
|
||||
Yii::trace("Request parsed with URL rule: {$rule->name}", __METHOD__);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -245,7 +250,7 @@ class UrlManager extends Component
|
||||
/** @var UrlRule $rule */
|
||||
foreach ($this->rules as $rule) {
|
||||
if (($url = $rule->createUrl($this, $route, $params)) !== false) {
|
||||
if ($rule->host !== null) {
|
||||
if (strpos($url, '://') !== false) {
|
||||
if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) {
|
||||
return substr($url, 0, $pos) . $baseUrl . substr($url, $pos);
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
namespace yii\web;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Object;
|
||||
use yii\base\InvalidConfigException;
|
||||
|
||||
@@ -26,7 +27,7 @@ use yii\base\InvalidConfigException;
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class UrlRule extends Object
|
||||
class UrlRule extends Object implements UrlRuleInterface
|
||||
{
|
||||
/**
|
||||
* Set [[mode]] with this value to mark that this rule is for URL parsing only
|
||||
@@ -47,7 +48,7 @@ class UrlRule extends Object
|
||||
*/
|
||||
public $pattern;
|
||||
/**
|
||||
* @var string the pattern used to parse and create the host info part of a URL.
|
||||
* @var string the pattern used to parse and create the host info part of a URL (e.g. `http://example.com`).
|
||||
* @see pattern
|
||||
*/
|
||||
public $host;
|
||||
@@ -127,7 +128,8 @@ class UrlRule extends Object
|
||||
$this->pattern = trim($this->pattern, '/');
|
||||
|
||||
if ($this->host !== null) {
|
||||
$this->pattern = rtrim($this->host, '/') . rtrim('/' . $this->pattern, '/') . '/';
|
||||
$this->host = rtrim($this->host, '/');
|
||||
$this->pattern = rtrim($this->host . '/' . $this->pattern, '/');
|
||||
} elseif ($this->pattern === '') {
|
||||
$this->_template = '';
|
||||
$this->pattern = '#^$#u';
|
||||
@@ -157,7 +159,7 @@ class UrlRule extends Object
|
||||
foreach ($matches as $match) {
|
||||
$name = $match[1][0];
|
||||
$pattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+';
|
||||
if (isset($this->defaults[$name])) {
|
||||
if (array_key_exists($name, $this->defaults)) {
|
||||
$length = strlen($match[0][0]);
|
||||
$offset = $match[0][1];
|
||||
if ($offset > 1 && $this->pattern[$offset - 1] === '/' && $this->pattern[$offset + $length] === '/') {
|
||||
@@ -243,6 +245,9 @@ class UrlRule extends Object
|
||||
} else {
|
||||
$route = $this->route;
|
||||
}
|
||||
|
||||
Yii::trace("Request parsed with URL rule: {$this->name}", __METHOD__);
|
||||
|
||||
return [$route, $params];
|
||||
}
|
||||
|
||||
|
||||
34
framework/web/UrlRuleInterface.php
Normal file
34
framework/web/UrlRuleInterface.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\web;
|
||||
|
||||
/**
|
||||
* UrlRuleInterface is the interface that should be implemented URL rule classes.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
interface UrlRuleInterface
|
||||
{
|
||||
/**
|
||||
* Parses the given request and returns the corresponding route and parameters.
|
||||
* @param UrlManager $manager the URL manager
|
||||
* @param Request $request the request component
|
||||
* @return array|boolean the parsing result. The route and the parameters are returned as an array.
|
||||
* If false, it means this rule cannot be used to parse this path info.
|
||||
*/
|
||||
public function parseRequest($manager, $request);
|
||||
/**
|
||||
* Creates a URL according to the given route and parameters.
|
||||
* @param UrlManager $manager the URL manager
|
||||
* @param string $route the route. It should not have slashes at the beginning or the end.
|
||||
* @param array $params the parameters
|
||||
* @return string|boolean the created URL, or false if this rule cannot be used for creating this URL.
|
||||
*/
|
||||
public function createUrl($manager, $route, $params);
|
||||
}
|
||||
@@ -89,6 +89,13 @@ class LinkPager extends Widget
|
||||
* If this property is null, the "last" page button will not be displayed.
|
||||
*/
|
||||
public $lastPageLabel;
|
||||
/**
|
||||
* @var bool whether to register link tags in the HTML header for prev, next, first and last page.
|
||||
* Defaults to `false` to avoid conflicts when multiple pagers are used on one page.
|
||||
* @see http://www.w3.org/TR/html401/struct/links.html#h-12.1.2
|
||||
* @see registerLinkTags()
|
||||
*/
|
||||
public $registerLinkTags = false;
|
||||
|
||||
|
||||
/**
|
||||
@@ -107,9 +114,25 @@ class LinkPager extends Widget
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if ($this->registerLinkTags) {
|
||||
$this->registerLinkTags();
|
||||
}
|
||||
echo $this->renderPageButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers relational link tags in the html header for prev, next, first and last page.
|
||||
* These links are generated using [[yii\data\Pagination::getLinks()]].
|
||||
* @see http://www.w3.org/TR/html401/struct/links.html#h-12.1.2
|
||||
*/
|
||||
protected function registerLinkTags()
|
||||
{
|
||||
$view = $this->getView();
|
||||
foreach($this->pagination->getLinks() as $rel => $href) {
|
||||
$view->registerLinkTag(['rel' => $rel, 'href' => $href], $rel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the page buttons.
|
||||
* @return string the rendering result
|
||||
|
||||
@@ -33,13 +33,13 @@ class ActiveRecordTest extends RedisTestCase
|
||||
ActiveRecord::$db = $this->getConnection();
|
||||
|
||||
$customer = new Customer();
|
||||
$customer->setAttributes(['email' => 'user1@example.com', 'name' => 'user1', 'address' => 'address1', 'status' => 1], false);
|
||||
$customer->setAttributes(['email' => 'user1@example.com', 'name' => 'user1', 'address' => 'address1', 'status' => 1, 'profile_id' => 1], false);
|
||||
$customer->save(false);
|
||||
$customer = new Customer();
|
||||
$customer->setAttributes(['email' => 'user2@example.com', 'name' => 'user2', 'address' => 'address2', 'status' => 1], false);
|
||||
$customer->setAttributes(['email' => 'user2@example.com', 'name' => 'user2', 'address' => 'address2', 'status' => 1, 'profile_id' => null], false);
|
||||
$customer->save(false);
|
||||
$customer = new Customer();
|
||||
$customer->setAttributes(['email' => 'user3@example.com', 'name' => 'user3', 'address' => 'address3', 'status' => 2], false);
|
||||
$customer->setAttributes(['email' => 'user3@example.com', 'name' => 'user3', 'address' => 'address3', 'status' => 2, 'profile_id' => 2], false);
|
||||
$customer->save(false);
|
||||
|
||||
// INSERT INTO tbl_category (name) VALUES ('Books');
|
||||
|
||||
@@ -12,6 +12,12 @@ use yiiunit\TestCase;
|
||||
*/
|
||||
class UrlRuleTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->mockApplication();
|
||||
}
|
||||
|
||||
public function testCreateUrl()
|
||||
{
|
||||
$manager = new UrlManager(['cache' => null]);
|
||||
|
||||
Reference in New Issue
Block a user