Browse Source

Merge commit '24e086deaf6336706624e77cc0f63a7062280821' into feature-restapi

tags/2.0.0-beta
Qiang Xue 11 years ago
parent
commit
1f292ef503
  1. 7
      apps/advanced/backend/controllers/SiteController.php
  2. 7
      apps/advanced/frontend/controllers/SiteController.php
  3. 2
      extensions/apidoc/models/PropertyDoc.php
  4. 8
      extensions/apidoc/templates/bootstrap/assets/css/style.css
  5. 2
      extensions/apidoc/templates/html/views/eventDetails.php
  6. 4
      extensions/apidoc/templates/html/views/methodDetails.php
  7. 2
      extensions/apidoc/templates/html/views/propertyDetails.php
  8. 30
      extensions/elasticsearch/README.md
  9. 2
      framework/CHANGELOG.md
  10. 73
      framework/web/CompositeUrlRule.php
  11. 13
      framework/web/UrlManager.php
  12. 13
      framework/web/UrlRule.php
  13. 34
      framework/web/UrlRuleInterface.php
  14. 23
      framework/widgets/LinkPager.php
  15. 6
      tests/unit/extensions/redis/ActiveRecordTest.php
  16. 6
      tests/unit/framework/web/UrlRuleTest.php

7
apps/advanced/backend/controllers/SiteController.php

@ -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'],
],
],
];
}

7
apps/advanced/frontend/controllers/SiteController.php

@ -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'],
],
],
];
}

2
extensions/apidoc/models/PropertyDoc.php

@ -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;
}

8
extensions/apidoc/templates/bootstrap/assets/css/style.css vendored

@ -50,3 +50,11 @@ body {
background: #E6ECFF;
border: 1px #BFCFFF solid;
}
blockquote {
font-size: 14px;
}
td p {
margin: 0;
}

2
extensions/apidoc/templates/html/views/eventDetails.php vendored

@ -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]); ?>

4
extensions/apidoc/templates/html/views/methodDetails.php vendored

@ -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]); ?>

2
extensions/apidoc/templates/html/views/propertyDetails.php vendored

@ -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]); ?>

30
extensions/elasticsearch/README.md

@ -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.

2
framework/CHANGELOG.md

@ -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

@ -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;
}
}

13
framework/web/UrlManager.php

@ -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 {

13
framework/web/UrlRule.php

@ -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

@ -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);
}

23
framework/widgets/LinkPager.php

@ -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,10 +114,26 @@ 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
*/

6
tests/unit/extensions/redis/ActiveRecordTest.php

@ -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');

6
tests/unit/framework/web/UrlRuleTest.php

@ -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]);

Loading…
Cancel
Save