Browse Source

Merge branch 'master' into bootstrap

* master: (33 commits)
  Skipped ApcCacheTest expire
  MS Windows EOLs → UNIX EOLs.
  Build command path fix.
  refactored RBAC.
  Added usage example of Theme.
  Added default class for theme.
  Fixes issue #172: Implemented new usage of widgets.
  code style fix of YiiRequirementChecker.php Renamed yiirequirements.php to requirements.php
  "YiiRequirementChecker" console view has been reworked to display requirements by blocks and in brief for the successful ones.
  Changed framework in dir structure to yii
  requirements.php typo fix.
  "requirements.php" has been added to "bootstrap" application.
  Doc comments and error messages for "YiiRequirementChecker" have been adjusted.
  Doc comments for "YiiRequirementChecker" have been updated.
  PHP version fallback for "YiiRequirementChecker" has been added.
  "YiiRequirementChecker::check()" has been updated allowing to accept filename for the requirements. Yii core requirements file has been composed.
  Check helper methods have been added to "YiiRequirementChecker".
  Web view for "YiiRequirementChecker" has been created.
  "YiiRequirementChecker::render()" has been implemented, console view has been created.
  added newline to end of header and body blocks in View
  ...
tags/2.0.0-beta
Antonio Ramirez 12 years ago
parent
commit
d812cbc6af
  1. 96
      apps/bootstrap/protected/requirements.php
  2. 8
      apps/bootstrap/protected/views/layouts/main.php
  3. 16
      apps/bootstrap/protected/views/site/contact.php
  4. 4
      apps/bootstrap/protected/views/site/login.php
  5. 2
      build/build
  6. 24
      docs/guide/upgrade-from-v1.md
  7. 2
      readme.md
  8. 9
      tests/unit/framework/caching/ApcCacheTest.php
  9. 104
      tests/unit/framework/caching/CacheTest.php
  10. 14
      tests/unit/framework/caching/DbCacheTest.php
  11. 12
      tests/unit/framework/caching/FileCacheTest.php
  12. 2
      tests/unit/framework/caching/MemCachedTest.php
  13. 1
      tests/unit/framework/rbac/ManagerTestBase.php
  14. 195
      tests/unit/framework/requirements/YiiRequirementCheckerTest.php
  15. 17
      yii/base/Theme.php
  16. 117
      yii/base/View.php
  17. 87
      yii/base/Widget.php
  18. 2
      yii/caching/ApcCache.php
  19. 2
      yii/caching/Cache.php
  20. 2
      yii/caching/DbCache.php
  21. 2
      yii/caching/DummyCache.php
  22. 2
      yii/caching/FileCache.php
  23. 7
      yii/caching/MemCache.php
  24. 2
      yii/caching/WinCache.php
  25. 2
      yii/caching/XCache.php
  26. 2
      yii/caching/ZendDataCache.php
  27. 81
      yii/rbac/Assignment.php
  28. 181
      yii/rbac/DbManager.php
  29. 158
      yii/rbac/Item.php
  30. 2
      yii/rbac/Manager.php
  31. 60
      yii/rbac/PhpManager.php
  32. 7
      yii/rbac/schema-mssql.sql
  33. 7
      yii/rbac/schema-mysql.sql
  34. 7
      yii/rbac/schema-oci.sql
  35. 7
      yii/rbac/schema-pgsql.sql
  36. 7
      yii/rbac/schema-sqlite.sql
  37. 392
      yii/requirements/YiiRequirementChecker.php
  38. 39
      yii/requirements/requirements.php
  39. 36
      yii/requirements/views/console/index.php
  40. 93
      yii/requirements/views/web/css.php
  41. 82
      yii/requirements/views/web/index.php
  42. 2
      yii/web/Pagination.php
  43. 12
      yii/widgets/Breadcrumbs.php
  44. 5
      yii/widgets/Menu.php

96
apps/bootstrap/protected/requirements.php

@ -0,0 +1,96 @@
<?php
/**
* Application requirement checker script.
*
* In order to run this script use the following console command:
* php requirements.php
*
* In order to run this script from the web, you should copy it to the web root.
* If you are using Linux you can create a hard link instead, using the following command:
* ln requirements.php ../requirements.php
*/
// you may need to adjust this path to the correct Yii framework path
$frameworkPath = dirname(__FILE__) . '/../../../yii';
require_once($frameworkPath . '/requirements/YiiRequirementChecker.php');
$requirementsChecker = new YiiRequirementChecker();
/**
* Adjust requirements according to your application specifics.
*/
$requirements = array(
// Database :
array(
'name' => 'PDO extension',
'mandatory' => true,
'condition' => extension_loaded('pdo'),
'by' => 'All <a href="http://www.yiiframework.com/doc/api/#system.db">DB-related classes</a>',
),
array(
'name' => 'PDO SQLite extension',
'mandatory' => false,
'condition' => extension_loaded('pdo_sqlite'),
'by' => 'All <a href="http://www.yiiframework.com/doc/api/#system.db">DB-related classes</a>',
'memo' => 'Required for SQLite database.',
),
array(
'name' => 'PDO MySQL extension',
'mandatory' => false,
'condition' => extension_loaded('pdo_mysql'),
'by' => 'All <a href="http://www.yiiframework.com/doc/api/#system.db">DB-related classes</a>',
'memo' => 'Required for MySQL database.',
),
// Cache :
array(
'name' => 'Memcache extension',
'mandatory' => false,
'condition' => extension_loaded('memcache') || extension_loaded('memcached'),
'by' => '<a href="http://www.yiiframework.com/doc/api/CMemCache">CMemCache</a>',
'memo' => extension_loaded('memcached') ? 'To use memcached set <a href="http://www.yiiframework.com/doc/api/CMemCache#useMemcached-detail">CMemCache::useMemcached</a> to <code>true</code>.' : ''
),
array(
'name' => 'APC extension',
'mandatory' => false,
'condition' => extension_loaded('apc') || extension_loaded('apc'),
'by' => '<a href="http://www.yiiframework.com/doc/api/CApcCache">CApcCache</a>',
),
// Additional PHP extensions :
array(
'name' => 'Mcrypt extension',
'mandatory' => false,
'condition' => extension_loaded('mcrypt'),
'by' => '<a href="http://www.yiiframework.com/doc/api/CSecurityManager">CSecurityManager</a>',
'memo' => 'Required by encrypt and decrypt methods.'
),
// PHP ini :
'phpSafeMode' => array(
'name' => 'PHP safe mode',
'mandatory' => false,
'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"),
'by' => 'File uploading and console command execution',
'memo' => '"safe_mode" should be disabled at php.ini',
),
'phpExposePhp' => array(
'name' => 'Expose PHP',
'mandatory' => false,
'condition' => $requirementsChecker->checkPhpIniOff("expose_php"),
'by' => 'Security reasons',
'memo' => '"expose_php" should be disabled at php.ini',
),
'phpAllowUrlInclude' => array(
'name' => 'PHP allow url include',
'mandatory' => false,
'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"),
'by' => 'Security reasons',
'memo' => '"allow_url_include" should be disabled at php.ini',
),
'phpSmtp' => array(
'name' => 'PHP mail SMTP',
'mandatory' => false,
'condition' => strlen(ini_get('SMTP'))>0,
'by' => 'Email sending',
'memo' => 'PHP mail SMTP server required',
),
);
$requirementsChecker->checkYii()->check($requirements)->render();

8
apps/bootstrap/protected/views/layouts/main.php

@ -1,6 +1,8 @@
<?php <?php
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\Menu; use yii\widgets\Menu;
use yii\widgets\Breadcrumbs;
use yii\debug\Toolbar;
/** /**
* @var $this \yii\base\View * @var $this \yii\base\View
@ -25,7 +27,7 @@ $this->registerAssetBundle('app');
<div class="navbar"> <div class="navbar">
<div class="navbar-inner"> <div class="navbar-inner">
<div class="container"> <div class="container">
<?php $this->widget(Menu::className(), array( <?php echo Menu::widget($this, array(
'options' => array('class' => 'nav'), 'options' => array('class' => 'nav'),
'items' => array( 'items' => array(
array('label' => 'Home', 'url' => array('/site/index')), array('label' => 'Home', 'url' => array('/site/index')),
@ -42,7 +44,7 @@ $this->registerAssetBundle('app');
<!-- /.navbar --> <!-- /.navbar -->
</div> </div>
<?php $this->widget('yii\widgets\Breadcrumbs', array( <?php echo Breadcrumbs::widget($this, array(
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
)); ?> )); ?>
<?php echo $content; ?> <?php echo $content; ?>
@ -58,7 +60,7 @@ $this->registerAssetBundle('app');
</div> </div>
<?php $this->endBody(); ?> <?php $this->endBody(); ?>
</div> </div>
<?php $this->widget('yii\debug\Toolbar'); ?> <?php echo Toolbar::widget($this); ?>
</body> </body>
</html> </html>
<?php $this->endPage(); ?> <?php $this->endPage(); ?>

16
apps/bootstrap/protected/views/site/contact.php

@ -23,7 +23,7 @@ $this->params['breadcrumbs'][] = $this->title;
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
</p> </p>
<?php $form = $this->beginWidget(ActiveForm::className(), array( <?php $form = ActiveForm::begin($this, array(
'options' => array('class' => 'form-horizontal'), 'options' => array('class' => 'form-horizontal'),
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')), 'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
)); ?> )); ?>
@ -33,14 +33,14 @@ $this->params['breadcrumbs'][] = $this->title;
<?php echo $form->field($model, 'body')->textArea(array('rows' => 6)); ?> <?php echo $form->field($model, 'body')->textArea(array('rows' => 6)); ?>
<?php <?php
$field = $form->field($model, 'verifyCode'); $field = $form->field($model, 'verifyCode');
echo $field->begin(); echo $field->begin()
echo $field->label(); . $field->label()
$this->widget(Captcha::className()); . Captcha::widget($this)
echo Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium')); . Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium'))
echo $field->error(); . $field->error()
echo $field->end(); . $field->end();
?> ?>
<div class="form-actions"> <div class="form-actions">
<?php echo Html::submitButton('Submit', null, null, array('class' => 'btn btn-primary')); ?> <?php echo Html::submitButton('Submit', null, null, array('class' => 'btn btn-primary')); ?>
</div> </div>
<?php $this->endWidget(); ?> <?php ActiveForm::end(); ?>

4
apps/bootstrap/protected/views/site/login.php

@ -14,11 +14,11 @@ $this->params['breadcrumbs'][] = $this->title;
<p>Please fill out the following fields to login:</p> <p>Please fill out the following fields to login:</p>
<?php $form = $this->beginWidget(ActiveForm::className(), array('options' => array('class' => 'form-horizontal'))); ?> <?php $form = ActiveForm::begin($this, array('options' => array('class' => 'form-horizontal'))); ?>
<?php echo $form->field($model, 'username')->textInput(); ?> <?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?> <?php echo $form->field($model, 'password')->passwordInput(); ?>
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?> <?php echo $form->field($model, 'rememberMe')->checkbox(); ?>
<div class="form-actions"> <div class="form-actions">
<?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?> <?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?>
</div> </div>
<?php $this->endWidget(); ?> <?php ActiveForm::end(); ?>

2
build/build

@ -11,7 +11,7 @@
// fcgi doesn't have STDIN defined by default // fcgi doesn't have STDIN defined by default
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
require(__DIR__ . '/../framework/Yii.php'); require(__DIR__ . '/../yii/Yii.php');
$id = 'yiic-build'; $id = 'yiic-build';
$basePath = __DIR__; $basePath = __DIR__;

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

@ -209,6 +209,26 @@ if (isset($_POST['Post'])) {
``` ```
Widgets
-------
Using a widget is more straightforward in 2.0. You mainly use the `begin()`, `end()` and `widget()`
methods of the `Widget` class. For example,
```php
// $this refers to the View object
// Note that you have to "echo" the result to display it
echo \yii\widgets\Menu::widget($this, array('items' => $items));
// $this refers to the View object
$form = \yii\widgets\ActiveForm::begin($this);
... form inputs here ...
\yii\widgets\ActiveForm::end();
```
Previously in 1.1, you would have to enter the widget class names as strings via the `beginWidget()`,
`endWidget()` and `widget()` methods of `CBaseController`. The approach above gets better IDE support.
Themes Themes
------ ------
@ -309,13 +329,13 @@ is a container consisting of a label, an input, and an error message. It is repr
as an `ActiveField` object. Using fields, you can build a form more cleanly than before: as an `ActiveField` object. Using fields, you can build a form more cleanly than before:
```php ```php
<?php $form = $this->beginWidget('yii\widgets\ActiveForm'); ?> <?php $form = yii\widgets\ActiveForm::begin(); ?>
<?php echo $form->field($model, 'username')->textInput(); ?> <?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?> <?php echo $form->field($model, 'password')->passwordInput(); ?>
<div class="form-actions"> <div class="form-actions">
<?php echo Html::submitButton('Login'); ?> <?php echo Html::submitButton('Login'); ?>
</div> </div>
<?php $this->endWidget(); ?> <?php yii\widgets\ActiveForm::end(); ?>
``` ```

2
readme.md

@ -19,7 +19,7 @@ DIRECTORY STRUCTURE
bootstrap/ a simple app supporting user login and contact page bootstrap/ a simple app supporting user login and contact page
build/ internally used build tools build/ internally used build tools
docs/ documentation docs/ documentation
framework/ framework source files yii/ framework source files
tests/ tests of the core framework code tests/ tests of the core framework code

9
tests/unit/framework/caching/ApcCacheTest.php

@ -21,9 +21,18 @@ class ApcCacheTest extends CacheTest
$this->markTestSkipped("APC cli is not enabled. Skipping."); $this->markTestSkipped("APC cli is not enabled. Skipping.");
} }
if(!ini_get("apc.enabled") || !ini_get("apc.enable_cli")) {
$this->markTestSkipped("APC is installed but not enabled. Skipping.");
}
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new ApcCache(); $this->_cacheInstance = new ApcCache();
} }
return $this->_cacheInstance; return $this->_cacheInstance;
} }
public function testExpire()
{
$this->markTestSkipped("APC keys are expiring only on the next request.");
}
} }

104
tests/unit/framework/caching/CacheTest.php

@ -1,5 +1,17 @@
<?php <?php
namespace yii\caching;
/**
* Mock for the time() function for caching classes
* @return int
*/
function time() {
return \yiiunit\framework\caching\CacheTest::$time ?: \time();
}
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yiiunit\TestCase; use yiiunit\TestCase;
use yii\caching\Cache; use yii\caching\Cache;
@ -9,6 +21,12 @@ use yii\caching\Cache;
abstract class CacheTest extends TestCase abstract class CacheTest extends TestCase
{ {
/** /**
* @var int virtual time to be returned by mocked time() function.
* Null means normal time() behavior.
*/
public static $time;
/**
* @return Cache * @return Cache
*/ */
abstract protected function getCacheInstance(); abstract protected function getCacheInstance();
@ -19,18 +37,50 @@ abstract class CacheTest extends TestCase
$this->mockApplication(); $this->mockApplication();
} }
protected function tearDown()
{
static::$time = null;
}
/**
* @return Cache
*/
public function prepare()
{
$cache = $this->getCacheInstance();
$cache->flush();
$cache->set('string_test', 'string_test');
$cache->set('number_test', 42);
$cache->set('array_test', array('array_test' => 'array_test'));
$cache['arrayaccess_test'] = new \stdClass();
return $cache;
}
/**
* default value of cache prefix is application id
*/
public function testKeyPrefix()
{
$cache = $this->getCacheInstance();
$this->assertNotNull(\Yii::$app->id);
$this->assertEquals(\Yii::$app->id, $cache->keyPrefix);
}
public function testSet() public function testSet()
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$this->assertTrue($cache->set('string_test', 'string_test')); $this->assertTrue($cache->set('string_test', 'string_test'));
$this->assertTrue($cache->set('number_test', 42)); $this->assertTrue($cache->set('number_test', 42));
$this->assertTrue($cache->set('array_test', array('array_test' => 'array_test'))); $this->assertTrue($cache->set('array_test', array('array_test' => 'array_test')));
$cache['arrayaccess_test'] = new \stdClass();
} }
public function testGet() public function testGet()
{ {
$cache = $this->getCacheInstance(); $cache = $this->prepare();
$this->assertEquals('string_test', $cache->get('string_test')); $this->assertEquals('string_test', $cache->get('string_test'));
$this->assertEquals(42, $cache->get('number_test')); $this->assertEquals(42, $cache->get('number_test'));
@ -38,51 +88,83 @@ abstract class CacheTest extends TestCase
$array = $cache->get('array_test'); $array = $cache->get('array_test');
$this->assertArrayHasKey('array_test', $array); $this->assertArrayHasKey('array_test', $array);
$this->assertEquals('array_test', $array['array_test']); $this->assertEquals('array_test', $array['array_test']);
}
public function testArrayAccess()
{
$cache = $this->getCacheInstance();
$cache['arrayaccess_test'] = new \stdClass();
$this->assertInstanceOf('stdClass', $cache['arrayaccess_test']); $this->assertInstanceOf('stdClass', $cache['arrayaccess_test']);
} }
public function testMget() public function testGetNonExistent()
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$this->assertFalse($cache->get('non_existent_key'));
}
public function testStoreSpecialValues()
{
$cache = $this->getCacheInstance();
$this->assertTrue($cache->set('null_value', null));
$this->assertNull($cache->get('null_value'));
$this->assertTrue($cache->set('bool_value', true));
$this->assertTrue($cache->get('bool_value'));
}
public function testMget()
{
$cache = $this->prepare();
$this->assertEquals(array('string_test' => 'string_test', 'number_test' => 42), $cache->mget(array('string_test', 'number_test'))); $this->assertEquals(array('string_test' => 'string_test', 'number_test' => 42), $cache->mget(array('string_test', 'number_test')));
// ensure that order does not matter
$this->assertEquals(array('number_test' => 42, 'string_test' => 'string_test'), $cache->mget(array('number_test', 'string_test')));
$this->assertEquals(array('number_test' => 42, 'non_existent_key' => null), $cache->mget(array('number_test', 'non_existent_key')));
} }
public function testExpire() public function testExpire()
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$this->assertTrue($cache->set('expire_test', 'expire_test', 2)); $this->assertTrue($cache->set('expire_test', 'expire_test', 2));
sleep(1); sleep(1);
$this->assertEquals('expire_test', $cache->get('expire_test')); $this->assertEquals('expire_test', $cache->get('expire_test'));
sleep(2); // wait a bit more than 2 sec to avoid random test failure
$this->assertEquals(false, $cache->get('expire_test')); usleep(2500000);
$this->assertFalse($cache->get('expire_test'));
} }
public function testAdd() public function testAdd()
{ {
$cache = $this->getCacheInstance(); $cache = $this->prepare();
// should not change existing keys // should not change existing keys
$this->assertFalse($cache->add('number_test', 13)); $this->assertFalse($cache->add('number_test', 13));
$this->assertEquals(42, $cache->get('number_test')); $this->assertEquals(42, $cache->get('number_test'));
// should store data is it's not there yet // should store data if it's not there yet
$this->assertFalse($cache->get('add_test'));
$this->assertTrue($cache->add('add_test', 13)); $this->assertTrue($cache->add('add_test', 13));
$this->assertEquals(13, $cache->get('add_test')); $this->assertEquals(13, $cache->get('add_test'));
} }
public function testDelete() public function testDelete()
{ {
$cache = $this->getCacheInstance(); $cache = $this->prepare();
$this->assertNotNull($cache->get('number_test'));
$this->assertTrue($cache->delete('number_test')); $this->assertTrue($cache->delete('number_test'));
$this->assertEquals(null, $cache->get('number_test')); $this->assertFalse($cache->get('number_test'));
} }
public function testFlush() public function testFlush()
{ {
$cache = $this->getCacheInstance(); $cache = $this->prepare();
$this->assertTrue($cache->flush()); $this->assertTrue($cache->flush());
$this->assertEquals(null, $cache->get('add_test')); $this->assertFalse($cache->get('number_test'));
} }
} }

14
tests/unit/framework/caching/DbCacheTest.php

@ -1,5 +1,7 @@
<?php <?php
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\DbCache; use yii\caching\DbCache;
use yiiunit\TestCase; use yiiunit\TestCase;
@ -70,4 +72,16 @@ class DbCacheTest extends CacheTest
} }
return $this->_cacheInstance; return $this->_cacheInstance;
} }
public function testExpire()
{
$cache = $this->getCacheInstance();
static::$time = \time();
$this->assertTrue($cache->set('expire_test', 'expire_test', 2));
static::$time++;
$this->assertEquals('expire_test', $cache->get('expire_test'));
static::$time++;
$this->assertFalse($cache->get('expire_test'));
}
} }

12
tests/unit/framework/caching/FileCacheTest.php

@ -22,4 +22,16 @@ class FileCacheTest extends CacheTest
} }
return $this->_cacheInstance; return $this->_cacheInstance;
} }
public function testExpire()
{
$cache = $this->getCacheInstance();
static::$time = \time();
$this->assertTrue($cache->set('expire_test', 'expire_test', 2));
static::$time++;
$this->assertEquals('expire_test', $cache->get('expire_test'));
static::$time++;
$this->assertFalse($cache->get('expire_test'));
}
} }

2
tests/unit/framework/caching/MemCachedTest.php

@ -4,7 +4,7 @@ use yii\caching\MemCache;
use yiiunit\TestCase; use yiiunit\TestCase;
/** /**
* Class for testing memcache cache backend * Class for testing memcached cache backend
*/ */
class MemCachedTest extends CacheTest class MemCachedTest extends CacheTest
{ {

1
tests/unit/framework/rbac/ManagerTestBase.php

@ -57,6 +57,7 @@ abstract class ManagerTestBase extends TestCase
$this->assertTrue($item instanceof Item); $this->assertTrue($item instanceof Item);
$this->assertTrue($this->auth->hasItemChild('reader', 'readPost')); $this->assertTrue($this->auth->hasItemChild('reader', 'readPost'));
$item->name = 'readPost2'; $item->name = 'readPost2';
$item->save();
$this->assertNull($this->auth->getItem('readPost')); $this->assertNull($this->auth->getItem('readPost'));
$this->assertEquals($this->auth->getItem('readPost2'), $item); $this->assertEquals($this->auth->getItem('readPost2'), $item);
$this->assertFalse($this->auth->hasItemChild('reader', 'readPost')); $this->assertFalse($this->auth->hasItemChild('reader', 'readPost'));

195
tests/unit/framework/requirements/YiiRequirementCheckerTest.php

@ -0,0 +1,195 @@
<?php
require_once(realpath(__DIR__.'/../../../../yii/requirements/YiiRequirementChecker.php'));
use yiiunit\TestCase;
/**
* Test case for [[YiiRequirementChecker]].
* @see YiiRequirementChecker
*/
class YiiRequirementCheckerTest extends TestCase
{
public function testCheck()
{
$requirementsChecker = new YiiRequirementChecker();
$requirements = array(
'requirementPass' => array(
'name' => 'Requirement 1',
'mandatory' => true,
'condition' => true,
'by' => 'Requirement 1',
'memo' => 'Requirement 1',
),
'requirementError' => array(
'name' => 'Requirement 2',
'mandatory' => true,
'condition' => false,
'by' => 'Requirement 2',
'memo' => 'Requirement 2',
),
'requirementWarning' => array(
'name' => 'Requirement 3',
'mandatory' => false,
'condition' => false,
'by' => 'Requirement 3',
'memo' => 'Requirement 3',
),
);
$checkResult = $requirementsChecker->check($requirements)->getResult();
$summary = $checkResult['summary'];
$this->assertEquals(count($requirements), $summary['total'], 'Wrong summary total!');
$this->assertEquals(1, $summary['errors'], 'Wrong summary errors!');
$this->assertEquals(1, $summary['warnings'], 'Wrong summary warnings!');
$checkedRequirements = $checkResult['requirements'];
$requirementsKeys = array_flip(array_keys($requirements));
$this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!');
$this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!');
$this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!');
$this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementWarning']]['error'], 'Error requirement has an error!');
$this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementWarning']]['warning'], 'Error requirement has no warning!');
}
/**
* @depends testCheck
*/
public function testCheckEval() {
$requirementsChecker = new YiiRequirementChecker();
$requirements = array(
'requirementPass' => array(
'name' => 'Requirement 1',
'mandatory' => true,
'condition' => 'eval:2>1',
'by' => 'Requirement 1',
'memo' => 'Requirement 1',
),
'requirementError' => array(
'name' => 'Requirement 2',
'mandatory' => true,
'condition' => 'eval:2<1',
'by' => 'Requirement 2',
'memo' => 'Requirement 2',
),
);
$checkResult = $requirementsChecker->check($requirements)->getResult();
$checkedRequirements = $checkResult['requirements'];
$requirementsKeys = array_flip(array_keys($requirements));
$this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!');
$this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!');
$this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!');
}
/**
* @depends testCheck
*/
public function testCheckChained()
{
$requirementsChecker = new YiiRequirementChecker();
$requirements1 = array(
array(
'name' => 'Requirement 1',
'mandatory' => true,
'condition' => true,
'by' => 'Requirement 1',
'memo' => 'Requirement 1',
),
);
$requirements2 = array(
array(
'name' => 'Requirement 2',
'mandatory' => true,
'condition' => true,
'by' => 'Requirement 2',
'memo' => 'Requirement 2',
),
);
$checkResult = $requirementsChecker->check($requirements1)->check($requirements2)->getResult();
$mergedRequirements = array_merge($requirements1, $requirements2);
$this->assertEquals(count($mergedRequirements), $checkResult['summary']['total'], 'Wrong total checks count!');
foreach ($mergedRequirements as $key => $mergedRequirement) {
$this->assertEquals($mergedRequirement['name'], $checkResult['requirements'][$key]['name'], 'Wrong requirements list!');
}
}
public function testCheckPhpExtensionVersion()
{
$requirementsChecker = new YiiRequirementChecker();
$this->assertFalse($requirementsChecker->checkPhpExtensionVersion('some_unexisting_php_extension', '0.1'), 'No fail while checking unexisting extension!');
$this->assertTrue($requirementsChecker->checkPhpExtensionVersion('pdo', '1.0'), 'Unable to check PDO version!');
}
/**
* Data provider for [[testGetByteSize()]].
* @return array
*/
public function dataProviderGetByteSize()
{
return array(
array('456', 456),
array('5K', 5*1024),
array('16KB', 16*1024),
array('4M', 4*1024*1024),
array('14MB', 14*1024*1024),
array('7G', 7*1024*1024*1024),
array('12GB', 12*1024*1024*1024),
);
}
/**
* @dataProvider dataProviderGetByteSize
*
* @param string $verboseValue verbose value.
* @param integer $expectedByteSize expected byte size.
*/
public function testGetByteSize($verboseValue, $expectedByteSize)
{
$requirementsChecker = new YiiRequirementChecker();
$this->assertEquals($expectedByteSize, $requirementsChecker->getByteSize($verboseValue), "Wrong byte size for '{$verboseValue}'!");
}
/**
* Data provider for [[testCompareByteSize()]]
* @return array
*/
public function dataProviderCompareByteSize()
{
return array(
array('2M', '2K', '>', true),
array('2M', '2K', '>=', true),
array('1K', '1024', '==', true),
array('10M', '11M', '<', true),
array('10M', '11M', '<=', true),
);
}
/**
* @depends testGetByteSize
* @dataProvider dataProviderCompareByteSize
*
* @param string $a first value.
* @param string $b second value.
* @param string $compare comparison.
* @param boolean $expectedComparisonResult expected comparison result.
*/
public function testCompareByteSize($a, $b, $compare, $expectedComparisonResult)
{
$requirementsChecker = new YiiRequirementChecker();
$this->assertEquals($expectedComparisonResult, $requirementsChecker->compareByteSize($a, $b, $compare), "Wrong compare '{$a}{$compare}{$b}'");
}
}

17
yii/base/Theme.php

@ -25,7 +25,22 @@ use yii\helpers\FileHelper;
* then the themed version for a view file `/www/views/site/index.php` will be * then the themed version for a view file `/www/views/site/index.php` will be
* `/www/themes/basic/site/index.php`. * `/www/themes/basic/site/index.php`.
* *
* @property string $baseUrl the base URL for this theme. This is mainly used by [[getUrl()]]. * To use a theme, you should configure the [[View::theme|theme]] property of the "view" application
* component like the following:
*
* ~~~
* 'view' => array(
* 'theme' => array(
* 'basePath' => '@wwwroot/themes/basic',
* 'baseUrl' => '@www/themes/basic',
* ),
* ),
* ~~~
*
* The above configuration specifies a theme located under the "themes/basic" directory of the Web folder
* that contains the entry script of the application. If your theme is designed to handle modules,
* you may configure the [[pathMap]] property like described above.
*
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0

117
yii/base/View.php

@ -11,6 +11,9 @@ use Yii;
use yii\base\Application; use yii\base\Application;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\Block;
use yii\widgets\ContentDecorator;
use yii\widgets\FragmentCache;
/** /**
* View represents a view object in the MVC pattern. * View represents a view object in the MVC pattern.
@ -108,12 +111,6 @@ class View extends Component
*/ */
public $blocks; public $blocks;
/** /**
* @var Widget[] the widgets that are currently being rendered (not ended). This property
* is maintained by [[beginWidget()]] and [[endWidget()]] methods. Do not modify it directly.
* @internal
*/
public $widgetStack = array();
/**
* @var array a list of currently active fragment cache widgets. This property * @var array a list of currently active fragment cache widgets. This property
* is used internally to implement the content caching feature. Do not modify it directly. * is used internally to implement the content caching feature. Do not modify it directly.
* @internal * @internal
@ -174,6 +171,9 @@ class View extends Component
{ {
parent::init(); parent::init();
if (is_array($this->theme)) { if (is_array($this->theme)) {
if (!isset($this->theme['class'])) {
$this->theme['class'] = 'yii\base\Theme';
}
$this->theme = Yii::createObject($this->theme); $this->theme = Yii::createObject($this->theme);
} }
} }
@ -364,91 +364,16 @@ class View extends Component
} }
/** /**
* Creates a widget.
* This method will use [[Yii::createObject()]] to create the widget.
* @param string $class the widget class name or path alias
* @param array $properties the initial property values of the widget.
* @return Widget the newly created widget instance
*/
public function createWidget($class, $properties = array())
{
$properties['class'] = $class;
if (!isset($properties['view'])) {
$properties['view'] = $this;
}
return Yii::createObject($properties);
}
/**
* Creates and runs a widget.
* Compared with [[createWidget()]], this method does one more thing: it will
* run the widget after it is created.
* @param string $class the widget class name or path alias
* @param array $properties the initial property values of the widget.
* @param boolean $captureOutput whether to capture the output of the widget and return it as a string
* @return string|Widget if $captureOutput is true, the output of the widget will be returned;
* otherwise the widget object will be returned.
*/
public function widget($class, $properties = array(), $captureOutput = false)
{
if ($captureOutput) {
ob_start();
ob_implicit_flush(false);
$widget = $this->createWidget($class, $properties);
$widget->run();
return ob_get_clean();
} else {
$widget = $this->createWidget($class, $properties);
$widget->run();
return $widget;
}
}
/**
* Begins a widget.
* This method is similar to [[createWidget()]] except that it will expect a matching
* [[endWidget()]] call after this.
* @param string $class the widget class name or path alias
* @param array $properties the initial property values of the widget.
* @return Widget the widget instance
*/
public function beginWidget($class, $properties = array())
{
$widget = $this->createWidget($class, $properties);
$this->widgetStack[] = $widget;
return $widget;
}
/**
* Ends a widget.
* Note that the rendering result of the widget is directly echoed out.
* If you want to capture the rendering result of a widget, you may use
* [[createWidget()]] and [[Widget::run()]].
* @return Widget the widget instance
* @throws InvalidCallException if [[beginWidget()]] and [[endWidget()]] calls are not properly nested
*/
public function endWidget()
{
$widget = array_pop($this->widgetStack);
if ($widget instanceof Widget) {
$widget->run();
return $widget;
} else {
throw new InvalidCallException("Unmatched beginWidget() and endWidget() calls.");
}
}
/**
* Begins recording a block. * Begins recording a block.
* This method is a shortcut to beginning [[yii\widgets\Block]] * This method is a shortcut to beginning [[Block]]
* @param string $id the block ID. * @param string $id the block ID.
* @param boolean $renderInPlace whether to render the block content in place. * @param boolean $renderInPlace whether to render the block content in place.
* Defaults to false, meaning the captured block will not be displayed. * Defaults to false, meaning the captured block will not be displayed.
* @return \yii\widgets\Block the Block widget instance * @return Block the Block widget instance
*/ */
public function beginBlock($id, $renderInPlace = false) public function beginBlock($id, $renderInPlace = false)
{ {
return $this->beginWidget('yii\widgets\Block', array( return Block::begin($this, array(
'id' => $id, 'id' => $id,
'renderInPlace' => $renderInPlace, 'renderInPlace' => $renderInPlace,
)); ));
@ -459,7 +384,7 @@ class View extends Component
*/ */
public function endBlock() public function endBlock()
{ {
$this->endWidget(); Block::end();
} }
/** /**
@ -476,12 +401,12 @@ class View extends Component
* @param string $viewFile the view file that will be used to decorate the content enclosed by this widget. * @param string $viewFile the view file that will be used to decorate the content enclosed by this widget.
* This can be specified as either the view file path or path alias. * This can be specified as either the view file path or path alias.
* @param array $params the variables (name => value) to be extracted and made available in the decorative view. * @param array $params the variables (name => value) to be extracted and made available in the decorative view.
* @return \yii\widgets\ContentDecorator the ContentDecorator widget instance * @return ContentDecorator the ContentDecorator widget instance
* @see \yii\widgets\ContentDecorator * @see ContentDecorator
*/ */
public function beginContent($viewFile, $params = array()) public function beginContent($viewFile, $params = array())
{ {
return $this->beginWidget('yii\widgets\ContentDecorator', array( return ContentDecorator::begin($this, array(
'viewFile' => $viewFile, 'viewFile' => $viewFile,
'params' => $params, 'params' => $params,
)); ));
@ -492,7 +417,7 @@ class View extends Component
*/ */
public function endContent() public function endContent()
{ {
$this->endWidget(); ContentDecorator::end();
} }
/** /**
@ -510,15 +435,15 @@ class View extends Component
* ~~~ * ~~~
* *
* @param string $id a unique ID identifying the fragment to be cached. * @param string $id a unique ID identifying the fragment to be cached.
* @param array $properties initial property values for [[\yii\widgets\FragmentCache]] * @param array $properties initial property values for [[FragmentCache]]
* @return boolean whether you should generate the content for caching. * @return boolean whether you should generate the content for caching.
* False if the cached version is available. * False if the cached version is available.
*/ */
public function beginCache($id, $properties = array()) public function beginCache($id, $properties = array())
{ {
$properties['id'] = $id; $properties['id'] = $id;
/** @var $cache \yii\widgets\FragmentCache */ /** @var $cache FragmentCache */
$cache = $this->beginWidget('yii\widgets\FragmentCache', $properties); $cache = FragmentCache::begin($this, $properties);
if ($cache->getCachedContent() !== false) { if ($cache->getCachedContent() !== false) {
$this->endCache(); $this->endCache();
return false; return false;
@ -532,7 +457,7 @@ class View extends Component
*/ */
public function endCache() public function endCache()
{ {
$this->endWidget(); FragmentCache::end();
} }
@ -771,7 +696,7 @@ class View extends Component
if (!empty($this->js[self::POS_HEAD])) { if (!empty($this->js[self::POS_HEAD])) {
$lines[] = implode("\n", $this->js[self::POS_HEAD]); $lines[] = implode("\n", $this->js[self::POS_HEAD]);
} }
return implode("\n", $lines); return empty($lines) ? '' : implode("\n", $lines) . "\n";
} }
/** /**
@ -788,7 +713,7 @@ class View extends Component
if (!empty($this->js[self::POS_BEGIN])) { if (!empty($this->js[self::POS_BEGIN])) {
$lines[] = implode("\n", $this->js[self::POS_BEGIN]); $lines[] = implode("\n", $this->js[self::POS_BEGIN]);
} }
return implode("\n", $lines); return empty($lines) ? '' : implode("\n", $lines) . "\n";
} }
/** /**
@ -805,6 +730,6 @@ class View extends Component
if (!empty($this->js[self::POS_END])) { if (!empty($this->js[self::POS_END])) {
$lines[] = implode("\n", $this->js[self::POS_END]); $lines[] = implode("\n", $this->js[self::POS_END]);
} }
return implode("\n", $lines); return empty($lines) ? '' : implode("\n", $lines) . "\n";
} }
} }

87
yii/base/Widget.php

@ -8,7 +8,6 @@
namespace yii\base; namespace yii\base;
use Yii; use Yii;
use yii\helpers\FileHelper;
/** /**
* Widget is the base class for widgets. * Widget is the base class for widgets.
@ -19,9 +18,9 @@ use yii\helpers\FileHelper;
class Widget extends Component class Widget extends Component
{ {
/** /**
* @var View the view object that is used to create this widget. * @var View the view object that this widget is associated with.
* This property is automatically set by [[View::createWidget()]]. * The widget will use this view object to register any needed assets.
* This property is required by [[render()]] and [[renderFile()]]. * This property is also required by [[render()]] and [[renderFile()]].
*/ */
public $view; public $view;
/** /**
@ -29,9 +28,85 @@ class Widget extends Component
*/ */
private $_id; private $_id;
/** /**
* @var integer a counter used to generate IDs for widgets. * @var integer a counter used to generate [[id]] for widgets.
* @internal
*/ */
private static $_counter = 0; public static $_counter = 0;
/**
* @var Widget[] the widgets that are currently being rendered (not ended). This property
* is maintained by [[begin()]] and [[end()]] methods.
* @internal
*/
public static $_stack = array();
/**
* Constructor.
* @param View $view the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* It is also required by [[render()]] and [[renderFile()]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($view, $config = array())
{
$this->view = $view;
parent::__construct($config);
}
/**
* Begins a widget.
* This method creates an instance of the calling class. It will apply the configuration
* to the created instance. A matching [[end()]] call should be called later.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties
* @return Widget the newly created widget instance
*/
public static function begin($view, $config = array())
{
$config['class'] = get_called_class();
/** @var Widget $widget */
$widget = Yii::createObject($config, $view);
self::$_stack[] = $widget;
return $widget;
}
/**
* Ends a widget.
* Note that the rendering result of the widget is directly echoed out.
* @return Widget the widget instance that is ended.
* @throws InvalidCallException if [[begin()]] and [[end()]] calls are not properly nested
*/
public static function end()
{
if (!empty(self::$_stack)) {
$widget = array_pop(self::$_stack);
if (get_class($widget) === get_called_class()) {
$widget->run();
return $widget;
} else {
throw new InvalidCallException("Expecting end() of " . get_class($widget) . ", found " . get_called_class());
}
} else {
throw new InvalidCallException("Unexpected " . get_called_class() . '::end() call. A matching begin() is not found.');
}
}
/**
* Creates a widget instance and runs it.
* The widget rendering result is returned by this method.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties
* @return string the rendering result of the widget.
*/
public static function widget($view, $config = array())
{
ob_start();
ob_implicit_flush(false);
/** @var Widget $widget */
$config['class'] = get_called_class();
$widget = Yii::createObject($config, $view);
$widget->run();
return ob_get_clean();
}
/** /**
* Returns the ID of the widget. * Returns the ID of the widget.

2
yii/caching/ApcCache.php

@ -24,7 +24,7 @@ class ApcCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

2
yii/caching/Cache.php

@ -247,7 +247,7 @@ abstract class Cache extends Component implements \ArrayAccess
* This method should be implemented by child classes to retrieve the data * This method should be implemented by child classes to retrieve the data
* from specific cache storage. * from specific cache storage.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
abstract protected function getValue($key); abstract protected function getValue($key);

2
yii/caching/DbCache.php

@ -92,7 +92,7 @@ class DbCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

2
yii/caching/DummyCache.php

@ -24,7 +24,7 @@ class DummyCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

2
yii/caching/FileCache.php

@ -61,7 +61,7 @@ class FileCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

7
yii/caching/MemCache.php

@ -7,7 +7,6 @@
namespace yii\caching; namespace yii\caching;
use yii\base\Exception;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
/** /**
@ -21,7 +20,7 @@ use yii\base\InvalidConfigException;
* MemCache can be configured with a list of memcache servers by settings its [[servers]] property. * MemCache can be configured with a list of memcache servers by settings its [[servers]] property.
* By default, MemCache assumes there is a memcache server running on localhost at port 11211. * By default, MemCache assumes there is a memcache server running on localhost at port 11211.
* *
* See [[Cache]] for common cache operations that ApcCache supports. * See [[Cache]] for common cache operations that MemCache supports.
* *
* Note, there is no security measure to protected data in memcache. * Note, there is no security measure to protected data in memcache.
* All data in memcache can be accessed by any process running in the system. * All data in memcache can be accessed by any process running in the system.
@ -89,7 +88,7 @@ class MemCache extends Cache
if (count($servers)) { if (count($servers)) {
foreach ($servers as $server) { foreach ($servers as $server) {
if ($server->host === null) { if ($server->host === null) {
throw new Exception("The 'host' property must be specified for every memcache server."); throw new InvalidConfigException("The 'host' property must be specified for every memcache server.");
} }
if ($this->useMemcached) { if ($this->useMemcached) {
$cache->addServer($server->host, $server->port, $server->weight); $cache->addServer($server->host, $server->port, $server->weight);
@ -145,7 +144,7 @@ class MemCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

2
yii/caching/WinCache.php

@ -24,7 +24,7 @@ class WinCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

2
yii/caching/XCache.php

@ -25,7 +25,7 @@ class XCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

2
yii/caching/ZendDataCache.php

@ -24,7 +24,7 @@ class ZendDataCache extends Cache
* Retrieves a value from cache with a specified key. * Retrieves a value from cache with a specified key.
* This is the implementation of the method declared in the parent class. * This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value * @param string $key a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired. * @return string|boolean the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {

81
yii/rbac/Assignment.php

@ -16,91 +16,40 @@ use yii\base\Object;
* Do not create a Assignment instance using the 'new' operator. * Do not create a Assignment instance using the 'new' operator.
* Instead, call [[Manager::assign()]]. * Instead, call [[Manager::assign()]].
* *
* @property mixed $userId User ID (see [[User::id]]).
* @property string $itemName The authorization item name.
* @property string $bizRule The business rule associated with this assignment.
* @property mixed $data Additional data for this assignment.
*
* @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
*/ */
class Assignment extends Object class Assignment extends Object
{ {
private $_auth;
private $_userId;
private $_itemName;
private $_bizRule;
private $_data;
/** /**
* Constructor. * @var Manager the auth manager of this item
* @param Manager $auth the authorization manager
* @param mixed $userId user ID (see [[User::id]])
* @param string $itemName authorization item name
* @param string $bizRule the business rule associated with this assignment
* @param mixed $data additional data for this assignment
*/ */
public function __construct($auth, $userId, $itemName, $bizRule = null, $data = null) public $manager;
{
$this->_auth = $auth;
$this->_userId = $userId;
$this->_itemName = $itemName;
$this->_bizRule = $bizRule;
$this->_data = $data;
}
/** /**
* @return mixed user ID (see [[User::id]]) * @var string the business rule associated with this assignment
*/ */
public function getUserId() public $bizRule;
{
return $this->_userId;
}
/** /**
* @return string the authorization item name * @var mixed additional data for this assignment
*/ */
public function getItemName() public $data;
{
return $this->_itemName;
}
/** /**
* @return string the business rule associated with this assignment * @var mixed user ID (see [[User::id]]). Do not modify this property after it is populated.
* To modify the user ID of an assignment, you must remove the assignment and create a new one.
*/ */
public function getBizRule() public $userId;
{
return $this->_bizRule;
}
/**
* @param string $value the business rule associated with this assignment
*/
public function setBizRule($value)
{
if ($this->_bizRule !== $value) {
$this->_bizRule = $value;
$this->_auth->saveAssignment($this);
}
}
/** /**
* @return mixed additional data for this assignment * @return string the authorization item name. Do not modify this property after it is populated.
* To modify the item name of an assignment, you must remove the assignment and create a new one.
*/ */
public function getData() public $itemName;
{
return $this->_data;
}
/** /**
* @param mixed $value additional data for this assignment * Saves the changes to an authorization assignment.
*/ */
public function setData($value) public function save()
{ {
if ($this->_data !== $value) { $this->manager->saveAssignment($this);
$this->_data = $value;
$this->_auth->saveAssignment($this);
}
} }
} }

181
yii/rbac/DbManager.php

@ -24,8 +24,6 @@ use yii\base\InvalidParamException;
* the three tables used to store the authorization data by setting [[itemTable]], * the three tables used to store the authorization data by setting [[itemTable]],
* [[itemChildTable]] and [[assignmentTable]]. * [[itemChildTable]] and [[assignmentTable]].
* *
* @property array $authItems The authorization items of the specific type.
*
* @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
@ -106,13 +104,13 @@ class DbManager extends Manager
if (!isset($params['userId'])) { if (!isset($params['userId'])) {
$params['userId'] = $userId; $params['userId'] = $userId;
} }
if ($this->executeBizRule($item->getBizRule(), $params, $item->getData())) { if ($this->executeBizRule($item->bizRule, $params, $item->data)) {
if (in_array($itemName, $this->defaultRoles)) { if (in_array($itemName, $this->defaultRoles)) {
return true; return true;
} }
if (isset($assignments[$itemName])) { if (isset($assignments[$itemName])) {
$assignment = $assignments[$itemName]; $assignment = $assignments[$itemName];
if ($this->executeBizRule($assignment->getBizRule(), $params, $assignment->getData())) { if ($this->executeBizRule($assignment->bizRule, $params, $assignment->data)) {
return true; return true;
} }
} }
@ -146,10 +144,7 @@ class DbManager extends Manager
} }
$query = new Query; $query = new Query;
$rows = $query->from($this->itemTable) $rows = $query->from($this->itemTable)
->where(array('or', 'name=:name1', 'name=:name2'), array( ->where(array('or', 'name=:name1', 'name=:name2'), array(':name1' => $itemName, ':name2' => $childName))
':name1' => $itemName,
':name2' => $childName
))
->createCommand($this->db) ->createCommand($this->db)
->queryAll(); ->queryAll();
if (count($rows) == 2) { if (count($rows) == 2) {
@ -165,10 +160,7 @@ class DbManager extends Manager
throw new InvalidCallException("Cannot add '$childName' as a child of '$itemName'. A loop has been detected."); throw new InvalidCallException("Cannot add '$childName' as a child of '$itemName'. A loop has been detected.");
} }
$this->db->createCommand() $this->db->createCommand()
->insert($this->itemChildTable, array( ->insert($this->itemChildTable, array('parent' => $itemName, 'child' => $childName));
'parent' => $itemName,
'child' => $childName,
));
return true; return true;
} else { } else {
throw new Exception("Either '$itemName' or '$childName' does not exist."); throw new Exception("Either '$itemName' or '$childName' does not exist.");
@ -185,10 +177,7 @@ class DbManager extends Manager
public function removeItemChild($itemName, $childName) public function removeItemChild($itemName, $childName)
{ {
return $this->db->createCommand() return $this->db->createCommand()
->delete($this->itemChildTable, array( ->delete($this->itemChildTable, array('parent' => $itemName, 'child' => $childName)) > 0;
'parent' => $itemName,
'child' => $childName
)) > 0;
} }
/** /**
@ -202,10 +191,7 @@ class DbManager extends Manager
$query = new Query; $query = new Query;
return $query->select(array('parent')) return $query->select(array('parent'))
->from($this->itemChildTable) ->from($this->itemChildTable)
->where(array( ->where(array('parent' => $itemName, 'child' => $childName))
'parent' => $itemName,
'child' => $childName
))
->createCommand($this->db) ->createCommand($this->db)
->queryScalar() !== false; ->queryScalar() !== false;
} }
@ -219,11 +205,8 @@ class DbManager extends Manager
public function getItemChildren($names) public function getItemChildren($names)
{ {
$query = new Query; $query = new Query;
$rows = $query->select(array('name', 'type', 'description', 'bizrule', 'data')) $rows = $query->select(array('name', 'type', 'description', 'biz_rule', 'data'))
->from(array( ->from(array($this->itemTable, $this->itemChildTable))
$this->itemTable,
$this->itemChildTable
))
->where(array('parent' => $names, 'name' => new Expression('child'))) ->where(array('parent' => $names, 'name' => new Expression('child')))
->createCommand($this->db) ->createCommand($this->db)
->queryAll(); ->queryAll();
@ -232,7 +215,14 @@ class DbManager extends Manager
if (($data = @unserialize($row['data'])) === false) { if (($data = @unserialize($row['data'])) === false) {
$data = null; $data = null;
} }
$children[$row['name']] = new Item($this, $row['name'], $row['type'], $row['description'], $row['bizrule'], $data); $children[$row['name']] = new Item(array(
'manager' => $this,
'name' => $row['name'],
'type' => $row['type'],
'description' => $row['description'],
'bizRule' => $row['biz_rule'],
'data' => $data,
));
} }
return $children; return $children;
} }
@ -256,10 +246,16 @@ class DbManager extends Manager
->insert($this->assignmentTable, array( ->insert($this->assignmentTable, array(
'user_id' => $userId, 'user_id' => $userId,
'item_name' => $itemName, 'item_name' => $itemName,
'bizrule' => $bizRule, 'biz_rule' => $bizRule,
'data' => serialize($data) 'data' => serialize($data),
)); ));
return new Assignment($this, $userId, $itemName, $bizRule, $data); return new Assignment(array(
'manager' => $this,
'userId' => $userId,
'itemName' => $itemName,
'bizRule' => $bizRule,
'data' => $data,
));
} }
/** /**
@ -271,10 +267,7 @@ class DbManager extends Manager
public function revoke($userId, $itemName) public function revoke($userId, $itemName)
{ {
return $this->db->createCommand() return $this->db->createCommand()
->delete($this->assignmentTable, array( ->delete($this->assignmentTable, array('user_id' => $userId, 'item_name' => $itemName)) > 0;
'user_id' => $userId,
'item_name' => $itemName
)) > 0;
} }
/** /**
@ -288,10 +281,7 @@ class DbManager extends Manager
$query = new Query; $query = new Query;
return $query->select(array('item_name')) return $query->select(array('item_name'))
->from($this->assignmentTable) ->from($this->assignmentTable)
->where(array( ->where(array('user_id' => $userId, 'item_name' => $itemName))
'user_id' => $userId,
'item_name' => $itemName
))
->createCommand($this->db) ->createCommand($this->db)
->queryScalar() !== false; ->queryScalar() !== false;
} }
@ -307,17 +297,20 @@ class DbManager extends Manager
{ {
$query = new Query; $query = new Query;
$row = $query->from($this->assignmentTable) $row = $query->from($this->assignmentTable)
->where(array( ->where(array('user_id' => $userId, 'item_name' => $itemName))
'user_id' => $userId,
'item_name' => $itemName
))
->createCommand($this->db) ->createCommand($this->db)
->queryRow(); ->queryRow();
if ($row !== false) { if ($row !== false) {
if (($data = @unserialize($row['data'])) === false) { if (($data = @unserialize($row['data'])) === false) {
$data = null; $data = null;
} }
return new Assignment($this, $row['user_id'], $row['item_name'], $row['bizrule'], $data); return new Assignment(array(
'manager' => $this,
'userId' => $row['user_id'],
'itemName' => $row['item_name'],
'bizRule' => $row['biz_rule'],
'data' => $data,
));
} else { } else {
return null; return null;
} }
@ -341,7 +334,13 @@ class DbManager extends Manager
if (($data = @unserialize($row['data'])) === false) { if (($data = @unserialize($row['data'])) === false) {
$data = null; $data = null;
} }
$assignments[$row['item_name']] = new Assignment($this, $row['user_id'], $row['item_name'], $row['bizrule'], $data); $assignments[$row['item_name']] = new Assignment(array(
'manager' => $this,
'userId' => $row['user_id'],
'itemName' => $row['item_name'],
'bizRule' => $row['biz_rule'],
'data' => $data,
));
} }
return $assignments; return $assignments;
} }
@ -354,11 +353,11 @@ class DbManager extends Manager
{ {
$this->db->createCommand() $this->db->createCommand()
->update($this->assignmentTable, array( ->update($this->assignmentTable, array(
'bizrule' => $assignment->getBizRule(), 'biz_rule' => $assignment->bizRule,
'data' => serialize($assignment->getData()), 'data' => serialize($assignment->data),
), array( ), array(
'user_id' => $assignment->getUserId(), 'user_id' => $assignment->userId,
'item_name' => $assignment->getItemName() 'item_name' => $assignment->itemName,
)); ));
} }
@ -381,24 +380,14 @@ class DbManager extends Manager
->where(array('type' => $type)) ->where(array('type' => $type))
->createCommand($this->db); ->createCommand($this->db);
} elseif ($type === null) { } elseif ($type === null) {
$command = $query->select(array('name', 'type', 'description', 't1.bizrule', 't1.data')) $command = $query->select(array('name', 'type', 'description', 't1.biz_rule', 't1.data'))
->from(array( ->from(array($this->itemTable . ' t1', $this->assignmentTable . ' t2'))
$this->itemTable . ' t1',
$this->assignmentTable . ' t2'
))
->where(array('user_id' => $userId, 'name' => new Expression('item_name'))) ->where(array('user_id' => $userId, 'name' => new Expression('item_name')))
->createCommand($this->db); ->createCommand($this->db);
} else { } else {
$command = $query->select('name', 'type', 'description', 't1.bizrule', 't1.data') $command = $query->select('name', 'type', 'description', 't1.biz_rule', 't1.data')
->from(array( ->from(array($this->itemTable . ' t1', $this->assignmentTable . ' t2'))
$this->itemTable . ' t1', ->where(array('user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')))
$this->assignmentTable . ' t2'
))
->where(array(
'user_id' => $userId,
'type' => $type,
'name' => new Expression('item_name'),
))
->createCommand($this->db); ->createCommand($this->db);
} }
$items = array(); $items = array();
@ -406,7 +395,14 @@ class DbManager extends Manager
if (($data = @unserialize($row['data'])) === false) { if (($data = @unserialize($row['data'])) === false) {
$data = null; $data = null;
} }
$items[$row['name']] = new Item($this, $row['name'], $row['type'], $row['description'], $row['bizrule'], $data); $items[$row['name']] = new Item(array(
'manager' => $this,
'name' => $row['name'],
'type' => $row['type'],
'description' => $row['description'],
'bizRule' => $row['biz_rule'],
'data' => $data,
));
} }
return $items; return $items;
} }
@ -433,10 +429,17 @@ class DbManager extends Manager
'name' => $name, 'name' => $name,
'type' => $type, 'type' => $type,
'description' => $description, 'description' => $description,
'bizrule' => $bizRule, 'biz_rule' => $bizRule,
'data' => serialize($data) 'data' => serialize($data),
)); ));
return new Item($this, $name, $type, $description, $bizRule, $data); return new Item(array(
'manager' => $this,
'name' => $name,
'type' => $type,
'description' => $description,
'bizRule' => $bizRule,
'data' => $data,
));
} }
/** /**
@ -448,13 +451,12 @@ class DbManager extends Manager
{ {
if ($this->usingSqlite()) { if ($this->usingSqlite()) {
$this->db->createCommand() $this->db->createCommand()
->delete($this->itemChildTable, array('or', 'parent=:name1', 'child=:name2'), array( ->delete($this->itemChildTable, array('or', 'parent=:name', 'child=:name'), array(':name' => $name));
':name1' => $name, $this->db->createCommand()
':name2' => $name ->delete($this->assignmentTable, array('item_name' => $name));
));
$this->db->createCommand()->delete($this->assignmentTable, array('item_name' => $name));
} }
return $this->db->createCommand()->delete($this->itemTable, array('name' => $name)) > 0; return $this->db->createCommand()
->delete($this->itemTable, array('name' => $name)) > 0;
} }
/** /**
@ -474,7 +476,14 @@ class DbManager extends Manager
if (($data = @unserialize($row['data'])) === false) { if (($data = @unserialize($row['data'])) === false) {
$data = null; $data = null;
} }
return new Item($this, $row['name'], $row['type'], $row['description'], $row['bizrule'], $data); return new Item(array(
'manager' => $this,
'name' => $row['name'],
'type' => $row['type'],
'description' => $row['description'],
'bizRule' => $row['biz_rule'],
'data' => $data,
));
} else } else
return null; return null;
} }
@ -488,32 +497,20 @@ class DbManager extends Manager
{ {
if ($this->usingSqlite() && $oldName !== null && $item->getName() !== $oldName) { if ($this->usingSqlite() && $oldName !== null && $item->getName() !== $oldName) {
$this->db->createCommand() $this->db->createCommand()
->update($this->itemChildTable, array( ->update($this->itemChildTable, array('parent' => $item->getName()), array('parent' => $oldName));
'parent' => $item->getName(),
), array(
'parent' => $oldName,
));
$this->db->createCommand() $this->db->createCommand()
->update($this->itemChildTable, array( ->update($this->itemChildTable, array('child' => $item->getName()), array('child' => $oldName));
'child' => $item->getName(),
), array(
'child' => $oldName,
));
$this->db->createCommand() $this->db->createCommand()
->update($this->assignmentTable, array( ->update($this->assignmentTable, array('item_name' => $item->getName()), array('item_name' => $oldName));
'item_name' => $item->getName(),
), array(
'item_name' => $oldName,
));
} }
$this->db->createCommand() $this->db->createCommand()
->update($this->itemTable, array( ->update($this->itemTable, array(
'name' => $item->getName(), 'name' => $item->getName(),
'type' => $item->getType(), 'type' => $item->type,
'description' => $item->getDescription(), 'description' => $item->description,
'bizrule' => $item->getBizRule(), 'biz_rule' => $item->bizRule,
'data' => serialize($item->getData()), 'data' => serialize($item->data),
), array( ), array(
'name' => $oldName === null ? $item->getName() : $oldName, 'name' => $oldName === null ? $item->getName() : $oldName,
)); ));

158
yii/rbac/Item.php

@ -18,14 +18,6 @@ use yii\base\Object;
* A user may be assigned one or several authorization items (called [[Assignment]] assignments). * A user may be assigned one or several authorization items (called [[Assignment]] assignments).
* He can perform an operation only when it is among his assigned items. * He can perform an operation only when it is among his assigned items.
* *
* @property Manager $authManager The authorization manager.
* @property integer $type The authorization item type. This could be 0 (operation), 1 (task) or 2 (role).
* @property string $name The item name.
* @property string $description The item description.
* @property string $bizRule The business rule associated with this item.
* @property mixed $data The additional data associated with this item.
* @property array $children All child items of this item.
*
* @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
@ -36,31 +28,30 @@ class Item extends Object
const TYPE_TASK = 1; const TYPE_TASK = 1;
const TYPE_ROLE = 2; const TYPE_ROLE = 2;
private $_auth;
private $_type;
private $_name;
private $_description;
private $_bizRule;
private $_data;
/** /**
* Constructor. * @var Manager the auth manager of this item
* @param Manager $auth authorization manager
* @param string $name authorization item name
* @param integer $type authorization item type. This can be 0 (operation), 1 (task) or 2 (role).
* @param string $description the description
* @param string $bizRule the business rule associated with this item
* @param mixed $data additional data for this item
*/ */
public function __construct($auth, $name, $type, $description = '', $bizRule = null, $data = null) public $manager;
{ /**
$this->_type = (int)$type; * @var string the item description
$this->_auth = $auth; */
$this->_name = $name; public $description;
$this->_description = $description; /**
$this->_bizRule = $bizRule; * @var string the business rule associated with this item
$this->_data = $data; */
} public $bizRule;
/**
* @var mixed the additional data associated with this item
*/
public $data;
/**
* @var integer the authorization item type. This could be 0 (operation), 1 (task) or 2 (role).
*/
public $type;
private $_name;
private $_oldName;
/** /**
* Checks to see if the specified item is within the hierarchy starting from this item. * Checks to see if the specified item is within the hierarchy starting from this item.
@ -73,11 +64,11 @@ class Item extends Object
public function checkAccess($itemName, $params = array()) public function checkAccess($itemName, $params = array())
{ {
Yii::trace('Checking permission: ' . $this->_name, __METHOD__); Yii::trace('Checking permission: ' . $this->_name, __METHOD__);
if ($this->_auth->executeBizRule($this->_bizRule, $params, $this->_data)) { if ($this->manager->executeBizRule($this->bizRule, $params, $this->data)) {
if ($this->_name == $itemName) { if ($this->_name == $itemName) {
return true; return true;
} }
foreach ($this->_auth->getItemChildren($this->_name) as $item) { foreach ($this->manager->getItemChildren($this->_name) as $item) {
if ($item->checkAccess($itemName, $params)) { if ($item->checkAccess($itemName, $params)) {
return true; return true;
} }
@ -87,22 +78,6 @@ class Item extends Object
} }
/** /**
* @return Manager the authorization manager
*/
public function getManager()
{
return $this->_auth;
}
/**
* @return integer the authorization item type. This could be 0 (operation), 1 (task) or 2 (role).
*/
public function getType()
{
return $this->_type;
}
/**
* @return string the item name * @return string the item name
*/ */
public function getName() public function getName()
@ -116,66 +91,8 @@ class Item extends Object
public function setName($value) public function setName($value)
{ {
if ($this->_name !== $value) { if ($this->_name !== $value) {
$oldName = $this->_name; $this->_oldName = $this->_name;
$this->_name = $value; $this->_name = $value;
$this->_auth->saveItem($this, $oldName);
}
}
/**
* @return string the item description
*/
public function getDescription()
{
return $this->_description;
}
/**
* @param string $value the item description
*/
public function setDescription($value)
{
if ($this->_description !== $value) {
$this->_description = $value;
$this->_auth->saveItem($this);
}
}
/**
* @return string the business rule associated with this item
*/
public function getBizRule()
{
return $this->_bizRule;
}
/**
* @param string $value the business rule associated with this item
*/
public function setBizRule($value)
{
if ($this->_bizRule !== $value) {
$this->_bizRule = $value;
$this->_auth->saveItem($this);
}
}
/**
* @return mixed the additional data associated with this item
*/
public function getData()
{
return $this->_data;
}
/**
* @param mixed $value the additional data associated with this item
*/
public function setData($value)
{
if ($this->_data !== $value) {
$this->_data = $value;
$this->_auth->saveItem($this);
} }
} }
@ -188,7 +105,7 @@ class Item extends Object
*/ */
public function addChild($name) public function addChild($name)
{ {
return $this->_auth->addItemChild($this->_name, $name); return $this->manager->addItemChild($this->_name, $name);
} }
/** /**
@ -200,7 +117,7 @@ class Item extends Object
*/ */
public function removeChild($name) public function removeChild($name)
{ {
return $this->_auth->removeItemChild($this->_name, $name); return $this->manager->removeItemChild($this->_name, $name);
} }
/** /**
@ -211,7 +128,7 @@ class Item extends Object
*/ */
public function hasChild($name) public function hasChild($name)
{ {
return $this->_auth->hasItemChild($this->_name, $name); return $this->manager->hasItemChild($this->_name, $name);
} }
/** /**
@ -221,7 +138,7 @@ class Item extends Object
*/ */
public function getChildren() public function getChildren()
{ {
return $this->_auth->getItemChildren($this->_name); return $this->manager->getItemChildren($this->_name);
} }
/** /**
@ -236,7 +153,7 @@ class Item extends Object
*/ */
public function assign($userId, $bizRule = null, $data = null) public function assign($userId, $bizRule = null, $data = null)
{ {
return $this->_auth->assign($userId, $this->_name, $bizRule, $data); return $this->manager->assign($userId, $this->_name, $bizRule, $data);
} }
/** /**
@ -247,7 +164,7 @@ class Item extends Object
*/ */
public function revoke($userId) public function revoke($userId)
{ {
return $this->_auth->revoke($userId, $this->_name); return $this->manager->revoke($userId, $this->_name);
} }
/** /**
@ -258,7 +175,7 @@ class Item extends Object
*/ */
public function isAssigned($userId) public function isAssigned($userId)
{ {
return $this->_auth->isAssigned($userId, $this->_name); return $this->manager->isAssigned($userId, $this->_name);
} }
/** /**
@ -270,6 +187,15 @@ class Item extends Object
*/ */
public function getAssignment($userId) public function getAssignment($userId)
{ {
return $this->_auth->getAssignment($userId, $this->_name); return $this->manager->getAssignment($userId, $this->_name);
}
/**
* Saves an authorization item to persistent storage.
*/
public function save()
{
$this->manager->saveItem($this, $this->_oldName);
unset($this->_oldName);
} }
} }

2
yii/rbac/Manager.php

@ -161,7 +161,7 @@ abstract class Manager extends Component
{ {
static $types = array('operation', 'task', 'role'); static $types = array('operation', 'task', 'role');
if ($parentType < $childType) { if ($parentType < $childType) {
throw new InvalidParamException("Cannot add an item of type '$types[$childType]' to an item of type '$types[$parentType]'."); throw new InvalidParamException("Cannot add an item of type '{$types[$childType]}' to an item of type '{$types[$parentType]}'.");
} }
} }

60
yii/rbac/PhpManager.php

@ -80,14 +80,14 @@ class PhpManager extends Manager
if (!isset($params['userId'])) { if (!isset($params['userId'])) {
$params['userId'] = $userId; $params['userId'] = $userId;
} }
if ($this->executeBizRule($item->getBizRule(), $params, $item->getData())) { if ($this->executeBizRule($item->bizRule, $params, $item->data)) {
if (in_array($itemName, $this->defaultRoles)) { if (in_array($itemName, $this->defaultRoles)) {
return true; return true;
} }
if (isset($this->_assignments[$userId][$itemName])) { if (isset($this->_assignments[$userId][$itemName])) {
/** @var $assignment Assignment */ /** @var $assignment Assignment */
$assignment = $this->_assignments[$userId][$itemName]; $assignment = $this->_assignments[$userId][$itemName];
if ($this->executeBizRule($assignment->getBizRule(), $params, $assignment->getData())) { if ($this->executeBizRule($assignment->bizRule, $params, $assignment->data)) {
return true; return true;
} }
} }
@ -117,7 +117,7 @@ class PhpManager extends Manager
$child = $this->_items[$childName]; $child = $this->_items[$childName];
/** @var $item Item */ /** @var $item Item */
$item = $this->_items[$itemName]; $item = $this->_items[$itemName];
$this->checkItemChildType($item->getType(), $child->getType()); $this->checkItemChildType($item->type, $child->type);
if ($this->detectLoop($itemName, $childName)) { if ($this->detectLoop($itemName, $childName)) {
throw new InvalidCallException("Cannot add '$childName' as a child of '$itemName'. A loop has been detected."); throw new InvalidCallException("Cannot add '$childName' as a child of '$itemName'. A loop has been detected.");
} }
@ -194,7 +194,13 @@ class PhpManager extends Manager
} elseif (isset($this->_assignments[$userId][$itemName])) { } elseif (isset($this->_assignments[$userId][$itemName])) {
throw new InvalidParamException("Authorization item '$itemName' has already been assigned to user '$userId'."); throw new InvalidParamException("Authorization item '$itemName' has already been assigned to user '$userId'.");
} else { } else {
return $this->_assignments[$userId][$itemName] = new Assignment($this, $userId, $itemName, $bizRule, $data); return $this->_assignments[$userId][$itemName] = new Assignment(array(
'manager' => $this,
'userId' => $userId,
'itemName' => $itemName,
'bizRule' => $bizRule,
'data' => $data,
));
} }
} }
@ -265,15 +271,15 @@ class PhpManager extends Manager
if ($userId === null) { if ($userId === null) {
foreach ($this->_items as $name => $item) { foreach ($this->_items as $name => $item) {
/** @var $item Item */ /** @var $item Item */
if ($item->getType() == $type) { if ($item->type == $type) {
$items[$name] = $item; $items[$name] = $item;
} }
} }
} elseif (isset($this->_assignments[$userId])) { } elseif (isset($this->_assignments[$userId])) {
foreach ($this->_assignments[$userId] as $assignment) { foreach ($this->_assignments[$userId] as $assignment) {
/** @var $assignment Assignment */ /** @var $assignment Assignment */
$name = $assignment->getItemName(); $name = $assignment->itemName;
if (isset($this->_items[$name]) && ($type === null || $this->_items[$name]->getType() == $type)) { if (isset($this->_items[$name]) && ($type === null || $this->_items[$name]->type == $type)) {
$items[$name] = $this->_items[$name]; $items[$name] = $this->_items[$name];
} }
} }
@ -301,7 +307,14 @@ class PhpManager extends Manager
if (isset($this->_items[$name])) { if (isset($this->_items[$name])) {
throw new Exception('Unable to add an item whose name is the same as an existing item.'); throw new Exception('Unable to add an item whose name is the same as an existing item.');
} }
return $this->_items[$name] = new Item($this, $name, $type, $description, $bizRule, $data); return $this->_items[$name] = new Item(array(
'manager' => $this,
'name' => $name,
'type' => $type,
'description' => $description,
'bizRule' => $bizRule,
'data' => $data,
));
} }
/** /**
@ -390,10 +403,10 @@ class PhpManager extends Manager
foreach ($this->_items as $name => $item) { foreach ($this->_items as $name => $item) {
/** @var $item Item */ /** @var $item Item */
$items[$name] = array( $items[$name] = array(
'type' => $item->getType(), 'type' => $item->type,
'description' => $item->getDescription(), 'description' => $item->description,
'bizRule' => $item->getBizRule(), 'bizRule' => $item->bizRule,
'data' => $item->getData(), 'data' => $item->data,
); );
if (isset($this->_children[$name])) { if (isset($this->_children[$name])) {
foreach ($this->_children[$name] as $child) { foreach ($this->_children[$name] as $child) {
@ -408,8 +421,8 @@ class PhpManager extends Manager
/** @var $assignment Assignment */ /** @var $assignment Assignment */
if (isset($items[$name])) { if (isset($items[$name])) {
$items[$name]['assignments'][$userId] = array( $items[$name]['assignments'][$userId] = array(
'bizRule' => $assignment->getBizRule(), 'bizRule' => $assignment->bizRule,
'data' => $assignment->getData(), 'data' => $assignment->data,
); );
} }
} }
@ -428,7 +441,14 @@ class PhpManager extends Manager
$items = $this->loadFromFile($this->authFile); $items = $this->loadFromFile($this->authFile);
foreach ($items as $name => $item) { foreach ($items as $name => $item) {
$this->_items[$name] = new Item($this, $name, $item['type'], $item['description'], $item['bizRule'], $item['data']); $this->_items[$name] = new Item(array(
'manager' => $this,
'name' => $name,
'type' => $item['type'],
'description' => $item['description'],
'bizRule' => $item['bizRule'],
'data' => $item['data'],
));
} }
foreach ($items as $name => $item) { foreach ($items as $name => $item) {
@ -441,8 +461,14 @@ class PhpManager extends Manager
} }
if (isset($item['assignments'])) { if (isset($item['assignments'])) {
foreach ($item['assignments'] as $userId => $assignment) { foreach ($item['assignments'] as $userId => $assignment) {
$this->_assignments[$userId][$name] = new Assignment($this, $name, $userId, $assignment['bizRule'], $assignment['data']); $this->_assignments[$userId][$name] = new Assignment(array(
} 'manager' => $this,
'userId' => $userId,
'itemName' => $name,
'bizRule' => $assignment['bizRule'],
'data' => $assignment['data'],
));
}
} }
} }
} }

7
yii/rbac/schema-mssql.sql

@ -18,9 +18,10 @@ create table [tbl_auth_item]
[name] varchar(64) not null, [name] varchar(64) not null,
[type] integer not null, [type] integer not null,
[description] text, [description] text,
[bizrule] text, [biz_rule] text,
[data] text, [data] text,
primary key ([name]) primary key ([name]),
key [type] ([type])
); );
create table [tbl_auth_item_child] create table [tbl_auth_item_child]
@ -36,7 +37,7 @@ create table [tbl_auth_assignment]
( (
[item_name] varchar(64) not null, [item_name] varchar(64) not null,
[user_id] varchar(64) not null, [user_id] varchar(64) not null,
[bizrule] text, [biz_rule] text,
[data] text, [data] text,
primary key ([item_name],[user_id]), primary key ([item_name],[user_id]),
foreign key ([item_name]) references [tbl_auth_item] ([name]) on delete cascade on update cascade foreign key ([item_name]) references [tbl_auth_item] ([name]) on delete cascade on update cascade

7
yii/rbac/schema-mysql.sql

@ -18,9 +18,10 @@ create table `tbl_auth_item`
`name` varchar(64) not null, `name` varchar(64) not null,
`type` integer not null, `type` integer not null,
`description` text, `description` text,
`bizrule` text, `biz_rule` text,
`data` text, `data` text,
primary key (`name`) primary key (`name`),
key `type` (`type`)
) engine InnoDB; ) engine InnoDB;
create table `tbl_auth_item_child` create table `tbl_auth_item_child`
@ -36,7 +37,7 @@ create table `tbl_auth_assignment`
( (
`item_name` varchar(64) not null, `item_name` varchar(64) not null,
`user_id` varchar(64) not null, `user_id` varchar(64) not null,
`bizrule` text, `biz_rule` text,
`data` text, `data` text,
primary key (`item_name`,`user_id`), primary key (`item_name`,`user_id`),
foreign key (`item_name`) references `tbl_auth_item` (`name`) on delete cascade on update cascade foreign key (`item_name`) references `tbl_auth_item` (`name`) on delete cascade on update cascade

7
yii/rbac/schema-oci.sql

@ -18,9 +18,10 @@ create table "tbl_auth_item"
"name" varchar(64) not null, "name" varchar(64) not null,
"type" integer not null, "type" integer not null,
"description" text, "description" text,
"bizrule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("name") primary key ("name"),
key "type" ("type")
); );
create table "tbl_auth_item_child" create table "tbl_auth_item_child"
@ -36,7 +37,7 @@ create table "tbl_auth_assignment"
( (
"item_name" varchar(64) not null, "item_name" varchar(64) not null,
"user_id" varchar(64) not null, "user_id" varchar(64) not null,
"bizrule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("item_name","user_id"), primary key ("item_name","user_id"),
foreign key ("item_name") references "tbl_auth_item" ("name") on delete cascade on update cascade foreign key ("item_name") references "tbl_auth_item" ("name") on delete cascade on update cascade

7
yii/rbac/schema-pgsql.sql

@ -18,9 +18,10 @@ create table "tbl_auth_item"
"name" varchar(64) not null, "name" varchar(64) not null,
"type" integer not null, "type" integer not null,
"description" text, "description" text,
"bizrule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("name") primary key ("name"),
key "type" ("type")
); );
create table "tbl_auth_item_child" create table "tbl_auth_item_child"
@ -36,7 +37,7 @@ create table "tbl_auth_assignment"
( (
"item_name" varchar(64) not null, "item_name" varchar(64) not null,
"user_id" varchar(64) not null, "user_id" varchar(64) not null,
"bizrule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("item_name","user_id"), primary key ("item_name","user_id"),
foreign key ("item_name") references "tbl_auth_item" ("name") on delete cascade on update cascade foreign key ("item_name") references "tbl_auth_item" ("name") on delete cascade on update cascade

7
yii/rbac/schema-sqlite.sql

@ -18,9 +18,10 @@ create table 'tbl_auth_item'
"name" varchar(64) not null, "name" varchar(64) not null,
"type" integer not null, "type" integer not null,
"description" text, "description" text,
"bizrule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("name") primary key ("name"),
key "type" ("type")
); );
create table 'tbl_auth_item_child' create table 'tbl_auth_item_child'
@ -36,7 +37,7 @@ create table 'tbl_auth_assignment'
( (
"item_name" varchar(64) not null, "item_name" varchar(64) not null,
"user_id" varchar(64) not null, "user_id" varchar(64) not null,
"bizrule" text, "biz_rule" text,
"data" text, "data" text,
primary key ("item_name","user_id"), primary key ("item_name","user_id"),
foreign key ("item_name") references 'tbl_auth_item' ("name") on delete cascade on update cascade foreign key ("item_name") references 'tbl_auth_item' ("name") on delete cascade on update cascade

392
yii/requirements/YiiRequirementChecker.php

@ -0,0 +1,392 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
if (version_compare(PHP_VERSION, '4.3', '<')) {
echo 'At least PHP 4.3 is required to run this script!';
exit(1);
}
/**
* YiiRequirementChecker allows checking, if current system meets the requirements for running the Yii application.
* This class allows rendering of the check report for the web and console application interface.
*
* Example:
*
* ~~~
* require_once('path/to/YiiRequirementChecker.php');
* $requirementsChecker = new YiiRequirementChecker();
* $requirements = array(
* array(
* 'name' => 'PHP Some Extension',
* 'mandatory' => true,
* 'condition' => extension_loaded('some_extension'),
* 'by' => 'Some application feature',
* 'memo' => 'PHP extension "some_extension" required',
* ),
* );
* $requirementsChecker->checkYii()->check($requirements)->render();
* ~~~
*
* If you wish to render the report with your own representation, use [[getResult()]] instead of [[render()]]
*
* Requirement condition could be in format "eval:PHP expression".
* In this case specified PHP expression will be evaluated in the context of this class instance.
* For example:
*
* ~~~
* $requirements = array(
* array(
* 'name' => 'Upload max file size',
* 'condition' => 'eval:$this->checkUploadMaxFileSize("5M")',
* ),
* );
* ~~~
*
* @property array|null $result the check results, this property is for internal usage only.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class YiiRequirementChecker
{
/**
* Check the given requirements, collecting results into internal field.
* This method can be invoked several times checking different requirement sets.
* Use [[getResult()]] or [[render()]] to get the results.
* @param array|string $requirements requirements to be checked.
* If an array, it is treated as the set of requirements;
* If a string, it is treated as the path of the file, which contains the requirements;
* @return YiiRequirementChecker self instance.
*/
function check($requirements)
{
if (is_string($requirements)) {
$requirements = require($requirements);
}
if (!is_array($requirements)) {
$this->usageError('Requirements must be an array, "' . gettype($requirements) . '" has been given!');
}
if (!isset($this->result) || !is_array($this->result)) {
$this->result = array(
'summary' => array(
'total' => 0,
'errors' => 0,
'warnings' => 0,
),
'requirements' => array(),
);
}
foreach ($requirements as $key => $rawRequirement) {
$requirement = $this->normalizeRequirement($rawRequirement, $key);
$this->result['summary']['total']++;
if (!$requirement['condition']) {
if ($requirement['mandatory']) {
$requirement['error'] = true;
$requirement['warning'] = true;
$this->result['summary']['errors']++;
} else {
$requirement['error'] = false;
$requirement['warning'] = true;
$this->result['summary']['warnings']++;
}
} else {
$requirement['error'] = false;
$requirement['warning'] = false;
}
$this->result['requirements'][] = $requirement;
}
return $this;
}
/**
* Performs the check for the Yii core requirements.
* @return YiiRequirementChecker self instance.
*/
public function checkYii()
{
return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php');
}
/**
* Return the check results.
* @return array|null check results in format:
* <code>
* array(
* 'summary' => array(
* 'total' => total number of checks,
* 'errors' => number of errors,
* 'warnings' => number of warnings,
* ),
* 'requirements' => array(
* array(
* ...
* 'error' => is there an error,
* 'warning' => is there a warning,
* ),
* ...
* ),
* )
* </code>
*/
function getResult()
{
if (isset($this->result)) {
return $this->result;
} else {
return null;
}
}
/**
* Renders the requirements check result.
* The output will vary depending is a script running from web or from console.
*/
function render()
{
if (!isset($this->result)) {
$this->usageError('Nothing to render!');
}
$baseViewFilePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views';
if (array_key_exists('argv', $_SERVER)) {
$viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'console' . DIRECTORY_SEPARATOR . 'index.php';
} else {
$viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'web' . DIRECTORY_SEPARATOR . 'index.php';
}
$this->renderViewFile($viewFileName, $this->result);
}
/**
* Checks if the given PHP extension is available and its version matches the given one.
* @param string $extensionName PHP extension name.
* @param string $version required PHP extension version.
* @param string $compare comparison operator, by default '>='
* @return boolean if PHP extension version matches.
*/
function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
{
if (!extension_loaded($extensionName)) {
return false;
}
$extensionVersion = phpversion($extensionName);
if (empty($extensionVersion)) {
return false;
}
return version_compare($extensionVersion, $version, $compare);
}
/**
* Checks if PHP configuration option (from php.ini) is on.
* @param string $name configuration option name.
* @return boolean option is on.
*/
function checkPhpIniOn($name)
{
$value = ini_get($name);
if (empty($value)) {
return false;
}
return ((integer)$value == 1 || strtolower($value) == 'on');
}
/**
* Checks if PHP configuration option (from php.ini) is off.
* @param string $name configuration option name.
* @return boolean option is off.
*/
function checkPhpIniOff($name)
{
$value = ini_get($name);
if (empty($value)) {
return true;
}
return (strtolower($value) == 'off');
}
/**
* Compare byte sizes of values given in the verbose representation,
* like '5M', '15K' etc.
* @param string $a first value.
* @param string $b second value.
* @param string $compare comparison operator, by default '>='.
* @return boolean comparison result.
*/
function compareByteSize($a, $b, $compare = '>=')
{
$compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')';
return $this->evaluateExpression($compareExpression);
}
/**
* Gets the size in bytes from verbose size representation.
* For example: '5K' => 5*1024
* @param string $verboseSize verbose size representation.
* @return integer actual size in bytes.
*/
function getByteSize($verboseSize)
{
if (empty($verboseSize)) {
return 0;
}
if (is_numeric($verboseSize)) {
return (integer)$verboseSize;
}
$sizeUnit = trim($verboseSize, '0123456789');
$size = str_replace($sizeUnit, '', $verboseSize);
$size = trim($size);
if (!is_numeric($size)) {
return 0;
}
switch (strtolower($sizeUnit)) {
case 'kb':
case 'k': {
return $size * 1024;
}
case 'mb':
case 'm': {
return $size * 1024 * 1024;
}
case 'gb':
case 'g': {
return $size * 1024 * 1024 * 1024;
}
default: {
return 0;
}
}
}
/**
* Checks if upload max file size matches the given range.
* @param string|null $min verbose file size minimum required value, pass null to skip minimum check.
* @param string|null $max verbose file size maximum required value, pass null to skip maximum check.
* @return boolean success.
*/
function checkUploadMaxFileSize($min = null, $max = null)
{
$postMaxSize = ini_get('post_max_size');
$uploadMaxFileSize = ini_get('upload_max_filesize');
if ($min !== null) {
$minCheckResult = $this->compareByteSize($postMaxSize, $min, '>=') && $this->compareByteSize($uploadMaxFileSize, $min, '>=');
} else {
$minCheckResult = true;
}
if ($max !== null) {
var_dump($postMaxSize, $uploadMaxFileSize, $max);
$maxCheckResult = $this->compareByteSize($postMaxSize, $max, '<=') && $this->compareByteSize($uploadMaxFileSize, $max, '<=');
} else {
$maxCheckResult = true;
}
return ($minCheckResult && $maxCheckResult);
}
/**
* Renders a view file.
* This method includes the view file as a PHP script
* and captures the display result if required.
* @param string $_viewFile_ view file
* @param array $_data_ data to be extracted and made available to the view file
* @param boolean $_return_ whether the rendering result should be returned as a string
* @return string the rendering result. Null if the rendering result is not required.
*/
function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
{
// we use special variable names here to avoid conflict when extracting data
if (is_array($_data_)) {
extract($_data_, EXTR_PREFIX_SAME, 'data');
} else {
$data = $_data_;
}
if ($_return_) {
ob_start();
ob_implicit_flush(false);
require($_viewFile_);
return ob_get_clean();
} else {
require($_viewFile_);
}
}
/**
* Normalizes requirement ensuring it has correct format.
* @param array $requirement raw requirement.
* @param int $requirementKey requirement key in the list.
* @return array normalized requirement.
*/
function normalizeRequirement($requirement, $requirementKey = 0)
{
if (!is_array($requirement)) {
$this->usageError('Requirement must be an array!');
}
if (!array_key_exists('condition', $requirement)) {
$this->usageError("Requirement '{$requirementKey}' has no condition!");
} else {
$evalPrefix = 'eval:';
if (is_string($requirement['condition']) && strpos($requirement['condition'], $evalPrefix) === 0) {
$expression = substr($requirement['condition'], strlen($evalPrefix));
$requirement['condition'] = $this->evaluateExpression($expression);
}
}
if (!array_key_exists('name', $requirement)) {
$requirement['name'] = is_numeric($requirementKey) ? 'Requirement #' . $requirementKey : $requirementKey;
}
if (!array_key_exists('mandatory', $requirement)) {
if (array_key_exists('required', $requirement)) {
$requirement['mandatory'] = $requirement['required'];
} else {
$requirement['mandatory'] = false;
}
}
if (!array_key_exists('by', $requirement)) {
$requirement['by'] = 'Unknown';
}
if (!array_key_exists('memo', $requirement)) {
$requirement['memo'] = '';
}
return $requirement;
}
/**
* Displays a usage error.
* This method will then terminate the execution of the current application.
* @param string $message the error message
*/
function usageError($message)
{
echo "Error: $message\n\n";
exit(1);
}
/**
* Evaluates a PHP expression under the context of this class.
* @param string $expression a PHP expression to be evaluated.
* @return mixed the expression result.
*/
function evaluateExpression($expression)
{
return eval('return ' . $expression . ';');
}
/**
* Returns the server information.
* @return string server information.
*/
function getServerInfo()
{
$info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
return $info;
}
/**
* Returns the now date if possible in string representation.
* @return string now date.
*/
function getNowDate()
{
$nowDate = @strftime('%Y-%m-%d %H:%M', time());
return $nowDate;
}
}

39
yii/requirements/requirements.php

@ -0,0 +1,39 @@
<?php
/**
* This is the Yii core requirements for the [[YiiRequirementChecker]] instance.
* These requirements are mandatory for any Yii application.
*/
return array(
array(
'name' => 'PHP version',
'mandatory' => true,
'condition' => version_compare(PHP_VERSION, '5.3.0', '>='),
'by' => '<a href="http://www.yiiframework.com">Yii Framework</a>',
'memo' => 'PHP 5.3.0 or higher is required.',
),
array(
'name' => 'Reflection extension',
'mandatory' => true,
'condition' => class_exists('Reflection', false),
'by' => '<a href="http://www.yiiframework.com">Yii Framework</a>',
),
array(
'name' => 'PCRE extension',
'mandatory' => true,
'condition' => extension_loaded('pcre'),
'by' => '<a href="http://www.yiiframework.com">Yii Framework</a>',
),
array(
'name' => 'SPL extension',
'mandatory' => true,
'condition' => extension_loaded('SPL'),
'by' => '<a href="http://www.yiiframework.com">Yii Framework</a>',
),
array(
'name' => 'MBString extension',
'mandatory' => true,
'condition' => extension_loaded('mbstring'),
'by' => '<a href="http://www.php.net/manual/en/book.mbstring.php">Multibyte string</a> processing',
'memo' => 'Required for multibyte encoding string processing.'
),
);

36
yii/requirements/views/console/index.php

@ -0,0 +1,36 @@
<?php
/* @var $this YiiRequirementChecker */
/* @var $summary array */
/* @var $requirements array[] */
echo "\nYii Application Requirement Checker\n\n";
echo "This script checks if your server configuration meets the requirements\n";
echo "for running Yii application.\n";
echo "It checks if the server is running the right version of PHP,\n";
echo "if appropriate PHP extensions have been loaded, and if php.ini file settings are correct.\n";
$header = 'Check conclusion:';
echo "\n{$header}\n";
echo str_pad('', strlen($header), '-')."\n\n";
foreach ($requirements as $key => $requirement) {
if ($requirement['condition']) {
echo $requirement['name'].": OK\n";
echo "\n";
} else {
echo $requirement['name'].': '.($requirement['mandatory'] ? 'FAILED!!!' : 'WARNING!!!')."\n";
echo 'Required by: '.strip_tags($requirement['by'])."\n";
$memo = strip_tags($requirement['memo']);
if (!empty($memo)) {
echo 'Memo: '.strip_tags($requirement['memo'])."\n";
}
echo "\n";
}
}
$summaryString = 'Errors: '.$summary['errors'].' Warnings: '.$summary['warnings'].' Total checks: '.$summary['total'];
echo str_pad('', strlen($summaryString), '-')."\n";
echo $summaryString;
echo "\n\n";

93
yii/requirements/views/web/css.php

@ -0,0 +1,93 @@
body
{
background: white;
font-family:'Lucida Grande',Verdana,Geneva,Lucida,Helvetica,Arial,sans-serif;
font-size:10pt;
font-weight:normal;
}
#page
{
width: 800px;
margin: 0 auto;
}
#header
{
}
#content
{
}
#footer
{
color: gray;
font-size:8pt;
border-top:1px solid #aaa;
margin-top:10px;
}
h1
{
color:black;
font-size:1.6em;
font-weight:bold;
margin:0.5em 0pt;
}
h2
{
color:black;
font-size:1.25em;
font-weight:bold;
margin:0.3em 0pt;
}
h3
{
color:black;
font-size:1.1em;
font-weight:bold;
margin:0.2em 0pt;
}
table.result
{
background:#E6ECFF none repeat scroll 0% 0%;
border-collapse:collapse;
width:100%;
}
table.result th
{
background:#CCD9FF none repeat scroll 0% 0%;
text-align:left;
}
table.result th, table.result td
{
border:1px solid #BFCFFF;
padding:0.2em;
}
td.passed
{
background-color: #60BF60;
border: 1px solid silver;
padding: 2px;
}
td.warning
{
background-color: #FFFFBF;
border: 1px solid silver;
padding: 2px;
}
td.failed
{
background-color: #FF8080;
border: 1px solid silver;
padding: 2px;
}

82
yii/requirements/views/web/index.php

@ -0,0 +1,82 @@
<?php
/* @var $this YiiRequirementChecker */
/* @var $summary array */
/* @var $requirements array[] */
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="content-language" content="en"/>
<style type="text/css">
<?php $this->renderViewFile(dirname(__FILE__).DIRECTORY_SEPARATOR.'css.php'); ?>
</style>
<title>Yii Application Requirement Checker</title>
</head>
<body>
<div id="page">
<div id="header">
<h1>Yii Application Requirement Checker</h1>
</div><!-- header-->
<div id="content">
<h2>Description</h2>
<p>
This script checks if your server configuration meets the requirements
for running Yii application.
It checks if the server is running the right version of PHP,
if appropriate PHP extensions have been loaded, and if php.ini file settings are correct.
</p>
<h2>Conclusion</h2>
<p>
<?php if ($summary['errors']>0): ?>
Unfortunately your server configuration does not satisfy the requirements by this application.
<?php elseif ($summary['warnings']>0): ?>
Your server configuration satisfies the minimum requirements by this application. Please pay attention to the warnings listed below if your application will use the corresponding features.
<?php else: ?>
Congratulations! Your server configuration satisfies all requirements.
<?php endif; ?>
</p>
<h2>Details</h2>
<table class="result">
<tr><th>Name</th><th>Result</th><th>Required By</th><th>Memo</th></tr>
<?php foreach($requirements as $requirement): ?>
<tr>
<td>
<?php echo $requirement['name']; ?>
</td>
<td class="<?php echo $requirement['condition'] ? 'passed' : ($requirement['mandatory'] ? 'failed' : 'warning'); ?>">
<?php echo $requirement['condition'] ? 'Passed' : ($requirement['mandatory'] ? 'Failed' : 'Warning'); ?>
</td>
<td>
<?php echo $requirement['by']; ?>
</td>
<td>
<?php echo $requirement['memo']; ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<table>
<tr>
<td class="passed">&nbsp;</td><td>passed</td>
<td class="failed">&nbsp;</td><td>failed</td>
<td class="warning">&nbsp;</td><td>warning</td>
</tr>
</table>
</div><!-- content -->
<div id="footer">
<?php echo $this->getServerInfo().' '.$this->getNowDate(); ?>
</div><!-- footer -->
</div><!-- page -->
</body>
</html>

2
yii/web/Pagination.php

@ -47,7 +47,7 @@ use Yii;
* } * }
* *
* // display pagination * // display pagination
* $this->widget('yii\widgets\LinkPager', array( * LinkPager::widget($this, array(
* 'pages' => $pages, * 'pages' => $pages,
* )); * ));
* ~~~ * ~~~

12
yii/widgets/Breadcrumbs.php

@ -19,10 +19,11 @@ use yii\helpers\Html;
* for the "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home" * for the "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home"
* to return to the homepage. * to return to the homepage.
* *
* To use Breadcrumbs, you need to configure its [[links]] property, which specifiesthe links to be displayed. For example, * To use Breadcrumbs, you need to configure its [[links]] property, which specifies the links to be displayed. For example,
* *
* ~~~ * ~~~
* $this->widget('yii\widgets\Breadcrumbs', array( * // $this is the view object currently being used
* echo Breadcrumbs::widget($this, array(
* 'links' => array( * 'links' => array(
* array('label' => 'Sample Post', 'url' => array('post/edit', 'id' => 1)), * array('label' => 'Sample Post', 'url' => array('post/edit', 'id' => 1)),
* 'Edit', * 'Edit',
@ -30,12 +31,13 @@ use yii\helpers\Html;
* )); * ));
* ~~~ * ~~~
* *
* Because breadcrumbs usually appears in nearly every page of a website, you may consider place it in a layout view. * Because breadcrumbs usually appears in nearly every page of a website, you may consider placing it in a layout view.
* You can then use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different * You can use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different
* views. In the layout view, you assign this view parameter to the [[links]] property like the following: * views. In the layout view, you assign this view parameter to the [[links]] property like the following:
* *
* ~~~ * ~~~
* $this->widget('yii\widgets\Breadcrumbs', array( * // $this is the view object currently being used
* echo Breadcrumbs::widget($this, array(
* 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), * 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
* )); * ));
* ~~~ * ~~~

5
yii/widgets/Menu.php

@ -26,10 +26,11 @@ use yii\helpers\Html;
* The following example shows how to use Menu: * The following example shows how to use Menu:
* *
* ~~~ * ~~~
* $this->widget('yii\widgets\Menu', array( * // $this is the view object currently being used
* echo Menu::widget($this, array(
* 'items' => array( * 'items' => array(
* // Important: you need to specify url as 'controller/action', * // Important: you need to specify url as 'controller/action',
* // not just as 'controller' even if default acion is used. * // not just as 'controller' even if default action is used.
* array('label' => 'Home', 'url' => array('site/index')), * array('label' => 'Home', 'url' => array('site/index')),
* // 'Products' menu item will be selected as long as the route is 'product/index' * // 'Products' menu item will be selected as long as the route is 'product/index'
* array('label' => 'Products', 'url' => array('product/index'), 'items' => array( * array('label' => 'Products', 'url' => array('product/index'), 'items' => array(

Loading…
Cancel
Save