Rinat Silnov
12 years ago
130 changed files with 7888 additions and 2353 deletions
@ -0,0 +1,29 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace app\commands; |
||||
use yii\console\Controller; |
||||
|
||||
/** |
||||
* This command echos what the first argument that you have entered. |
||||
* |
||||
* This command is provided as an example for you to learn how to create console commands. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class HelloController extends Controller |
||||
{ |
||||
/** |
||||
* This command echos what you have entered as the message. |
||||
* @param string $message the message to be echoed. |
||||
*/ |
||||
public function actionIndex($message = 'hello world') |
||||
{ |
||||
echo $message; |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
<?php |
||||
|
||||
return array( |
||||
'id' => 'bootstrap-console', |
||||
'basePath' => dirname(__DIR__), |
||||
'preload' => array('log'), |
||||
'controllerPath' => dirname(__DIR__) . '/commands', |
||||
'controllerNamespace' => 'app\commands', |
||||
'modules' => array( |
||||
), |
||||
'components' => array( |
||||
'cache' => array( |
||||
'class' => 'yii\caching\FileCache', |
||||
), |
||||
'log' => array( |
||||
'class' => 'yii\logging\Router', |
||||
'targets' => array( |
||||
array( |
||||
'class' => 'yii\logging\FileTarget', |
||||
'levels' => array('error', 'warning'), |
||||
), |
||||
), |
||||
), |
||||
), |
||||
'params' => require(__DIR__ . '/params.php'), |
||||
); |
@ -0,0 +1,5 @@
|
||||
<?php |
||||
|
||||
return array( |
||||
'adminEmail' => 'admin@example.com', |
||||
); |
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env php |
||||
<?php |
||||
/** |
||||
* Yii console bootstrap file. |
||||
* |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
|
||||
// fcgi doesn't have STDIN defined by default |
||||
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); |
||||
|
||||
$frameworkPath = __DIR__ . '/../../../yii'; |
||||
|
||||
require($frameworkPath . '/Yii.php'); |
||||
|
||||
$config = require(__DIR__ . '/config/console.php'); |
||||
|
||||
$application = new yii\console\Application($config); |
||||
$application->run(); |
@ -1,209 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\base; |
||||
|
||||
use yii\base\Dictionary; |
||||
|
||||
class MapItem |
||||
{ |
||||
public $data='data'; |
||||
} |
||||
|
||||
class DictionaryTest extends \yiiunit\TestCase |
||||
{ |
||||
/** |
||||
* @var \yii\base\Dictionary |
||||
*/ |
||||
protected $dictionary; |
||||
protected $item1; |
||||
protected $item2; |
||||
protected $item3; |
||||
|
||||
protected function setUp() |
||||
{ |
||||
parent::setUp(); |
||||
$this->dictionary = new Dictionary; |
||||
$this->item1 = new MapItem; |
||||
$this->item2 = new MapItem; |
||||
$this->item3 = new MapItem; |
||||
$this->dictionary->add('key1', $this->item1); |
||||
$this->dictionary->add('key2', $this->item2); |
||||
} |
||||
|
||||
protected function tearDown() |
||||
{ |
||||
parent::tearDown(); |
||||
$this->dictionary = null; |
||||
$this->item1 = null; |
||||
$this->item2 = null; |
||||
$this->item3 = null; |
||||
} |
||||
|
||||
public function testConstruct() |
||||
{ |
||||
$a = array(1, 2, 'key3' => 3); |
||||
$dictionary = new Dictionary($a); |
||||
$this->assertEquals(3, $dictionary->getCount()); |
||||
$dictionary2=new Dictionary($this->dictionary); |
||||
$this->assertEquals(2, $dictionary2->getCount()); |
||||
} |
||||
|
||||
public function testGetCount() |
||||
{ |
||||
$this->assertEquals(2, $this->dictionary->getCount()); |
||||
} |
||||
|
||||
public function testGetKeys() |
||||
{ |
||||
$keys = $this->dictionary->getKeys(); |
||||
$this->assertEquals(2, count($keys)); |
||||
$this->assertEquals('key1', $keys[0]); |
||||
$this->assertEquals('key2', $keys[1]); |
||||
} |
||||
|
||||
public function testAdd() |
||||
{ |
||||
$this->dictionary->add('key3', $this->item3); |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertTrue($this->dictionary->has('key3')); |
||||
|
||||
$this->dictionary[] = 'test'; |
||||
} |
||||
|
||||
public function testRemove() |
||||
{ |
||||
$this->dictionary->remove('key1'); |
||||
$this->assertEquals(1, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key1')); |
||||
$this->assertTrue($this->dictionary->remove('unknown key') === null); |
||||
} |
||||
|
||||
public function testRemoveAll() |
||||
{ |
||||
$this->dictionary->add('key3', $this->item3); |
||||
$this->dictionary->removeAll(); |
||||
$this->assertEquals(0, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2')); |
||||
|
||||
$this->dictionary->add('key3', $this->item3); |
||||
$this->dictionary->removeAll(true); |
||||
$this->assertEquals(0, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2')); |
||||
} |
||||
|
||||
public function testHas() |
||||
{ |
||||
$this->assertTrue($this->dictionary->has('key1')); |
||||
$this->assertTrue($this->dictionary->has('key2')); |
||||
$this->assertFalse($this->dictionary->has('key3')); |
||||
} |
||||
|
||||
public function testFromArray() |
||||
{ |
||||
$array = array('key3' => $this->item3, 'key4' => $this->item1); |
||||
$this->dictionary->copyFrom($array); |
||||
|
||||
$this->assertEquals(2, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item3, $this->dictionary['key3']); |
||||
$this->assertEquals($this->item1, $this->dictionary['key4']); |
||||
|
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->dictionary->copyFrom($this); |
||||
} |
||||
|
||||
public function testMergeWith() |
||||
{ |
||||
$a = array('a' => 'v1', 'v2', array('2'), 'c' => array('3', 'c' => 'a')); |
||||
$b = array('v22', 'a' => 'v11', array('2'), 'c' => array('c' => '3', 'a')); |
||||
$c = array('a' => 'v11', 'v2', array('2'), 'c' => array('3', 'c' => '3', 'a'), 'v22', array('2')); |
||||
$dictionary = new Dictionary($a); |
||||
$dictionary2 = new Dictionary($b); |
||||
$dictionary->mergeWith($dictionary2); |
||||
$this->assertTrue($dictionary->toArray() === $c); |
||||
|
||||
$array = array('key2' => $this->item1, 'key3' => $this->item3); |
||||
$this->dictionary->mergeWith($array, false); |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item1, $this->dictionary['key2']); |
||||
$this->assertEquals($this->item3, $this->dictionary['key3']); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->dictionary->mergeWith($this, false); |
||||
} |
||||
|
||||
public function testRecursiveMergeWithTraversable(){ |
||||
$dictionary = new Dictionary(); |
||||
$obj = new \ArrayObject(array( |
||||
'k1' => $this->item1, |
||||
'k2' => $this->item2, |
||||
'k3' => new \ArrayObject(array( |
||||
'k4' => $this->item3, |
||||
)) |
||||
)); |
||||
$dictionary->mergeWith($obj, true); |
||||
|
||||
$this->assertEquals(3, $dictionary->getCount()); |
||||
$this->assertEquals($this->item1, $dictionary['k1']); |
||||
$this->assertEquals($this->item2, $dictionary['k2']); |
||||
$this->assertEquals($this->item3, $dictionary['k3']['k4']); |
||||
} |
||||
|
||||
public function testArrayRead() |
||||
{ |
||||
$this->assertEquals($this->item1, $this->dictionary['key1']); |
||||
$this->assertEquals($this->item2, $this->dictionary['key2']); |
||||
$this->assertEquals(null, $this->dictionary['key3']); |
||||
} |
||||
|
||||
public function testArrayWrite() |
||||
{ |
||||
$this->dictionary['key3'] = $this->item3; |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item3, $this->dictionary['key3']); |
||||
|
||||
$this->dictionary['key1'] = $this->item3; |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item3, $this->dictionary['key1']); |
||||
|
||||
unset($this->dictionary['key2']); |
||||
$this->assertEquals(2, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key2')); |
||||
|
||||
unset($this->dictionary['unknown key']); |
||||
} |
||||
|
||||
public function testArrayForeach() |
||||
{ |
||||
$n = 0; |
||||
$found = 0; |
||||
foreach ($this->dictionary as $index => $item) { |
||||
$n++; |
||||
if ($index === 'key1' && $item === $this->item1) { |
||||
$found++; |
||||
} |
||||
if ($index === 'key2' && $item === $this->item2) { |
||||
$found++; |
||||
} |
||||
} |
||||
$this->assertTrue($n == 2 && $found == 2); |
||||
} |
||||
|
||||
public function testArrayMisc() |
||||
{ |
||||
$this->assertEquals($this->dictionary->Count, count($this->dictionary)); |
||||
$this->assertTrue(isset($this->dictionary['key1'])); |
||||
$this->assertFalse(isset($this->dictionary['unknown key'])); |
||||
} |
||||
|
||||
public function testToArray() |
||||
{ |
||||
$dictionary = new Dictionary(array('key' => 'value')); |
||||
$this->assertEquals(array('key' => 'value'), $dictionary->toArray()); |
||||
} |
||||
|
||||
public function testIteratorCurrent() |
||||
{ |
||||
$dictionary = new Dictionary(array('key1' => 'value1', 'key2' => 'value2')); |
||||
$val = $dictionary->getIterator()->current(); |
||||
$this->assertEquals('value1', $val); |
||||
} |
||||
} |
@ -1,230 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\base; |
||||
|
||||
use yii\base\Vector; |
||||
|
||||
class ListItem |
||||
{ |
||||
public $data='data'; |
||||
} |
||||
|
||||
class VectorTest extends \yiiunit\TestCase |
||||
{ |
||||
/** |
||||
* @var Vector |
||||
*/ |
||||
protected $vector; |
||||
protected $item1; |
||||
protected $item2; |
||||
protected $item3; |
||||
|
||||
protected function setUp() |
||||
{ |
||||
parent::setUp(); |
||||
$this->vector = new Vector; |
||||
$this->item1 = new ListItem; |
||||
$this->item2 = new ListItem; |
||||
$this->item3 = new ListItem; |
||||
$this->vector->add($this->item1); |
||||
$this->vector->add($this->item2); |
||||
} |
||||
|
||||
protected function tearDown() |
||||
{ |
||||
parent::tearDown(); |
||||
$this->vector = null; |
||||
$this->item1 = null; |
||||
$this->item2 = null; |
||||
$this->item3 = null; |
||||
} |
||||
|
||||
public function testConstruct() |
||||
{ |
||||
$a = array(1, 2, 3); |
||||
$vector = new Vector($a); |
||||
$this->assertEquals(3, $vector->getCount()); |
||||
$vector2 = new Vector($this->vector); |
||||
$this->assertEquals(2, $vector2->getCount()); |
||||
} |
||||
|
||||
public function testItemAt() |
||||
{ |
||||
$a = array(1, 2, null, 4); |
||||
$vector = new Vector($a); |
||||
$this->assertEquals(1, $vector->itemAt(0)); |
||||
$this->assertEquals(2, $vector->itemAt(1)); |
||||
$this->assertNull($vector->itemAt(2)); |
||||
$this->assertEquals(4, $vector->itemAt(3)); |
||||
} |
||||
|
||||
public function testGetCount() |
||||
{ |
||||
$this->assertEquals(2, $this->vector->getCount()); |
||||
$this->assertEquals(2, $this->vector->Count); |
||||
} |
||||
|
||||
public function testAdd() |
||||
{ |
||||
$this->vector->add(null); |
||||
$this->vector->add($this->item3); |
||||
$this->assertEquals(4, $this->vector->getCount()); |
||||
$this->assertEquals(3, $this->vector->indexOf($this->item3)); |
||||
} |
||||
|
||||
public function testInsertAt() |
||||
{ |
||||
$this->vector->insertAt(0, $this->item3); |
||||
$this->assertEquals(3, $this->vector->getCount()); |
||||
$this->assertEquals(2, $this->vector->indexOf($this->item2)); |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item3)); |
||||
$this->assertEquals(1, $this->vector->indexOf($this->item1)); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->insertAt(4, $this->item3); |
||||
} |
||||
|
||||
public function testRemove() |
||||
{ |
||||
$this->vector->remove($this->item1); |
||||
$this->assertEquals(1, $this->vector->getCount()); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item2)); |
||||
|
||||
$this->assertEquals(false, $this->vector->remove($this->item1)); |
||||
|
||||
} |
||||
|
||||
public function testRemoveAt() |
||||
{ |
||||
$this->vector->add($this->item3); |
||||
$this->vector->removeAt(1); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item2)); |
||||
$this->assertEquals(1, $this->vector->indexOf($this->item3)); |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item1)); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->removeAt(2); |
||||
} |
||||
|
||||
public function testRemoveAll() |
||||
{ |
||||
$this->vector->add($this->item3); |
||||
$this->vector->removeAll(); |
||||
$this->assertEquals(0, $this->vector->getCount()); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item2)); |
||||
|
||||
$this->vector->add($this->item3); |
||||
$this->vector->removeAll(true); |
||||
$this->assertEquals(0, $this->vector->getCount()); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item2)); |
||||
} |
||||
|
||||
public function testHas() |
||||
{ |
||||
$this->assertTrue($this->vector->has($this->item1)); |
||||
$this->assertTrue($this->vector->has($this->item2)); |
||||
$this->assertFalse($this->vector->has($this->item3)); |
||||
} |
||||
|
||||
public function testIndexOf() |
||||
{ |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(1, $this->vector->indexOf($this->item2)); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item3)); |
||||
} |
||||
|
||||
public function testFromArray() |
||||
{ |
||||
$array = array($this->item3, $this->item1); |
||||
$this->vector->copyFrom($array); |
||||
$this->assertTrue(count($array) == 2 && $this->vector[0] === $this->item3 && $this->vector[1] === $this->item1); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->copyFrom($this); |
||||
} |
||||
|
||||
public function testMergeWith() |
||||
{ |
||||
$array = array($this->item3, $this->item1); |
||||
$this->vector->mergeWith($array); |
||||
$this->assertTrue($this->vector->getCount() == 4 && $this->vector[0] === $this->item1 && |
||||
$this->vector[3] === $this->item1); |
||||
|
||||
$a = array(1); |
||||
$vector = new Vector($a); |
||||
$this->vector->mergeWith($vector); |
||||
$this->assertTrue($this->vector->getCount() == 5 && $this->vector[0] === $this->item1 && |
||||
$this->vector[3] === $this->item1 && $this->vector[4] === 1); |
||||
|
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->mergeWith($this); |
||||
} |
||||
|
||||
public function testToArray() |
||||
{ |
||||
$array = $this->vector->toArray(); |
||||
$this->assertTrue(count($array) == 2 && $array[0] === $this->item1 && $array[1] === $this->item2); |
||||
} |
||||
|
||||
public function testArrayRead() |
||||
{ |
||||
$this->assertTrue($this->vector[0] === $this->item1); |
||||
$this->assertTrue($this->vector[1] === $this->item2); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$a = $this->vector[2]; |
||||
} |
||||
|
||||
public function testGetIterator() |
||||
{ |
||||
$n = 0; |
||||
$found = 0; |
||||
foreach ($this->vector as $index => $item) { |
||||
foreach ($this->vector as $a => $b) { |
||||
// test of iterator |
||||
} |
||||
$n++; |
||||
if ($index === 0 && $item === $this->item1) { |
||||
$found++; |
||||
} |
||||
if ($index === 1 && $item === $this->item2) { |
||||
$found++; |
||||
} |
||||
} |
||||
$this->assertTrue($n == 2 && $found == 2); |
||||
} |
||||
|
||||
public function testArrayMisc() |
||||
{ |
||||
$this->assertEquals($this->vector->Count, count($this->vector)); |
||||
$this->assertTrue(isset($this->vector[1])); |
||||
$this->assertFalse(isset($this->vector[2])); |
||||
} |
||||
|
||||
public function testOffsetSetAdd() |
||||
{ |
||||
$vector = new Vector(array(1, 2, 3)); |
||||
$vector->offsetSet(null, 4); |
||||
$this->assertEquals(array(1, 2, 3, 4), $vector->toArray()); |
||||
} |
||||
|
||||
public function testOffsetSetReplace() |
||||
{ |
||||
$vector = new Vector(array(1, 2, 3)); |
||||
$vector->offsetSet(1, 4); |
||||
$this->assertEquals(array(1, 4, 3), $vector->toArray()); |
||||
} |
||||
|
||||
public function testOffsetUnset() |
||||
{ |
||||
$vector = new Vector(array(1, 2, 3)); |
||||
$vector->offsetUnset(1); |
||||
$this->assertEquals(array(1, 3), $vector->toArray()); |
||||
} |
||||
|
||||
public function testIteratorCurrent() |
||||
{ |
||||
$vector = new Vector(array('value1', 'value2')); |
||||
$val = $vector->getIterator()->current(); |
||||
$this->assertEquals('value1', $val); |
||||
} |
||||
} |
@ -0,0 +1,86 @@
|
||||
<?php |
||||
|
||||
namespace yii\web; |
||||
|
||||
use yiiunit\framework\web\ResponseTest; |
||||
|
||||
/** |
||||
* Mock PHP header function to check for sent headers |
||||
* @param string $string |
||||
* @param bool $replace |
||||
* @param int $httpResponseCode |
||||
*/ |
||||
function header($string, $replace = true, $httpResponseCode = null) { |
||||
ResponseTest::$headers[] = $string; |
||||
// TODO implement replace |
||||
|
||||
if ($httpResponseCode !== null) { |
||||
ResponseTest::$httpResponseCode = $httpResponseCode; |
||||
} |
||||
} |
||||
|
||||
namespace yiiunit\framework\web; |
||||
|
||||
use yii\helpers\StringHelper; |
||||
use yii\web\Response; |
||||
|
||||
class ResponseTest extends \yiiunit\TestCase |
||||
{ |
||||
public static $headers = array(); |
||||
public static $httpResponseCode = 200; |
||||
|
||||
protected function setUp() |
||||
{ |
||||
parent::setUp(); |
||||
$this->reset(); |
||||
} |
||||
|
||||
protected function reset() |
||||
{ |
||||
static::$headers = array(); |
||||
static::$httpResponseCode = 200; |
||||
} |
||||
|
||||
public function ranges() |
||||
{ |
||||
// TODO test more cases for range requests and check for rfc compatibility |
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616.txt |
||||
return array( |
||||
array('0-5', '0-5', 6, '12ёж'), |
||||
array('2-', '2-66', 65, 'ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'), |
||||
array('-12', '55-66', 12, '(ёжик)=?'), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @dataProvider ranges |
||||
*/ |
||||
public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedFile) |
||||
{ |
||||
$content = $this->generateTestFileContent(); |
||||
|
||||
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; |
||||
$sent = $this->runSendFile('testFile.txt', $content, null); |
||||
$this->assertEquals($expectedFile, $sent); |
||||
$this->assertTrue(in_array('HTTP/1.1 206 Partial Content', static::$headers)); |
||||
$this->assertTrue(in_array('Accept-Ranges: bytes', static::$headers)); |
||||
$this->assertArrayHasKey('Content-Range: bytes ' . $expectedHeader . '/' . StringHelper::strlen($content), array_flip(static::$headers)); |
||||
$this->assertTrue(in_array('Content-Type: text/plain', static::$headers)); |
||||
$this->assertTrue(in_array('Content-Length: ' . $length, static::$headers)); |
||||
} |
||||
|
||||
protected function generateTestFileContent() |
||||
{ |
||||
return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'; |
||||
} |
||||
|
||||
protected function runSendFile($fileName, $content, $mimeType) |
||||
{ |
||||
ob_start(); |
||||
ob_implicit_flush(false); |
||||
$response = new Response(); |
||||
$response->sendFile($fileName, $content, $mimeType, false); |
||||
$file = ob_get_clean(); |
||||
return $file; |
||||
} |
||||
} |
@ -1,297 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
use yii\helpers\ArrayHelper; |
||||
|
||||
/** |
||||
* Dictionary implements a collection that stores key-value pairs. |
||||
* |
||||
* You can access, add or remove an item with a key by using |
||||
* [[itemAt()]], [[add()]], and [[remove()]]. |
||||
* |
||||
* To get the number of the items in the dictionary, use [[getCount()]]. |
||||
* |
||||
* Because Dictionary implements a set of SPL interfaces, it can be used |
||||
* like a regular PHP array as follows, |
||||
* |
||||
* ~~~ |
||||
* $dictionary[$key] = $value; // add a key-value pair |
||||
* unset($dictionary[$key]); // remove the value with the specified key |
||||
* if (isset($dictionary[$key])) // if the dictionary contains the key |
||||
* foreach ($dictionary as $key => $value) // traverse the items in the dictionary |
||||
* $n = count($dictionary); // returns the number of items in the dictionary |
||||
* ~~~ |
||||
* |
||||
* @property integer $count the number of items in the dictionary |
||||
* @property array $keys The keys in the dictionary |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Countable |
||||
{ |
||||
/** |
||||
* @var array internal data storage |
||||
*/ |
||||
private $_d = array(); |
||||
|
||||
/** |
||||
* Constructor. |
||||
* Initializes the dictionary with an array or an iterable object. |
||||
* @param mixed $data the initial data to be populated into the dictionary. |
||||
* This can be an array or an iterable object. |
||||
* @param array $config name-value pairs that will be used to initialize the object properties |
||||
* @throws Exception if data is not well formed (neither an array nor an iterable object) |
||||
*/ |
||||
public function __construct($data = array(), $config = array()) |
||||
{ |
||||
if (!empty($data)) { |
||||
$this->copyFrom($data); |
||||
} |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* Returns an iterator for traversing the items in the dictionary. |
||||
* This method is required by the SPL interface `IteratorAggregate`. |
||||
* It will be implicitly called when you use `foreach` to traverse the dictionary. |
||||
* @return DictionaryIterator an iterator for traversing the items in the dictionary. |
||||
*/ |
||||
public function getIterator() |
||||
{ |
||||
return new DictionaryIterator($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of items in the dictionary. |
||||
* This method is required by the SPL `Countable` interface. |
||||
* It will be implicitly called when you use `count($dictionary)`. |
||||
* @return integer number of items in the dictionary. |
||||
*/ |
||||
public function count() |
||||
{ |
||||
return $this->getCount(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of items in the dictionary. |
||||
* @return integer the number of items in the dictionary |
||||
*/ |
||||
public function getCount() |
||||
{ |
||||
return count($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the keys stored in the dictionary. |
||||
* @return array the key list |
||||
*/ |
||||
public function getKeys() |
||||
{ |
||||
return array_keys($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the item with the specified key. |
||||
* @param mixed $key the key |
||||
* @return mixed the element with the specified key. |
||||
* Null if the key cannot be found in the dictionary. |
||||
*/ |
||||
public function itemAt($key) |
||||
{ |
||||
return isset($this->_d[$key]) ? $this->_d[$key] : null; |
||||
} |
||||
|
||||
/** |
||||
* Adds an item into the dictionary. |
||||
* Note, if the specified key already exists, the old value will be overwritten. |
||||
* @param mixed $key key |
||||
* @param mixed $value value |
||||
* @throws Exception if the dictionary is read-only |
||||
*/ |
||||
public function add($key, $value) |
||||
{ |
||||
if ($key === null) { |
||||
$this->_d[] = $value; |
||||
} else { |
||||
$this->_d[$key] = $value; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes an item from the dictionary by its key. |
||||
* @param mixed $key the key of the item to be removed |
||||
* @return mixed the removed value, null if no such key exists. |
||||
* @throws Exception if the dictionary is read-only |
||||
*/ |
||||
public function remove($key) |
||||
{ |
||||
if (isset($this->_d[$key])) { |
||||
$value = $this->_d[$key]; |
||||
unset($this->_d[$key]); |
||||
return $value; |
||||
} else { // the value is null |
||||
unset($this->_d[$key]); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes all items from the dictionary. |
||||
* @param boolean $safeClear whether to clear every item by calling [[remove]]. |
||||
* Defaults to false, meaning all items in the dictionary will be cleared directly |
||||
* without calling [[remove]]. |
||||
*/ |
||||
public function removeAll($safeClear = false) |
||||
{ |
||||
if ($safeClear) { |
||||
foreach (array_keys($this->_d) as $key) { |
||||
$this->remove($key); |
||||
} |
||||
} else { |
||||
$this->_d = array(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a value indicating whether the dictionary contains the specified key. |
||||
* @param mixed $key the key |
||||
* @return boolean whether the dictionary contains an item with the specified key |
||||
*/ |
||||
public function has($key) |
||||
{ |
||||
return isset($this->_d[$key]) || array_key_exists($key, $this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the dictionary as a PHP array. |
||||
* @return array the list of items in array |
||||
*/ |
||||
public function toArray() |
||||
{ |
||||
return $this->_d; |
||||
} |
||||
|
||||
/** |
||||
* Copies iterable data into the dictionary. |
||||
* Note, existing data in the dictionary will be cleared first. |
||||
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable` |
||||
* @throws InvalidParamException if data is neither an array nor an iterator. |
||||
*/ |
||||
public function copyFrom($data) |
||||
{ |
||||
if (is_array($data) || $data instanceof \Traversable) { |
||||
if (!empty($this->_d)) { |
||||
$this->removeAll(); |
||||
} |
||||
if ($data instanceof self) { |
||||
$data = $data->_d; |
||||
} |
||||
foreach ($data as $key => $value) { |
||||
$this->add($key, $value); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Merges iterable data into the dictionary. |
||||
* |
||||
* Existing elements in the dictionary will be overwritten if their keys are the same as those in the source. |
||||
* If the merge is recursive, the following algorithm is performed: |
||||
* |
||||
* - the dictionary data is saved as $a, and the source data is saved as $b; |
||||
* - if $a and $b both have an array indexed at the same string key, the arrays will be merged using this algorithm; |
||||
* - any integer-indexed elements in $b will be appended to $a; |
||||
* - any string-indexed elements in $b will overwrite elements in $a with the same index; |
||||
* |
||||
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable |
||||
* @param boolean $recursive whether the merging should be recursive. |
||||
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`. |
||||
*/ |
||||
public function mergeWith($data, $recursive = true) |
||||
{ |
||||
if (is_array($data) || $data instanceof \Traversable) { |
||||
if ($data instanceof self) { |
||||
$data = $data->_d; |
||||
} |
||||
if ($recursive) { |
||||
if ($data instanceof \Traversable) { |
||||
$d = array(); |
||||
foreach ($data as $key => $value) { |
||||
$d[$key] = $value; |
||||
} |
||||
$this->_d = ArrayHelper::merge($this->_d, $d); |
||||
} else { |
||||
$this->_d = ArrayHelper::merge($this->_d, $data); |
||||
} |
||||
} else { |
||||
foreach ($data as $key => $value) { |
||||
$this->add($key, $value); |
||||
} |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there is an element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `isset($dictionary[$offset])`. |
||||
* This is equivalent to [[contains]]. |
||||
* @param mixed $offset the offset to check on |
||||
* @return boolean |
||||
*/ |
||||
public function offsetExists($offset) |
||||
{ |
||||
return $this->has($offset); |
||||
} |
||||
|
||||
/** |
||||
* Returns the element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `$value = $dictionary[$offset];`. |
||||
* This is equivalent to [[itemAt]]. |
||||
* @param mixed $offset the offset to retrieve element. |
||||
* @return mixed the element at the offset, null if no element is found at the offset |
||||
*/ |
||||
public function offsetGet($offset) |
||||
{ |
||||
return $this->itemAt($offset); |
||||
} |
||||
|
||||
/** |
||||
* Sets the element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `$dictionary[$offset] = $item;`. |
||||
* If the offset is null, the new item will be appended to the dictionary. |
||||
* Otherwise, the existing item at the offset will be replaced with the new item. |
||||
* This is equivalent to [[add]]. |
||||
* @param mixed $offset the offset to set element |
||||
* @param mixed $item the element value |
||||
*/ |
||||
public function offsetSet($offset, $item) |
||||
{ |
||||
$this->add($offset, $item); |
||||
} |
||||
|
||||
/** |
||||
* Unsets the element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `unset($dictionary[$offset])`. |
||||
* This is equivalent to [[remove]]. |
||||
* @param mixed $offset the offset to unset element |
||||
*/ |
||||
public function offsetUnset($offset) |
||||
{ |
||||
$this->remove($offset); |
||||
} |
||||
} |
@ -1,92 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* DictionaryIterator implements the SPL `Iterator` interface for [[Dictionary]]. |
||||
* |
||||
* It allows [[Dictionary]] to return a new iterator for data traversing purpose. |
||||
* You normally do not use this class directly. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class DictionaryIterator implements \Iterator |
||||
{ |
||||
/** |
||||
* @var array the data to be iterated through |
||||
*/ |
||||
private $_d; |
||||
/** |
||||
* @var array list of keys in the map |
||||
*/ |
||||
private $_keys; |
||||
/** |
||||
* @var mixed current key |
||||
*/ |
||||
private $_key; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param array $data the data to be iterated through |
||||
*/ |
||||
public function __construct(&$data) |
||||
{ |
||||
$this->_d = &$data; |
||||
$this->_keys = array_keys($data); |
||||
$this->_key = reset($this->_keys); |
||||
} |
||||
|
||||
/** |
||||
* Rewinds the index of the current item. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
*/ |
||||
public function rewind() |
||||
{ |
||||
$this->_key = reset($this->_keys); |
||||
} |
||||
|
||||
/** |
||||
* Returns the key of the current array element. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return mixed the key of the current array element |
||||
*/ |
||||
public function key() |
||||
{ |
||||
return $this->_key; |
||||
} |
||||
|
||||
/** |
||||
* Returns the current array element. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return mixed the current array element |
||||
*/ |
||||
public function current() |
||||
{ |
||||
return $this->_d[$this->_key]; |
||||
} |
||||
|
||||
/** |
||||
* Moves the internal pointer to the next element. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
*/ |
||||
public function next() |
||||
{ |
||||
$this->_key = next($this->_keys); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there is an element at current position. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return boolean whether there is an item at current position. |
||||
*/ |
||||
public function valid() |
||||
{ |
||||
return $this->_key !== false; |
||||
} |
||||
} |
@ -1,341 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* Vector implements an integer-indexed collection class. |
||||
* |
||||
* You can access, append, insert, remove an item from the vector |
||||
* by calling methods such as [[itemAt()]], [[add()]], [[insertAt()]], |
||||
* [[remove()]] and [[removeAt()]]. |
||||
* |
||||
* To get the number of the items in the vector, use [[getCount()]]. |
||||
* |
||||
* Because Vector implements a set of SPL interfaces, it can be used |
||||
* like a regular PHP array as follows, |
||||
* |
||||
* ~~~ |
||||
* $vector[] = $item; // append new item at the end |
||||
* $vector[$index] = $item; // set new item at $index |
||||
* unset($vector[$index]); // remove the item at $index |
||||
* if (isset($vector[$index])) // if the vector has an item at $index |
||||
* foreach ($vector as $index => $item) // traverse each item in the vector |
||||
* $n = count($vector); // count the number of items |
||||
* ~~~ |
||||
* |
||||
* Note that if you plan to extend Vector by performing additional operations |
||||
* with each addition or removal of an item (e.g. performing type check), |
||||
* please make sure you override [[insertAt()]] and [[removeAt()]]. |
||||
* |
||||
* @property integer $count the number of items in the vector |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Countable |
||||
{ |
||||
/** |
||||
* @var array internal data storage |
||||
*/ |
||||
private $_d = array(); |
||||
/** |
||||
* @var integer number of items |
||||
*/ |
||||
private $_c = 0; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* Initializes the vector with an array or an iterable object. |
||||
* @param mixed $data the initial data to be populated into the vector. |
||||
* This can be an array or an iterable object. |
||||
* @param array $config name-value pairs that will be used to initialize the object properties |
||||
* @throws Exception if data is not well formed (neither an array nor an iterable object) |
||||
*/ |
||||
public function __construct($data = array(), $config = array()) |
||||
{ |
||||
if (!empty($data)) { |
||||
$this->copyFrom($data); |
||||
} |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* Returns an iterator for traversing the items in the vector. |
||||
* This method is required by the SPL interface `IteratorAggregate`. |
||||
* It will be implicitly called when you use `foreach` to traverse the vector. |
||||
* @return VectorIterator an iterator for traversing the items in the vector. |
||||
*/ |
||||
public function getIterator() |
||||
{ |
||||
return new VectorIterator($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of items in the vector. |
||||
* This method is required by the SPL `Countable` interface. |
||||
* It will be implicitly called when you use `count($vector)`. |
||||
* @return integer number of items in the vector. |
||||
*/ |
||||
public function count() |
||||
{ |
||||
return $this->getCount(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of items in the vector. |
||||
* @return integer the number of items in the vector |
||||
*/ |
||||
public function getCount() |
||||
{ |
||||
return $this->_c; |
||||
} |
||||
|
||||
/** |
||||
* Returns the item at the specified index. |
||||
* @param integer $index the index of the item |
||||
* @return mixed the item at the index |
||||
* @throws InvalidParamException if the index is out of range |
||||
*/ |
||||
public function itemAt($index) |
||||
{ |
||||
if (isset($this->_d[$index])) { |
||||
return $this->_d[$index]; |
||||
} elseif ($index >= 0 && $index < $this->_c) { // in case the value is null |
||||
return $this->_d[$index]; |
||||
} else { |
||||
throw new InvalidParamException('Index out of range: ' . $index); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Appends an item at the end of the vector. |
||||
* @param mixed $item new item |
||||
* @return integer the zero-based index at which the item is added |
||||
* @throws Exception if the vector is read-only. |
||||
*/ |
||||
public function add($item) |
||||
{ |
||||
$this->insertAt($this->_c, $item); |
||||
return $this->_c - 1; |
||||
} |
||||
|
||||
/** |
||||
* Inserts an item at the specified position. |
||||
* Original item at the position and the following items will be moved |
||||
* one step towards the end. |
||||
* @param integer $index the specified position. |
||||
* @param mixed $item new item to be inserted into the vector |
||||
* @throws InvalidParamException if the index specified is out of range, or the vector is read-only. |
||||
*/ |
||||
public function insertAt($index, $item) |
||||
{ |
||||
if ($index === $this->_c) { |
||||
$this->_d[$this->_c++] = $item; |
||||
} elseif ($index >= 0 && $index < $this->_c) { |
||||
array_splice($this->_d, $index, 0, array($item)); |
||||
$this->_c++; |
||||
} else { |
||||
throw new InvalidParamException('Index out of range: ' . $index); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes an item from the vector. |
||||
* The vector will search for the item, and the first item found |
||||
* will be removed from the vector. |
||||
* @param mixed $item the item to be removed. |
||||
* @return mixed the index at which the item is being removed, or false |
||||
* if the item cannot be found in the vector. |
||||
* @throws Exception if the vector is read only. |
||||
*/ |
||||
public function remove($item) |
||||
{ |
||||
if (($index = $this->indexOf($item)) >= 0) { |
||||
$this->removeAt($index); |
||||
return $index; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes an item at the specified position. |
||||
* @param integer $index the index of the item to be removed. |
||||
* @return mixed the removed item. |
||||
* @throws InvalidParamException if the index is out of range, or the vector is read only. |
||||
*/ |
||||
public function removeAt($index) |
||||
{ |
||||
if ($index >= 0 && $index < $this->_c) { |
||||
$this->_c--; |
||||
if ($index === $this->_c) { |
||||
return array_pop($this->_d); |
||||
} else { |
||||
$item = $this->_d[$index]; |
||||
array_splice($this->_d, $index, 1); |
||||
return $item; |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('Index out of range: ' . $index); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes all items from the vector. |
||||
* @param boolean $safeClear whether to clear every item by calling [[removeAt]]. |
||||
* Defaults to false, meaning all items in the vector will be cleared directly |
||||
* without calling [[removeAt]]. |
||||
*/ |
||||
public function removeAll($safeClear = false) |
||||
{ |
||||
if ($safeClear) { |
||||
for ($i = $this->_c - 1; $i >= 0; --$i) { |
||||
$this->removeAt($i); |
||||
} |
||||
} else { |
||||
$this->_d = array(); |
||||
$this->_c = 0; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a value indicating whether the vector contains the specified item. |
||||
* Note that the search is based on strict PHP comparison. |
||||
* @param mixed $item the item |
||||
* @return boolean whether the vector contains the item |
||||
*/ |
||||
public function has($item) |
||||
{ |
||||
return $this->indexOf($item) >= 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns the index of the specified item in the vector. |
||||
* The index is zero-based. If the item is not found in the vector, -1 will be returned. |
||||
* Note that the search is based on strict PHP comparison. |
||||
* @param mixed $item the item |
||||
* @return integer the index of the item in the vector (0 based), -1 if not found. |
||||
*/ |
||||
public function indexOf($item) |
||||
{ |
||||
$index = array_search($item, $this->_d, true); |
||||
return $index === false ? -1 : $index; |
||||
} |
||||
|
||||
/** |
||||
* Returns the vector as a PHP array. |
||||
* @return array the items in the vector. |
||||
*/ |
||||
public function toArray() |
||||
{ |
||||
return $this->_d; |
||||
} |
||||
|
||||
/** |
||||
* Copies iterable data into the vector. |
||||
* Note, existing data in the vector will be cleared first. |
||||
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable` |
||||
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`. |
||||
*/ |
||||
public function copyFrom($data) |
||||
{ |
||||
if (is_array($data) || $data instanceof \Traversable) { |
||||
if ($this->_c > 0) { |
||||
$this->removeAll(); |
||||
} |
||||
if ($data instanceof self) { |
||||
$data = $data->_d; |
||||
} |
||||
foreach ($data as $item) { |
||||
$this->add($item); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Merges iterable data into the vector. |
||||
* New items will be appended to the end of the existing items. |
||||
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable |
||||
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`. |
||||
*/ |
||||
public function mergeWith($data) |
||||
{ |
||||
if (is_array($data) || ($data instanceof \Traversable)) { |
||||
if ($data instanceof Vector) { |
||||
$data = $data->_d; |
||||
} |
||||
foreach ($data as $item) { |
||||
$this->add($item); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a value indicating whether there is an item at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `isset($vector[$offset])`. |
||||
* @param integer $offset the offset to be checked |
||||
* @return boolean whether there is an item at the specified offset. |
||||
*/ |
||||
public function offsetExists($offset) |
||||
{ |
||||
return $offset >= 0 && $offset < $this->_c; |
||||
} |
||||
|
||||
/** |
||||
* Returns the item at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `$value = $vector[$offset];`. |
||||
* This is equivalent to [[itemAt]]. |
||||
* @param integer $offset the offset to retrieve item. |
||||
* @return mixed the item at the offset |
||||
* @throws Exception if the offset is out of range |
||||
*/ |
||||
public function offsetGet($offset) |
||||
{ |
||||
return $this->itemAt($offset); |
||||
} |
||||
|
||||
/** |
||||
* Sets the item at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `$vector[$offset] = $item;`. |
||||
* If the offset is null or equal to the number of the existing items, |
||||
* the new item will be appended to the vector. |
||||
* Otherwise, the existing item at the offset will be replaced with the new item. |
||||
* @param integer $offset the offset to set item |
||||
* @param mixed $item the item value |
||||
* @throws Exception if the offset is out of range, or the vector is read only. |
||||
*/ |
||||
public function offsetSet($offset, $item) |
||||
{ |
||||
if ($offset === null || $offset === $this->_c) { |
||||
$this->insertAt($this->_c, $item); |
||||
} else { |
||||
$this->removeAt($offset); |
||||
$this->insertAt($offset, $item); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Unsets the item at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `unset($vector[$offset])`. |
||||
* This is equivalent to [[removeAt]]. |
||||
* @param integer $offset the offset to unset item |
||||
* @throws Exception if the offset is out of range, or the vector is read only. |
||||
*/ |
||||
public function offsetUnset($offset) |
||||
{ |
||||
$this->removeAt($offset); |
||||
} |
||||
} |
@ -1,92 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* VectorIterator implements the SPL `Iterator` interface for [[Vector]]. |
||||
* |
||||
* It allows [[Vector]] to return a new iterator for data traversing purpose. |
||||
* You normally do not use this class directly. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class VectorIterator implements \Iterator |
||||
{ |
||||
/** |
||||
* @var array the data to be iterated through |
||||
*/ |
||||
private $_d; |
||||
/** |
||||
* @var integer index of the current item |
||||
*/ |
||||
private $_i; |
||||
/** |
||||
* @var integer count of the data items |
||||
*/ |
||||
private $_c; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param array $data the data to be iterated through |
||||
*/ |
||||
public function __construct(&$data) |
||||
{ |
||||
$this->_d = &$data; |
||||
$this->_i = 0; |
||||
$this->_c = count($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Rewinds the index of the current item. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
*/ |
||||
public function rewind() |
||||
{ |
||||
$this->_i = 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns the key of the current item. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return integer the key of the current item |
||||
*/ |
||||
public function key() |
||||
{ |
||||
return $this->_i; |
||||
} |
||||
|
||||
/** |
||||
* Returns the current item. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return mixed the current item |
||||
*/ |
||||
public function current() |
||||
{ |
||||
return $this->_d[$this->_i]; |
||||
} |
||||
|
||||
/** |
||||
* Moves the internal pointer to the next item. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
*/ |
||||
public function next() |
||||
{ |
||||
$this->_i++; |
||||
} |
||||
|
||||
/** |
||||
* Returns a value indicating whether there is an item at current position. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return boolean whether there is an item at current position. |
||||
*/ |
||||
public function valid() |
||||
{ |
||||
return $this->_i < $this->_c; |
||||
} |
||||
} |
@ -0,0 +1,105 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\behaviors; |
||||
|
||||
use yii\base\Behavior; |
||||
use yii\db\Expression; |
||||
use yii\db\ActiveRecord; |
||||
|
||||
/** |
||||
* AutoTimestamp will automatically fill the attributes about creation time and updating time. |
||||
* |
||||
* AutoTimestamp fills the attributes when the associated AR model is being inserted or updated. |
||||
* You may specify an AR to use this behavior like the following: |
||||
* |
||||
* ~~~ |
||||
* public function behaviors() |
||||
* { |
||||
* return array( |
||||
* 'timestamp' => array( |
||||
* 'class' => 'yii\behaviors\AutoTimestamp', |
||||
* ), |
||||
* ); |
||||
* } |
||||
* ~~~ |
||||
* |
||||
* By default, the attribute for keeping the creation time is named as "create_time", and the attribute |
||||
* for updating time is "update_time". You may customize the names via [[createAttribute]] and [[updateAttribute]]. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class AutoTimestamp extends Behavior |
||||
{ |
||||
/** |
||||
* @var string The name of the attribute to store the creation time. Set to null to not |
||||
* use a timestamp for the creation attribute. Defaults to 'create_time' |
||||
*/ |
||||
public $createAttribute = 'create_time'; |
||||
/** |
||||
* @var string The name of the attribute to store the modification time. Set to null to not |
||||
* use a timestamp for the update attribute. Defaults to 'update_time' |
||||
*/ |
||||
public $updateAttribute = 'update_time'; |
||||
/** |
||||
* @var \Closure|Expression The expression that will be used for generating the timestamp. |
||||
* This can be either an anonymous function that returns the timestamp value, |
||||
* or an [[Expression]] object representing a DB expression (e.g. `new Expression('NOW()')`). |
||||
* If not set, it will use the value of `time()` to fill the attributes. |
||||
*/ |
||||
public $timestamp; |
||||
|
||||
|
||||
/** |
||||
* Declares event handlers for the [[owner]]'s events. |
||||
* @return array events (array keys) and the corresponding event handler methods (array values). |
||||
*/ |
||||
public function events() |
||||
{ |
||||
return array( |
||||
ActiveRecord::EVENT_BEFORE_INSERT => 'beforeInsert', |
||||
ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate', |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* This is the event handler for the "beforeInsert" event of the associated AR object. |
||||
*/ |
||||
public function beforeInsert() |
||||
{ |
||||
if ($this->createAttribute !== null) { |
||||
$this->owner->{$this->createAttribute} = $this->evaluateTimestamp($this->createAttribute); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This is the event handler for the "beforeUpdate" event of the associated AR object. |
||||
*/ |
||||
public function beforeUpdate() |
||||
{ |
||||
if ($this->updateAttribute !== null) { |
||||
$this->owner->{$this->updateAttribute} = $this->evaluateTimestamp($this->updateAttribute); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the appropriate timestamp depending on the column type $attribute is |
||||
* @param string $attribute attribute name |
||||
* @return mixed the timestamp value |
||||
*/ |
||||
protected function evaluateTimestamp($attribute) |
||||
{ |
||||
if ($this->timestamp instanceof Expression) { |
||||
return $this->timestamp; |
||||
} elseif ($this->timestamp !== null) { |
||||
return call_user_func($this->timestamp); |
||||
} else { |
||||
return time(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
<?php use yii\helpers\Html; |
||||
|
||||
echo Html::style(" |
||||
#yii-debug-toolbar { |
||||
position: fixed; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
background-color: #eee; |
||||
border-top: 1px solid #ccc; |
||||
margin: 0; |
||||
padding: 5px 10px; |
||||
z-index: 1000000; |
||||
font: 11px Verdana, Arial, sans-serif; |
||||
text-align: left; |
||||
} |
||||
.yii-debug-toolbar-block { |
||||
float: left; |
||||
margin: 0 10px; |
||||
"); |
||||
?> |
||||
|
||||
<div class="yii-debug-toolbar-block"> |
||||
</div> |
||||
|
||||
<div class="yii-debug-toolbar-block"> |
||||
Peak memory: <?php echo sprintf('%.2fMB', $memory / 1048576); ?> |
||||
</div> |
||||
|
||||
<div class="yii-debug-toolbar-block"> |
||||
Time spent: <?php echo sprintf('%.3fs', $time); ?> |
||||
</div> |
||||
|
||||
<div class="yii-debug-toolbar-block"> |
||||
</div> |
||||
|
||||
<div class="yii-debug-toolbar-block"> |
||||
</div> |
||||
|
@ -0,0 +1,91 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\logging; |
||||
|
||||
use Yii; |
||||
|
||||
/** |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class DebugTarget extends Target |
||||
{ |
||||
public $maxLogFiles = 20; |
||||
|
||||
/** |
||||
* Exports log messages to a specific destination. |
||||
* Child classes must implement this method. |
||||
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure |
||||
* of each message. |
||||
*/ |
||||
public function export($messages) |
||||
{ |
||||
$path = Yii::$app->getRuntimePath() . '/debug'; |
||||
if (!is_dir($path)) { |
||||
mkdir($path); |
||||
} |
||||
$file = $path . '/' . Yii::getLogger()->getTag() . '.log'; |
||||
$data = array( |
||||
'messages' => $messages, |
||||
'_SERVER' => $_SERVER, |
||||
'_GET' => $_GET, |
||||
'_POST' => $_POST, |
||||
'_COOKIE' => $_COOKIE, |
||||
'_FILES' => empty($_FILES) ? array() : $_FILES, |
||||
'_SESSION' => empty($_SESSION) ? array() : $_SESSION, |
||||
'memory' => memory_get_peak_usage(), |
||||
'time' => microtime(true) - YII_BEGIN_TIME, |
||||
); |
||||
file_put_contents($file, json_encode($data)); |
||||
} |
||||
|
||||
/** |
||||
* Processes the given log messages. |
||||
* This method will filter the given messages with [[levels]] and [[categories]]. |
||||
* And if requested, it will also export the filtering result to specific medium (e.g. email). |
||||
* @param array $messages log messages to be processed. See [[Logger::messages]] for the structure |
||||
* of each message. |
||||
* @param boolean $final whether this method is called at the end of the current application |
||||
*/ |
||||
public function collect($messages, $final) |
||||
{ |
||||
if (Yii::$app->getModule('debug', false) !== null) { |
||||
return; |
||||
} |
||||
$this->messages = array_merge($this->messages, $this->filterMessages($messages)); |
||||
if ($final) { |
||||
$this->export($this->messages); |
||||
$this->gc(); |
||||
} |
||||
} |
||||
|
||||
protected function gc() |
||||
{ |
||||
if (mt_rand(0, 10000) > 100) { |
||||
return; |
||||
} |
||||
$iterator = new \DirectoryIterator(Yii::$app->getRuntimePath() . '/debug'); |
||||
$files = array(); |
||||
foreach ($iterator as $file) { |
||||
if (preg_match('/^[\d\-]+\.log$/', $file->getFileName()) && $file->isFile()) { |
||||
$files[] = $file->getPathname(); |
||||
} |
||||
} |
||||
sort($files); |
||||
if (count($files) > $this->maxLogFiles) { |
||||
$n = count($files) - $this->maxLogFiles; |
||||
foreach ($files as $i => $file) { |
||||
if ($i < $n) { |
||||
unlink($file); |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,61 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright © 2008-2011 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
/** |
||||
* CWebLogRoute shows the log content in Web page. |
||||
* |
||||
* The log content can appear either at the end of the current Web page |
||||
* or in FireBug console window (if {@link showInFireBug} is set true). |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class CWebLogRoute extends CLogRoute |
||||
{ |
||||
/** |
||||
* @var boolean whether the log should be displayed in FireBug instead of browser window. Defaults to false. |
||||
*/ |
||||
public $showInFireBug = false; |
||||
|
||||
/** |
||||
* @var boolean whether the log should be ignored in FireBug for ajax calls. Defaults to true. |
||||
* This option should be used carefully, because an ajax call returns all output as a result data. |
||||
* For example if the ajax call expects a json type result any output from the logger will cause ajax call to fail. |
||||
*/ |
||||
public $ignoreAjaxInFireBug = true; |
||||
|
||||
/** |
||||
* Displays the log messages. |
||||
* @param array $logs list of log messages |
||||
*/ |
||||
public function processLogs($logs) |
||||
{ |
||||
$this->render('log', $logs); |
||||
} |
||||
|
||||
/** |
||||
* Renders the view. |
||||
* @param string $view the view name (file name without extension). The file is assumed to be located under framework/data/views. |
||||
* @param array $data data to be passed to the view |
||||
*/ |
||||
protected function render($view, $data) |
||||
{ |
||||
$app = \Yii::$app; |
||||
$isAjax = $app->getRequest()->getIsAjaxRequest(); |
||||
|
||||
if ($this->showInFireBug) |
||||
{ |
||||
if ($isAjax && $this->ignoreAjaxInFireBug) |
||||
return; |
||||
$view .= '-firebug'; |
||||
} elseif (!($app instanceof CWebApplication) || $isAjax) |
||||
return; |
||||
|
||||
$viewFile = YII_PATH . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $view . '.php'; |
||||
include($app->findLocalizedFile($viewFile, 'en')); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue