Commit b260fbbd by Aleksandr Krivtcun

Merge branch 'master' of git://github.com/yiisoft/yii2 into translation-ru-structure-widgets

parents 8eb73958 37dde677
<?php <?php
namespace common\models; namespace common\models;
use Yii;
use yii\base\NotSupportedException; use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
use Yii;
use yii\web\IdentityInterface; use yii\web\IdentityInterface;
/** /**
...@@ -25,7 +26,6 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -25,7 +26,6 @@ class User extends ActiveRecord implements IdentityInterface
{ {
const STATUS_DELETED = 0; const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10; const STATUS_ACTIVE = 10;
const ROLE_USER = 10; const ROLE_USER = 10;
/** /**
...@@ -42,13 +42,7 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -42,13 +42,7 @@ class User extends ActiveRecord implements IdentityInterface
public function behaviors() public function behaviors()
{ {
return [ return [
'timestamp' => [ TimestampBehavior::className(),
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
],
]; ];
} }
...@@ -101,7 +95,7 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -101,7 +95,7 @@ class User extends ActiveRecord implements IdentityInterface
*/ */
public static function findByPasswordResetToken($token) public static function findByPasswordResetToken($token)
{ {
$expire = \Yii::$app->params['user.passwordResetTokenExpire']; $expire = Yii::$app->params['user.passwordResetTokenExpire'];
$parts = explode('_', $token); $parts = explode('_', $token);
$timestamp = (int) end($parts); $timestamp = (int) end($parts);
if ($timestamp + $expire < time()) { if ($timestamp + $expire < time()) {
......
...@@ -69,14 +69,6 @@ $requirements = array( ...@@ -69,14 +69,6 @@ $requirements = array(
'condition' => extension_loaded('apc'), 'condition' => extension_loaded('apc'),
'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>', 'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>',
), ),
// Additional PHP extensions :
array(
'name' => 'Mcrypt extension',
'mandatory' => false,
'condition' => extension_loaded('mcrypt'),
'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-helpers-security.html">Security Helper</a>',
'memo' => 'Required by encrypt and decrypt methods.'
),
// PHP ini : // PHP ini :
'phpSafeMode' => array( 'phpSafeMode' => array(
'name' => 'PHP safe mode', 'name' => 'PHP safe mode',
......
...@@ -69,14 +69,6 @@ $requirements = array( ...@@ -69,14 +69,6 @@ $requirements = array(
'condition' => extension_loaded('apc'), 'condition' => extension_loaded('apc'),
'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>', 'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>',
), ),
// Additional PHP extensions :
array(
'name' => 'Mcrypt extension',
'mandatory' => false,
'condition' => extension_loaded('mcrypt'),
'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-helpers-security.html">Security Helper</a>',
'memo' => 'Required by encrypt and decrypt methods.'
),
// PHP ini : // PHP ini :
'phpSafeMode' => array( 'phpSafeMode' => array(
'name' => 'PHP safe mode', 'name' => 'PHP safe mode',
......
Componentes
===========
Los componentes son los principales bloques de construcción de las aplicaciones Yii. Los componentes son instancias de
[[yii\base\Component]] o de una clase extendida. Las tres características principales que los componentes proporcionan
a las otras clases son:
* [Propiedades](concept-properties.md)
* [Eventos](concept-events.md)
* [Comportamientos](concept-behaviors.md)
Por separado y combinadas, estas características hacen que las clases Yii sean mucho mas personalizables y sean mucho
más fáciles de usar. Por ejemplo, el incluido [[yii\jui\DatePicker|widget de selección de fecha]], un componente de la
interfaz de usuario, puede ser utilizado en una [vista](structure-view.md) para generar un selector de fechas interactivo:
```php
use yii\jui\DatePicker;
echo DatePicker::widget([
'language' => 'ru',
'name' => 'country',
'clientOptions' => [
'dateFormat' => 'yy-mm-dd',
],
]);
```
Las propiedades del widget son facilmente modificables porque la clase se extiende de [[yii\base\Component]].
Mientras que los componentes son muy potentes, son un poco más pesados que los objetos normales, debido al hecho de que
necesitan más memoria y tiempo de CPU para poder soportar [eventos](concept-events.md) y [comportamientos](concept-behaviors.md) en particular.
Si tus componentes no necesitan estas dos características, deberías considerar extender tu componente directamente de
[[yii\base\Object]] en vez de [[yii\base\Component]]. De esta manera harás que tus componentes sean mucho más eficientes que
que objetos PHP normales, pero con el añadido soporte para [propiedades](concept-properties.md).
Cuando extiendes tu clase de [[yii\base\Component]] o [[yii\base\Object]], se recomienda que sigas las siguientes
convenciones:
- Si sobrescribes el constructor, especifica un parámetro `$config` como el *último* parámetro del constructor, y después
pasa este parámetro al constructor de la clase "padre".
- Siempre llama al constructor del "padre" al *final* de su propio constructor.
- Si sobrescribes el método [[yii\base\Object::init()]], asegúrate de que llamas a la implementación de la clase "padre"
*al principio* de tu método `init`.
Por ejemplo:
```php
namespace yii\components\MyClass;
use yii\base\Object;
class MyClass extends Object
{
public $prop1;
public $prop2;
public function __construct($param1, $param2, $config = [])
{
// ... inicialización antes de la configuración está siendo aplicada
parent::__construct($config);
}
public function init()
{
parent::init();
// ... inicialización despues de la configuración esta siendo aplicada
}
}
```
Siguiendo esas directrices hará que tus componentes sean [configurables](concept-configurations.md) cuando son creados. Por ejemplo:
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// alternativamente
$component = \Yii::createObject([
'class' => MyClass::className(),
'prop1' => 3,
'prop2' => 4,
], [1, 2]);
```
> Información: Mientras que el enfoque de llamar [[Yii::createObject()]] parece mucho más complicado, es mucho más potente
debido al hecho de que se implementa en la parte superior de un [contenedor de inyección de dependencia](concept-di-container.md).
La clase [[yii\base\Object]] hace cumplir el siguiente ciclo de vida del objeto:
1. Pre-inicialización en el constructor. Puedes establecer los valores predeterminados de propiedades aquí.
2. Configuración del objeto a través de `$config`. La configuración puede sobrescribir los valores prdeterminados dentro
del constructor.
3. Post-inicialización dentro de [[yii\base\Object::init()|init()]]. Puedes sobrescribir este método para realizar
comprobaciones de validez y normalización de las propiedades.
4. LLamadas a métodos del objeto.
Los tres primeros pasos ocurren dentro del constructor del objeto. Esto significa que una vez obtengas la instancia de
un objeto, ésta ha sido inicializada para que puedas utilizarla adecuadamente.
...@@ -3,7 +3,7 @@ Extending Yii ...@@ -3,7 +3,7 @@ Extending Yii
> Note: This section is under development. > Note: This section is under development.
The Yii framework was designed to be easily extendable. Additional features can be added to your project and then reused, either by yourself on other projects or by sharing your work as a formal Yii extension. The Yii framework was designed to be easily extensible. Additional features can be added to your project and then reused, either by yourself on other projects or by sharing your work as a formal Yii extension.
Code style Code style
---------- ----------
......
Helper Classes
==============
> Note: This section is under development.
Yii provides many classes that help simplify common coding tasks, such as string or array manipulations,
HTML code generation, and so forth. These helper classes are organized under the `yii\helpers` namespace and
are all static classes (meaning they contain only static properties and methods and should not be instantiated).
You use a helper class by directly calling one of its static methods:
```
use yii\helpers\ArrayHelper;
$c = ArrayHelper::merge($a, $b);
```
Extending Helper Classes
------------------------
To make helper classes easier to extend, Yii breaks each helper class into two classes: a base class (e.g. `BaseArrayHelper`)
and a concrete class (e.g. `ArrayHelper`). When you use a helper, you should only use the concrete version, never use the base class.
If you want to customize a helper, perform the following steps (using `ArrayHelper` as an example):
1. Name your class the same as the concrete class provided by Yii, including the namespace: `yii\helpers\ArrayHelper`
2. Extend your class from the base class: `class ArrayHelper extends \yii\helpers\BaseArrayHelper`.
3. In your class, override any method or property as needed, or add new methods or properties.
4. Tell your application to use your version of the helper class by including the following line of code in the bootstrap script:
```php
Yii::$classMap['yii\helpers\ArrayHelper'] = 'path/to/ArrayHelper.php';
```
Step 4 above will instruct the Yii class autoloader to load your version of the helper class instead of the one included in the Yii distribution.
> Tip: You can use `Yii::$classMap` to replace ANY core Yii class with your own customized version, not just helper classes.
...@@ -22,6 +22,20 @@ curl -s http://getcomposer.org/installer | php ...@@ -22,6 +22,20 @@ curl -s http://getcomposer.org/installer | php
We strongly recommend a global composer installation. We strongly recommend a global composer installation.
Installing Composer Class Autoloader
------------------------------------
Make sure the [entry script](concept-entry-scripts.md) of your application contains the following lines of code:
```php
// install Composer's class autoloader
require(__DIR__ . '/../vendor/autoload.php');
// include Yii class file
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
Working with composer Working with composer
--------------------- ---------------------
...@@ -52,7 +66,7 @@ composer.phar update ...@@ -52,7 +66,7 @@ composer.phar update
As an example, packages on `dev-master` will constantly get new updates when you run `update`, while running `install` won't, unless you've pulled an update of the `composer.lock` file. As an example, packages on `dev-master` will constantly get new updates when you run `update`, while running `install` won't, unless you've pulled an update of the `composer.lock` file.
There are several paramaters available to the above commands. Very commonly used ones are `--no-dev`, which would skip packages in the `require-dev` section and `--prefer-dist`, which downloads archives if available, instead of checking out repositories to your `vendor` folder. There are several parameters available to the above commands. Very commonly used ones are `--no-dev`, which would skip packages in the `require-dev` section and `--prefer-dist`, which downloads archives if available, instead of checking out repositories to your `vendor` folder.
> Composer commands must be executed within your Yii project's directory, where the `composer.json` file can be found. > Composer commands must be executed within your Yii project's directory, where the `composer.json` file can be found.
Depending upon your operating system and setup, you may need to provide paths to the PHP executable and Depending upon your operating system and setup, you may need to provide paths to the PHP executable and
...@@ -100,7 +114,7 @@ afterwards. ...@@ -100,7 +114,7 @@ afterwards.
> Depending on the package additional configuration may be required (eg. you have to register a module in the config), but autoloading of the classes should be handled by composer. > Depending on the package additional configuration may be required (eg. you have to register a module in the config), but autoloading of the classes should be handled by composer.
Using a specifc version of a package Using a specific version of a package
------------------------------------ ------------------------------------
Yii always comes with the latest version of a required library that it is compatible with, but allows you to use an older version if you need to. Yii always comes with the latest version of a required library that it is compatible with, but allows you to use an older version if you need to.
......
...@@ -3,14 +3,26 @@ Helpers ...@@ -3,14 +3,26 @@ Helpers
> Note: This section is under development. > Note: This section is under development.
Helper classes typically contain static methods only and are used as follows: Yii provides many classes that help simplify common coding tasks, such as string or array manipulations,
HTML code generation, and so on. These helper classes are organized under the `yii\helpers` namespace and
are all static classes (meaning they contain only static properties and methods and should not be instantiated).
You use a helper class by directly calling one of its static methods, like the following:
```php ```php
use \yii\helpers\Html; use yii\helpers\Html;
echo Html::encode('Test > test'); echo Html::encode('Test > test');
``` ```
There are several classes provided by framework: > Note: To support [extending helper classes](#extending-helper-classes), Yii breaks each core helper class
into two classes: a base class (e.g. `BaseArrayHelper`) and a concrete class (e.g. `ArrayHelper`).
When you use a helper, you should only use the concrete version and never use the base class.
## Core Helper Classes
The following core helper classes are provided in the Yii releases:
- ArrayHelper - ArrayHelper
- Console - Console
...@@ -25,3 +37,39 @@ There are several classes provided by framework: ...@@ -25,3 +37,39 @@ There are several classes provided by framework:
- StringHelper - StringHelper
- Url - Url
- VarDumper - VarDumper
## Extending Helper Classes
To custom a core helper class (e.g. `yii\helpers\ArrayHelper`), you should extend from its corresponding base class
(e.g. `yii\helpers\BaseArrayHelper`) and name your class the same as the corresponding concrete class
(e.g. `yii\helpers\ArrayHelper`), including its namespace.
The following example shows how to customize the [[yii\helpers\ArrayHelper::merge()|merge()]] method of the
[[yii\helpers\ArrayHelper]] class:
```php
namespace yii\helpers;
use yii\helpers\BaseArrayHelper;
class ArrayHelper extends BaseArrayHelper
{
public static function merge($a, $b)
{
// your custom implementation
}
}
```
Save your class in a file named `ArrayHelper.php`. The file can be in any directory, such as `@app/components`.
Next, in your application's [entry script](structure-entry-scripts.md), add the following line of code
after including the `yii.php` file:
```php
Yii::$classMap['yii\helpers\ArrayHelper'] = 'path/to/ArrayHelper.php';
```
The above line instructs the [Yii class autoloader](concept-autoloading.md) to load your version of the helper
class, instead of the one included in the Yii releases.
...@@ -121,6 +121,12 @@ Yii Framework 2 Change Log ...@@ -121,6 +121,12 @@ Yii Framework 2 Change Log
- Improved overall slug results. - Improved overall slug results.
- Added note about the fact that intl is required for non-latin languages to requirements checker. - Added note about the fact that intl is required for non-latin languages to requirements checker.
- Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq) - Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq)
- Enh #4072: `\yii\rbac\PhpManager` adjustments (samdark)
- Data is now stored in three separate files for items, assignments and rules. File format is simpler.
- Removed `authFile`. Added `itemFile`, `assignmentFile` and `ruleFile`.
- `createdAt` and `updatedAt` are now properly filled with corresponding file modification time.
- `save()` and `load()` are now protected instead of public.
- Added unit test for saving and loading data.
- Enh #4080: Added proper handling and support of the symlinked directories in `FileHelper`, added $options parameter in `FileHelper::removeDirectory()` (resurtm) - Enh #4080: Added proper handling and support of the symlinked directories in `FileHelper`, added $options parameter in `FileHelper::removeDirectory()` (resurtm)
- Enh #4086: changedAttributes of afterSave Event now contain old values (dizews) - Enh #4086: changedAttributes of afterSave Event now contain old values (dizews)
- Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue) - Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue)
......
...@@ -74,6 +74,54 @@ Upgrade from Yii 2.0 Beta ...@@ -74,6 +74,54 @@ Upgrade from Yii 2.0 Beta
* `mail` component was renamed to `mailer`, `yii\log\EmailTarget::$mail` was renamed to `yii\log\EmailTarget::$mailer`. * `mail` component was renamed to `mailer`, `yii\log\EmailTarget::$mail` was renamed to `yii\log\EmailTarget::$mailer`.
Please update all references in the code and config files. Please update all references in the code and config files.
* `\yii\rbac\PhpManager` now stores data in three separate files instead of one. In order to convert old file to
new ones save the following code as `convert.php` that should be placed in the same directory your `rbac.php` is in:
```php
<?php
$oldFile = 'rbac.php';
$itemsFile = 'items.php';
$assignmentsFile = 'assignments.php';
$rulesFile = 'rules.php';
$oldData = include $oldFile;
function saveToFile($data, $fileName) {
$out = var_export($data, true);
$out = "<?php\nreturn " . $out . ";";
$out = str_replace(['array (', ')'], ['[', ']'], $out);
file_put_contents($fileName, $out);
}
$items = [];
$assignments = [];
if (isset($oldData['items'])) {
foreach ($oldData['items'] as $name => $data) {
if (isset($data['assignments'])) {
foreach ($data['assignments'] as $userId => $assignmentData) {
$assignments[$userId] = $assignmentData['roleName'];
}
unset($data['assignments']);
}
$items[$name] = $data;
}
}
$rules = [];
if (isset($oldData['rules'])) {
$rules = $oldData['rules'];
}
saveToFile($items, $itemsFile);
saveToFile($assignments, $assignmentsFile);
saveToFile($rules, $rulesFile);
echo "Done!\n";
```
Run it once, delete `rbac.php`. If you've configured `authFile` property, remove the line from config and instead
configure `itemFile`, `assignmentFile` and `ruleFile`.
* Static helper `yii\helpers\Security` has been converted into an application component. You should change all usage of * Static helper `yii\helpers\Security` has been converted into an application component. You should change all usage of
its methods to a new syntax, for example: instead of `yii\helpers\Security::hashData()` use `Yii::$app->getSecurity()->hashData()`. its methods to a new syntax, for example: instead of `yii\helpers\Security::hashData()` use `Yii::$app->getSecurity()->hashData()`.
Default encryption and hash parameters has been upgraded. If you need to decrypt/validate data that was encrypted/hashed Default encryption and hash parameters has been upgraded. If you need to decrypt/validate data that was encrypted/hashed
......
...@@ -309,11 +309,19 @@ class Security extends Component ...@@ -309,11 +309,19 @@ class Security extends Component
* Generates a random key. * Generates a random key.
* Note the generated key is a binary string with the specified number of bytes in it. * Note the generated key is a binary string with the specified number of bytes in it.
* @param integer $length the length of the key that should be generated * @param integer $length the length of the key that should be generated
* @throws Exception on failure.
* @return string the generated random key * @return string the generated random key
*/ */
public function generateRandomKey($length = 32) public function generateRandomKey($length = 32)
{ {
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); if (!extension_loaded('mcrypt')) {
throw new InvalidConfigException('The mcrypt PHP extension is not installed.');
}
$key = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
if ($key === false) {
throw new Exception('Unable to generate random key.');
}
return $key;
} }
/** /**
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace yii\helpers; namespace yii\helpers;
use Yii; use Yii;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
/** /**
...@@ -117,9 +118,17 @@ class BaseFileHelper ...@@ -117,9 +118,17 @@ class BaseFileHelper
* @param boolean $checkExtension whether to use the file extension to determine the MIME type in case * @param boolean $checkExtension whether to use the file extension to determine the MIME type in case
* `finfo_open()` cannot determine it. * `finfo_open()` cannot determine it.
* @return string the MIME type (e.g. `text/plain`). Null is returned if the MIME type cannot be determined. * @return string the MIME type (e.g. `text/plain`). Null is returned if the MIME type cannot be determined.
* @throws InvalidConfigException when the `fileinfo` PHP extension is not installed and `$checkExtension` is `false`.
*/ */
public static function getMimeType($file, $magicFile = null, $checkExtension = true) public static function getMimeType($file, $magicFile = null, $checkExtension = true)
{ {
if (!extension_loaded('fileinfo')) {
if ($checkExtension) {
return static::getMimeTypeByExtension($file, $magicFile);
} else {
throw new InvalidConfigException('The fileinfo PHP extension is not installed.');
}
}
$info = finfo_open(FILEINFO_MIME_TYPE, $magicFile); $info = finfo_open(FILEINFO_MIME_TYPE, $magicFile);
if ($info) { if ($info) {
...@@ -131,7 +140,7 @@ class BaseFileHelper ...@@ -131,7 +140,7 @@ class BaseFileHelper
} }
} }
return $checkExtension ? static::getMimeTypeByExtension($file) : null; return $checkExtension ? static::getMimeTypeByExtension($file, $magicFile) : null;
} }
/** /**
......
...@@ -13,8 +13,6 @@ use yii\base\Object; ...@@ -13,8 +13,6 @@ use yii\base\Object;
/** /**
* Assignment represents an assignment of a role to a user. * Assignment represents an assignment of a role to a user.
* *
* It includes additional assignment information including [[ruleName]] and [[data]].
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Alexander Kochetov <creocoder@gmail.com> * @author Alexander Kochetov <creocoder@gmail.com>
* @since 2.0 * @since 2.0
......
...@@ -39,6 +39,13 @@ return array( ...@@ -39,6 +39,13 @@ return array(
'memo' => 'Required for multibyte encoding string processing.' 'memo' => 'Required for multibyte encoding string processing.'
), ),
array( array(
'name' => 'Mcrypt extension',
'mandatory' => false,
'condition' => extension_loaded('mcrypt'),
'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-base-security.html">Security Component</a>',
'memo' => 'Required by encrypt and decrypt methods.'
),
array(
'name' => 'Intl extension', 'name' => 'Intl extension',
'mandatory' => false, 'mandatory' => false,
'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2', '>='), 'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2', '>='),
...@@ -50,7 +57,7 @@ return array( ...@@ -50,7 +57,7 @@ return array(
), ),
array( array(
'name' => 'Fileinfo extension', 'name' => 'Fileinfo extension',
'mandatory' => true, 'mandatory' => false,
'condition' => extension_loaded('fileinfo'), 'condition' => extension_loaded('fileinfo'),
'by' => '<a href="http://www.php.net/manual/en/book.fileinfo.php">File Information</a>', 'by' => '<a href="http://www.php.net/manual/en/book.fileinfo.php">File Information</a>',
'memo' => 'Required for files upload to detect correct file mime-types.' 'memo' => 'Required for files upload to detect correct file mime-types.'
......
...@@ -131,4 +131,11 @@ class SecurityTest extends TestCase ...@@ -131,4 +131,11 @@ class SecurityTest extends TestCase
$decryptedData = $this->security->decrypt($encryptedData, $key); $decryptedData = $this->security->decrypt($encryptedData, $key);
$this->assertEquals($data, $decryptedData); $this->assertEquals($data, $decryptedData);
} }
public function testGenerateRandomKey()
{
$keyLength = 20;
$key = $this->security->generateRandomKey($keyLength);
$this->assertEquals($keyLength, strlen($key));
}
} }
<?php
namespace yiiunit\framework\rbac;
use yii\rbac\PhpManager;
/**
* Exposes protected properties and methods to inspect from outside
*/
class ExposedPhpManager extends PhpManager
{
/**
* @var \yii\rbac\Item[]
*/
public $items = []; // itemName => item
/**
* @var array
*/
public $children = []; // itemName, childName => child
/**
* @var \yii\rbac\Assignment[]
*/
public $assignments = []; // userId, itemName => assignment
/**
* @var \yii\rbac\Rule[]
*/
public $rules = []; // ruleName => rule
public function load()
{
parent::load();
}
public function save()
{
parent::save();
}
}
\ No newline at end of file
...@@ -7,6 +7,9 @@ use yii\rbac\Permission; ...@@ -7,6 +7,9 @@ use yii\rbac\Permission;
use yii\rbac\Role; use yii\rbac\Role;
use yiiunit\TestCase; use yiiunit\TestCase;
/**
* ManagerTestCase
*/
abstract class ManagerTestCase extends TestCase abstract class ManagerTestCase extends TestCase
{ {
/** /**
...@@ -14,7 +17,7 @@ abstract class ManagerTestCase extends TestCase ...@@ -14,7 +17,7 @@ abstract class ManagerTestCase extends TestCase
*/ */
protected $auth; protected $auth;
public function testCreateRoleAndPermission() public function testCreateRole()
{ {
$role = $this->auth->createRole('admin'); $role = $this->auth->createRole('admin');
$this->assertTrue($role instanceof Role); $this->assertTrue($role instanceof Role);
...@@ -57,174 +60,6 @@ abstract class ManagerTestCase extends TestCase ...@@ -57,174 +60,6 @@ abstract class ManagerTestCase extends TestCase
$this->auth->addChild($user, $changeName); $this->auth->addChild($user, $changeName);
$this->assertCount(1, $this->auth->getChildren($user->name)); $this->assertCount(1, $this->auth->getChildren($user->name));
} }
/*
public function testRemove()
{
}
public function testUpdate()
{
}
public function testCreateItem()
{
$type = Item::TYPE_TASK;
$name = 'editUser';
$description = 'edit a user';
$ruleName = 'isAuthor';
$data = [1, 2, 3];
$item = $this->auth->createItem($name, $type, $description, $ruleName, $data);
$this->assertTrue($item instanceof Item);
$this->assertEquals($item->type, $type);
$this->assertEquals($item->name, $name);
$this->assertEquals($item->description, $description);
$this->assertEquals($item->ruleName, $ruleName);
$this->assertEquals($item->data, $data);
// test shortcut
$name2 = 'createUser';
$item2 = $this->auth->createRole($name2, $description, $ruleName, $data);
$this->assertEquals($item2->type, Item::TYPE_ROLE);
// test adding an item with the same name
$this->setExpectedException('\yii\base\Exception');
$this->auth->createItem($name, $type, $description, $ruleName, $data);
}
public function testGetItem()
{
$this->assertTrue($this->auth->getItem('readPost') instanceof Item);
$this->assertTrue($this->auth->getItem('reader') instanceof Item);
$this->assertNull($this->auth->getItem('unknown'));
}
public function testRemoveItem()
{
$this->assertTrue($this->auth->getItem('updatePost') instanceof Item);
$this->assertTrue($this->auth->removeItem('updatePost'));
$this->assertNull($this->auth->getItem('updatePost'));
$this->assertFalse($this->auth->removeItem('updatePost'));
}
public function testChangeItemName()
{
$item = $this->auth->getItem('readPost');
$this->assertTrue($item instanceof Item);
$this->assertTrue($this->auth->hasItemChild('reader', 'readPost'));
$item->name = 'readPost2';
$item->save();
$this->assertNull($this->auth->getItem('readPost'));
$this->assertEquals($this->auth->getItem('readPost2'), $item);
$this->assertFalse($this->auth->hasItemChild('reader', 'readPost'));
$this->assertTrue($this->auth->hasItemChild('reader', 'readPost2'));
}
public function testAddItemChild()
{
$this->auth->addItemChild('createPost', 'updatePost');
// test adding upper level item to lower one
$this->setExpectedException('\yii\base\Exception');
$this->auth->addItemChild('readPost', 'reader');
}
public function testAddItemChild2()
{
// test adding inexistent items
$this->setExpectedException('\yii\base\Exception');
$this->assertFalse($this->auth->addItemChild('createPost2', 'updatePost'));
}
public function testRemoveItemChild()
{
$this->assertTrue($this->auth->hasItemChild('reader', 'readPost'));
$this->assertTrue($this->auth->removeItemChild('reader', 'readPost'));
$this->assertFalse($this->auth->hasItemChild('reader', 'readPost'));
$this->assertFalse($this->auth->removeItemChild('reader', 'readPost'));
}
public function testGetItemChildren()
{
$this->assertEquals([], $this->auth->getItemChildren('readPost'));
$children = $this->auth->getItemChildren('author');
$this->assertEquals(3, count($children));
$this->assertTrue(reset($children) instanceof Item);
}
public function testAssign()
{
$auth = $this->auth->assign('new user', 'createPost', 'isAuthor', 'data');
$this->assertTrue($auth instanceof Assignment);
$this->assertEquals($auth->userId, 'new user');
$this->assertEquals($auth->itemName, 'createPost');
$this->assertEquals($auth->ruleName, 'isAuthor');
$this->assertEquals($auth->data, 'data');
$this->setExpectedException('\yii\base\Exception');
$this->auth->assign('new user', 'createPost2', 'rule', 'data');
}
public function testRevoke()
{
$this->assertTrue($this->auth->isAssigned('author B', 'author'));
$auth = $this->auth->getAssignment('author B', 'author');
$this->assertTrue($auth instanceof Assignment);
$this->assertTrue($this->auth->revoke('author B', 'author'));
$this->assertFalse($this->auth->isAssigned('author B', 'author'));
$this->assertFalse($this->auth->revoke('author B', 'author'));
}
public function testRevokeAll()
{
$this->assertTrue($this->auth->revokeAll('reader E'));
$this->assertFalse($this->auth->isAssigned('reader E', 'reader'));
}
public function testGetAssignments()
{
$this->auth->assign('author B', 'deletePost');
$auths = $this->auth->getAssignments('author B');
$this->assertEquals(2, count($auths));
$this->assertTrue(reset($auths) instanceof Assignment);
}
public function testGetItems()
{
$this->assertEquals(count($this->auth->getRoles()), 4);
$this->assertEquals(count($this->auth->getOperations()), 4);
$this->assertEquals(count($this->auth->getTasks()), 1);
$this->assertEquals(count($this->auth->getItems()), 9);
$this->assertEquals(count($this->auth->getItems('author B', null)), 1);
$this->assertEquals(count($this->auth->getItems('author C', null)), 0);
$this->assertEquals(count($this->auth->getItems('author B', Item::TYPE_ROLE)), 1);
$this->assertEquals(count($this->auth->getItems('author B', Item::TYPE_OPERATION)), 0);
}
public function testClearAll()
{
$this->auth->clearAll();
$this->assertEquals(count($this->auth->getRoles()), 0);
$this->assertEquals(count($this->auth->getOperations()), 0);
$this->assertEquals(count($this->auth->getTasks()), 0);
$this->assertEquals(count($this->auth->getItems()), 0);
$this->assertEquals(count($this->auth->getAssignments('author B')), 0);
}
public function testClearAssignments()
{
$this->auth->clearAssignments();
$this->assertEquals(count($this->auth->getAssignments('author B')), 0);
}
public function testDetectLoop()
{
$this->setExpectedException('\yii\base\Exception');
$this->auth->addItemChild('readPost', 'readPost');
}
*/
public function testGetRule() public function testGetRule()
{ {
......
...@@ -3,38 +3,74 @@ ...@@ -3,38 +3,74 @@
namespace yiiunit\framework\rbac; namespace yiiunit\framework\rbac;
use Yii; use Yii;
use yii\rbac\PhpManager;
/** /**
* @group rbac * @group rbac
* @property \yii\rbac\PhpManager $auth * @property ExposedPhpManager $auth
*/ */
class PhpManagerTest extends ManagerTestCase class PhpManagerTest extends ManagerTestCase
{ {
protected function getItemFile()
{
return Yii::$app->getRuntimePath() . '/rbac-items.php';
}
protected function getAssignmentFile()
{
return Yii::$app->getRuntimePath() . '/rbac-assignments.php';
}
protected function getRuleFile()
{
return Yii::$app->getRuntimePath() . '/rbac-rules.php';
}
protected function removeDataFiles()
{
@unlink($this->getItemFile());
@unlink($this->getAssignmentFile());
@unlink($this->getRuleFile());
}
protected function createManager()
{
return new ExposedPhpManager([
'itemFile' => $this->getItemFile(),
'assignmentFile' => $this->getAssignmentFile(),
'ruleFile' => $this->getRuleFile(),
]);
}
protected function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();
$this->mockApplication(); $this->mockApplication();
$authFile = Yii::$app->getRuntimePath() . '/rbac.php'; $this->removeDataFiles();
@unlink($authFile); $this->auth = $this->createManager();
$this->auth = new PhpManager();
$this->auth->authFile = $authFile;
$this->auth->init();
} }
protected function tearDown() protected function tearDown()
{ {
$this->removeDataFiles();
parent::tearDown(); parent::tearDown();
@unlink($this->auth->authFile);
} }
public function testSaveLoad() public function testSaveLoad()
{ {
$this->prepareData(); $this->prepareData();
$items = $this->auth->items;
$children = $this->auth->children;
$assignments = $this->auth->assignments;
$rules = $this->auth->rules;
$this->auth->save(); $this->auth->save();
$this->auth->removeAll();
$this->auth = $this->createManager();
$this->auth->load(); $this->auth->load();
// TODO : Check if loaded and saved data are the same.
}
$this->assertEquals($items, $this->auth->items);
$this->assertEquals($children, $this->auth->children);
$this->assertEquals($assignments, $this->auth->assignments);
$this->assertEquals($rules, $this->auth->rules);
}
} }
\ No newline at end of file
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