49 changed files with 1592 additions and 1439 deletions
			
			
		| @ -1,328 +0,0 @@ | ||||
| Yii2 code standard | ||||
| ================== | ||||
| 
 | ||||
| This code standard is used for all the Yii2 core classes and can be applied to | ||||
| your application in order to achieve consistency among your team. Also it will | ||||
| help in case you want to opensource code. | ||||
| 
 | ||||
| PHP file formatting | ||||
| ------------------- | ||||
| 
 | ||||
| ### General | ||||
| 
 | ||||
| - Do not end file with `?>` if it contains PHP code only. | ||||
| - Do not use `<?`. Use `<?php` instead. | ||||
| - Files should be encoded in UTF-8. | ||||
| - Any file that contains PHP code should end with the extension `.php`. | ||||
| - Do not add trailing spaces to the end of the lines. | ||||
| 
 | ||||
| #### Indentation | ||||
| 
 | ||||
| All code must be indented with tabs. That includes both PHP and JavaScript code. | ||||
| 
 | ||||
| #### Maximum Line Length | ||||
| 
 | ||||
| We're not strictly limiting maximum line length but sticking to 80 characters | ||||
| where possible. | ||||
| 
 | ||||
| ### PHP types | ||||
| 
 | ||||
| All PHP types and values should be used lowercase. That includes `true`, `false`, | ||||
| `null` and `array`. | ||||
| 
 | ||||
| ### Strings | ||||
| 
 | ||||
| - If string doesn't contain variables or single quotes, use single quotes. | ||||
| 
 | ||||
| ~~~ | ||||
| $str = 'Like this.'; | ||||
| ~~~ | ||||
| 
 | ||||
| - If string contains single quotes you can use double quotes to avoid extra escaping. | ||||
| - You can use the following forms of variable substitution: | ||||
| 
 | ||||
| ~~~ | ||||
| $str1 = "Hello $username!"; | ||||
| $str2 = "Hello {$username}!"; | ||||
| ~~~ | ||||
| 
 | ||||
| The following is not permitted: | ||||
| 
 | ||||
| ~~~ | ||||
| $str3 = "Hello ${username}!"; | ||||
| ~~~ | ||||
| 
 | ||||
| ### String concatenation | ||||
| 
 | ||||
| Add spaces around dot when concatenating strings: | ||||
| 
 | ||||
| ~~~ | ||||
| $name = 'Yii' . ' Framework'; | ||||
| ~~~ | ||||
| 
 | ||||
| When string is long format is the following: | ||||
| 
 | ||||
| ~~~ | ||||
| $sql = "SELECT *" | ||||
|      . "FROM `post` " | ||||
|      . "WHERE `id` = 121 "; | ||||
| ~~~ | ||||
| 
 | ||||
| 
 | ||||
| ### Numerically indexed arrays | ||||
| 
 | ||||
| - Do not use negative numbers as array indexes. | ||||
| 
 | ||||
| Use the following formatting when declaring array: | ||||
| 
 | ||||
| ~~~ | ||||
| $arr = array(3, 14, 15, 'Yii', 'Framework'); | ||||
| ~~~ | ||||
| 
 | ||||
| If there are too many elements for a single line: | ||||
| 
 | ||||
| ~~~ | ||||
| $arr = array( | ||||
| 	3, 14, 15, | ||||
| 	92, 6, $test, | ||||
| 	'Yii', 'Framework', | ||||
| ); | ||||
| ~~~ | ||||
| 
 | ||||
| ### Associative arrays | ||||
| 
 | ||||
| Use the following format for associative arrays: | ||||
| 
 | ||||
| ~~~ | ||||
| $config = array( | ||||
| 	'name'  => 'Yii', | ||||
| 	'options' => array( | ||||
| 		'usePHP' => true, | ||||
| 	), | ||||
| ); | ||||
| ~~~ | ||||
| 
 | ||||
| ### Classes | ||||
| 
 | ||||
| - Classes should be named using `CamelCase`. | ||||
| - The brace should always be written on the line underneath the class name. | ||||
| - Every class must have a documentation block that conforms to the PHPDoc. | ||||
| - All code in a class must be indented with a single tab. | ||||
| - There should be only one class in a single PHP file. | ||||
| - All classes should be namespaced. | ||||
| - Class name should match file name. Class namespace should match directory structure. | ||||
| 
 | ||||
| ~~~ | ||||
| /** | ||||
|  * Documentation | ||||
|  */ | ||||
| class MyClass extends \yii\Object implements MyInterface | ||||
| { | ||||
| 	// code | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| 
 | ||||
| ### Class members and variables | ||||
| 
 | ||||
| - When declaring public class members specify `public` keyword explicitly. | ||||
| - Variables should be declared at the top of the class before any method declarations. | ||||
| - Private and protected variables should be named like `$_varName`. | ||||
| - Public class members and standalone variables should be named using `$camelCase` | ||||
|   with first letter lowercase. | ||||
| - Use descriptive names. Variables such as `$i` and `$j` are better not to be used. | ||||
| 
 | ||||
| ### Constants | ||||
| 
 | ||||
| Both class level constants and global constants should be named in uppercase. Words | ||||
| are separated by underscore. | ||||
| 
 | ||||
| ~~~ | ||||
| class User { | ||||
| 	const STATUS_ACTIVE = 1; | ||||
| 	const STATUS_BANNED = 2; | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| It's preferable to define class level constants rather than global ones. | ||||
| 
 | ||||
| ### Functions and methods | ||||
| 
 | ||||
| - Functions and methods should be named using `camelCase` with first letter lowercase. | ||||
| - Name should be descriptive by itself indicating the purpose of the function. | ||||
| - Class methods should always declare visibility using `private`, `protected` and | ||||
|   `public` modifiers. `var` is not allowed. | ||||
| - Opening brace of a function should be on the line after the function declaration. | ||||
| 
 | ||||
| ~~~ | ||||
| /** | ||||
|  * Documentation | ||||
|  */ | ||||
| class Foo | ||||
| { | ||||
| 	/** | ||||
| 	 * Documentation | ||||
| 	 */ | ||||
| 	public function bar() | ||||
| 	{ | ||||
| 		// code | ||||
| 		return $value; | ||||
| 	} | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| Use type hinting where possible: | ||||
| 
 | ||||
| ~~~ | ||||
| public function __construct(CDbConnection $connection) | ||||
| { | ||||
| 	$this->connection = $connection; | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| ### Function and method calls | ||||
| 
 | ||||
| ~~~ | ||||
| doIt(2, 3); | ||||
| 
 | ||||
| doIt(array( | ||||
| 	'a' => 'b', | ||||
| )); | ||||
| 
 | ||||
| doIt('a', array( | ||||
| 	'a' => 'b', | ||||
| )); | ||||
| ~~~ | ||||
| 
 | ||||
| ### Control statements | ||||
| 
 | ||||
| - Control statement condition must have single space before and after parenthesis. | ||||
| - Operators inside of parenthesis should be separated by spaces. | ||||
| - Opening brace is on the same line. | ||||
| - Closing brace is on a new line. | ||||
| - Always use braces for single line statements. | ||||
| 
 | ||||
| ~~~ | ||||
| if ($event === null) { | ||||
| 	return new Event(); | ||||
| } elseif ($event instanceof CoolEvent) { | ||||
| 	return $event->instance(); | ||||
| } else { | ||||
| 	return null; | ||||
| } | ||||
| 
 | ||||
| // the following is NOT allowed: | ||||
| if(!$model) | ||||
| 	throw new Exception('test'); | ||||
| ~~~ | ||||
| 
 | ||||
| 
 | ||||
| ### Switch | ||||
| 
 | ||||
| Use the following formatting for switch: | ||||
| 
 | ||||
| ~~~ | ||||
| switch ($this->phpType) { | ||||
| 	case 'string': | ||||
| 		$a = (string)$value; | ||||
| 		break; | ||||
| 	case 'integer': | ||||
| 	case 'int': | ||||
| 		$a = (integer)$value; | ||||
| 		break; | ||||
| 	case 'boolean': | ||||
| 		$a = (boolean)$value; | ||||
| 		break; | ||||
| 	default: | ||||
| 		$a = null; | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| ### Code documentation | ||||
| 
 | ||||
| - Refer ot [phpDoc](http://phpdoc.org/) for documentation syntax. | ||||
| - Code without documentation is not allowed. | ||||
| - All class files must contain a "file-level" docblock at the top of each file | ||||
|   and a "class-level" docblock immediately above each class. | ||||
| - There is no need to use `@return` if method does return nothing. | ||||
| 
 | ||||
| #### File | ||||
| 
 | ||||
| ~~~ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| ~~~ | ||||
| 
 | ||||
| #### Class | ||||
| 
 | ||||
| ~~~ | ||||
| /** | ||||
|  * Component is the base class that provides the *property*, *event* and *behavior* features. | ||||
|  * | ||||
|  * @include @yii/docs/base-Component.md | ||||
|  * | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class Component extends \yii\base\Object | ||||
| ~~~ | ||||
| 
 | ||||
| 
 | ||||
| #### Function / method | ||||
| 
 | ||||
| ~~~ | ||||
| /** | ||||
|  * Returns the list of attached event handlers for an event. | ||||
|  * You may manipulate the returned [[Vector]] object by adding or removing handlers. | ||||
|  * For example, | ||||
|  * | ||||
|  * ~~~ | ||||
|  * $component->getEventHandlers($eventName)->insertAt(0, $eventHandler); | ||||
|  * ~~~ | ||||
|  * | ||||
|  * @param string $name the event name | ||||
|  * @return Vector list of attached event handlers for the event | ||||
|  * @throws Exception if the event is not defined | ||||
|  */ | ||||
| public function getEventHandlers($name) | ||||
| { | ||||
| 	if (!isset($this->_e[$name])) { | ||||
| 		$this->_e[$name] = new Vector; | ||||
| 	} | ||||
| 	$this->ensureBehaviors(); | ||||
| 	return $this->_e[$name]; | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| #### Comments | ||||
| 
 | ||||
| - One-line comments should be started with `//` and not `#`. | ||||
| - One-line comment should be on its own line. | ||||
| 
 | ||||
| Yii application naming conventions | ||||
| ---------------------------------- | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| Other library and framework standards | ||||
| ------------------------------------- | ||||
| 
 | ||||
| It's good to be consistent with other frameworks and libraries whose components | ||||
| will be possibly used with Yii2. That's why when there are no objective reasons | ||||
| to use different style we should use one that's common among most of the popular | ||||
| libraries and frameworks. | ||||
| 
 | ||||
| That's not only about PHP but about JavaScript as well. Since we're using jQuery | ||||
| a lot it's better to be consistent with its style as well. | ||||
| 
 | ||||
| Application style consistency is much more important than consistency with other frameworks and libraries. | ||||
| 
 | ||||
| - [Symfony 2](http://symfony.com/doc/current/contributing/code/standards.html) | ||||
| - [Zend Framework 1](http://framework.zend.com/manual/en/coding-standard.coding-style.html) | ||||
| - [Zend Framework 2](http://framework.zend.com/wiki/display/ZFDEV2/Coding+Standards) | ||||
| - [Pear](http://pear.php.net/manual/en/standards.php) | ||||
| - [jQuery](http://docs.jquery.com/JQuery_Core_Style_Guidelines) | ||||
| Before Width: | Height: | Size: 298 KiB | 
| Before Width: | Height: | Size: 16 KiB | 
| @ -1,192 +0,0 @@ | ||||
| Alex's Code Review, 2011.11.12 | ||||
| ============================== | ||||
| 
 | ||||
| Overall hierarchy | ||||
| ------------------ | ||||
| 
 | ||||
| Generally is OK. Like that `Object` and `Component` are now separated. | ||||
| I've generated 2 diagrams under `docs/` to see it better as a whole. | ||||
| 
 | ||||
| > The purpose of separating `Object` from `Component` is to make `Object` | ||||
| > a super-light base class that supports properties defined by getter/setters. | ||||
| > Note that `Component` is a bit of heavy because it uses two extra member | ||||
| > variables to support events and behaviors. | ||||
| 
 | ||||
| 
 | ||||
| Object | ||||
| ------ | ||||
| 
 | ||||
| ### property feature | ||||
| 
 | ||||
| Is it OK that `canGetProperty` and `canSetProperty` will return `false` for real | ||||
| class members? | ||||
| 
 | ||||
| > Added $checkVar parameter | ||||
| 
 | ||||
| ### callbacks and expressions | ||||
| 
 | ||||
| We're using 5.3. What's the reason to support `eval()` in `evaluateExpression` if | ||||
| we have anonymous functions? Is that for storing code as string inside of DB (RBAC)? | ||||
| 
 | ||||
| If we're going to get rid of `eval()`, cosider remaning method to something about callback. | ||||
| If not then we definitely need to use anonymous functions in API docs and the guide | ||||
| where possible. | ||||
| 
 | ||||
| > The purpose of evaluateExpression() is to provide a way of evaluating a PHP expression | ||||
| > in the context of an object. Will remove it before release if we find no use of it. | ||||
| 
 | ||||
| >> mdomba: | ||||
| >> As eval() is controversial, and anonymous functions can replace all Yii 1 usage of eval() | ||||
| >> how about removing it from the beginning and add it only if we find it necessary. | ||||
| >> This way we would not be tempted to stick with eval() and will be forced to first try to find alternatives | ||||
| 
 | ||||
| ### Object::create() | ||||
| 
 | ||||
| #### `__construct` issue | ||||
| 
 | ||||
| Often a class doesn't have `__construct` implementation and `stdClass` doesn't have | ||||
| default one either but Object::create() always expects constructor to be | ||||
| defined. See `ObjectTest`. Either `method_exists` call or `Object::__construct` needed. | ||||
| 
 | ||||
| > Added Object::__construct. | ||||
| 
 | ||||
| #### How to support object factory like we do with CWidgetFactory? | ||||
| 
 | ||||
| ~~~ | ||||
| class ObjectConfig | ||||
| { | ||||
| 	public function configure($class) | ||||
| 	{ | ||||
| 		$config = $this->load($class); | ||||
| 		// apply config to $class | ||||
| 	} | ||||
| 
 | ||||
| 	private function load($class) | ||||
| 	{ | ||||
| 		// get class properties from a config file | ||||
| 		// in this method we need to walk all the | ||||
| 		// inheritance hierarchy down to Object itself | ||||
| 		return array( | ||||
| 			'property' => 'value', | ||||
| 			// … | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| Then we need to add `__construct` to `Object` (or implement `Initalbe`): | ||||
| 
 | ||||
| ~~~ | ||||
| class Object | ||||
| { | ||||
| 	public function __construct() | ||||
| 	{ | ||||
| 		$conf = new ObjectConfig(); | ||||
| 		$conf->configure($this); | ||||
| 	} | ||||
| } | ||||
| ~~~ | ||||
| 
 | ||||
| This way we'll be able to set defaults for any object. | ||||
| 
 | ||||
| > The key issue here is about how to process the config file. Clearly, we cannot | ||||
| > do this for every type of component because it would mean an extra file access | ||||
| > for every component type | ||||
| 
 | ||||
| #### Do we need to support lazy class injection? | ||||
| 
 | ||||
| Currently there's no way to lazy-inject class into another class property via | ||||
| config. Do we need it? If yes then we can probably extend component config to support | ||||
| the following: | ||||
| 
 | ||||
| ~~~ | ||||
| class Foo extends Object | ||||
| { | ||||
| 	public $prop; | ||||
| } | ||||
| 
 | ||||
| class Bar extends Object | ||||
| { | ||||
| 	public $prop; | ||||
| } | ||||
| 
 | ||||
| $config = array( | ||||
| 	'prop' => array( | ||||
| 		'class' => 'Bar', | ||||
| 		'prop' => 'Hello!', | ||||
| 	), | ||||
| ); | ||||
| 
 | ||||
| $foo = Foo::create($config); | ||||
| echo $foo->bar->prop; | ||||
| // will output Hello! | ||||
| ~~~ | ||||
| 
 | ||||
| Should it support infinite nesting level? | ||||
| 
 | ||||
| > I don't think we need this. Foo::$prop cannot be an object unless it needs it to be. | ||||
| > In that case, it can be defined with a setter in which it can handle the object creation | ||||
| > based on a configuration array. This is a bit inconvenient, but I think such usage is | ||||
| > not very common. | ||||
| 
 | ||||
| ### Why `Event` is `Object`? | ||||
| 
 | ||||
| There's no need to extend from `Object`. Is there a plan to use `Object` features | ||||
| later? | ||||
| 
 | ||||
| > To use properties defined via getter/setter. | ||||
| 
 | ||||
| 
 | ||||
| Behaviors | ||||
| --------- | ||||
| 
 | ||||
| Overall I wasn't able to use behaviors. See `BehaviorTest`. | ||||
| 
 | ||||
| ### Should behaviors be able to define events for owner components? | ||||
| 
 | ||||
| Why not? Should be a very good feature in order to make behaviors customizable. | ||||
| 
 | ||||
| > It's a bit hard to implement it efficiently. I tend not to support it for now | ||||
| > unless enough people are requesting for it. | ||||
| 
 | ||||
| ### Multiple behaviors can be attached to the same component | ||||
| 
 | ||||
| What if we'll have multiple methods / properties / events with the same name? | ||||
| 
 | ||||
| > The first one takes precedence. This is the same as we do in 1.1. | ||||
| 
 | ||||
| ### How to use Behavior::attach? | ||||
| 
 | ||||
| Looks like it is used by `Component::attachBehavior` but can't be used without it. | ||||
| Why it's public then? Can we move it to `Component?` | ||||
| 
 | ||||
| > It's public because it is called by Component. It is in Behavior such that | ||||
| > it can be overridden by behavior classes to customize the attach process. | ||||
| 
 | ||||
| Events | ||||
| ------ | ||||
| 
 | ||||
| Class itself looks OK. Component part is OK as well but I've not tested | ||||
| it carefully. Overall it seems concept is the same as in Yii1. | ||||
| 
 | ||||
| ### Event declaration: the on-method is mostly repetitive for every event. Should we choose a different way of declaring events? | ||||
| 
 | ||||
| Maybe. People complained previously about too many code for event declaration. | ||||
| 
 | ||||
| ### Should we implement some additional event mechanism, such as global events? | ||||
| 
 | ||||
| Why use two different implementations in a single application? | ||||
| 
 | ||||
| Exceptions | ||||
| ---------- | ||||
| 
 | ||||
| - Should we convert all errors, warnings and notices to exceptions? | ||||
| 
 | ||||
| > I think not. We used to do this in early versions of 1.0. We found sometimes | ||||
| > very mysterious things would happen which makes error fixing harder rather than | ||||
| > easier. | ||||
| 
 | ||||
| Coding style | ||||
| ------------ | ||||
| 
 | ||||
| See `docs/code_style.md`. | ||||
| @ -0,0 +1,136 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\base; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class ViewContent extends Component | ||||
| { | ||||
| 	const POS_HEAD = 1; | ||||
| 	const POS_BEGIN = 2; | ||||
| 	const POS_END = 3; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var array | ||||
| 	 * | ||||
| 	 * Each asset bundle should be declared with the following structure: | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     'basePath' => '...', | ||||
| 	 *     'baseUrl' => '...',  // if missing, the bundle will be published to the "www/assets" folder | ||||
| 	 *     'js' => array( | ||||
| 	 *         'js/main.js', | ||||
| 	 *         'js/menu.js', | ||||
| 	 *         'js/base.js' => self::POS_HEAD, | ||||
| 	 *     'css' => array( | ||||
| 	 *         'css/main.css', | ||||
| 	 *         'css/menu.css', | ||||
| 	 *     ), | ||||
| 	 *     'depends' => array( | ||||
| 	 *         'jquery', | ||||
| 	 *         'yii', | ||||
| 	 *         'yii/treeview', | ||||
| 	 *     ), | ||||
| 	 * ) | ||||
| 	 * ~~~ | ||||
| 	 */ | ||||
| 	public $bundles; | ||||
| 
 | ||||
| 	public $title; | ||||
| 	public $metaTags; | ||||
| 	public $linkTags; | ||||
| 	public $css; | ||||
| 	public $js; | ||||
| 	public $cssFiles; | ||||
| 	public $jsFiles; | ||||
| 
 | ||||
| 	public function populate($content) | ||||
| 	{ | ||||
| 		return $content; | ||||
| 	} | ||||
| 
 | ||||
| 	public function reset() | ||||
| 	{ | ||||
| 		$this->title = null; | ||||
| 		$this->metaTags = null; | ||||
| 		$this->linkTags = null; | ||||
| 		$this->css = null; | ||||
| 		$this->js = null; | ||||
| 		$this->cssFiles = null; | ||||
| 		$this->jsFiles = null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function registerBundle($name) | ||||
| 	{ | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	public function getMetaTag($key) | ||||
| 	{ | ||||
| 		return isset($this->metaTags[$key]) ? $this->metaTags[$key] : null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function setMetaTag($key, $tag) | ||||
| 	{ | ||||
| 		$this->metaTags[$key] = $tag; | ||||
| 	} | ||||
| 
 | ||||
| 	public function getLinkTag($key) | ||||
| 	{ | ||||
| 		return isset($this->linkTags[$key]) ? $this->linkTags[$key] : null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function setLinkTag($key, $tag) | ||||
| 	{ | ||||
| 		$this->linkTags[$key] = $tag; | ||||
| 	} | ||||
| 
 | ||||
| 	public function getCss($key) | ||||
| 	{ | ||||
| 		return isset($this->css[$key]) ? $this->css[$key]: null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function setCss($key, $css) | ||||
| 	{ | ||||
| 		$this->css[$key] = $css; | ||||
| 	} | ||||
| 
 | ||||
| 	public function getCssFile($key) | ||||
| 	{ | ||||
| 		return isset($this->cssFiles[$key]) ? $this->cssFiles[$key]: null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function setCssFile($key, $file) | ||||
| 	{ | ||||
| 		$this->cssFiles[$key] = $file; | ||||
| 	} | ||||
| 
 | ||||
| 	public function getJs($key, $position = self::POS_END) | ||||
| 	{ | ||||
| 		return isset($this->js[$position][$key]) ? $this->js[$position][$key] : null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function setJs($key, $js, $position = self::POS_END) | ||||
| 	{ | ||||
| 		$this->js[$position][$key] = $js; | ||||
| 	} | ||||
| 
 | ||||
| 	public function getJsFile($key, $position = self::POS_END) | ||||
| 	{ | ||||
| 		return isset($this->jsFiles[$position][$key]) ? $this->jsFiles[$position][$key] : null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function setJsFile($key, $file, $position = self::POS_END) | ||||
| 	{ | ||||
| 		$this->jsFiles[$position][$key] = $file; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\base; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class ViewEvent extends Event | ||||
| { | ||||
| 	/** | ||||
| 	 * @var string the rendering result of [[View::renderFile()]]. | ||||
| 	 * Event handlers may modify this property and the modified output will be | ||||
| 	 * returned by [[View::renderFile()]]. This property is only used | ||||
| 	 * by [[View::EVENT_AFTER_RENDER]] event. | ||||
| 	 */ | ||||
| 	public $output; | ||||
| 	/** | ||||
| 	 * @var string the view file path that is being rendered by [[View::renderFile()]]. | ||||
| 	 */ | ||||
| 	public $viewFile; | ||||
| 	/** | ||||
| 	 * @var boolean whether to continue rendering the view file. Event handlers of | ||||
| 	 * [[View::EVENT_BEFORE_RENDER]] may set this property to decide whether | ||||
| 	 * to continue rendering the current view file. | ||||
| 	 */ | ||||
| 	public $isValid = true; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Constructor. | ||||
| 	 * @param string $viewFile the view file path that is being rendered by [[View::renderFile()]]. | ||||
| 	 * @param array $config name-value pairs that will be used to initialize the object properties | ||||
| 	 */ | ||||
| 	public function __construct($viewFile, $config = array()) | ||||
| 	{ | ||||
| 		$this->viewFile = $viewFile; | ||||
| 		parent::__construct($config); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,246 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\web; | ||||
| 
 | ||||
| use yii\widgets\ActiveForm; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class UploadedFile extends \yii\base\Object | ||||
| { | ||||
| 	private static $_files; | ||||
| 	private $_name; | ||||
| 	private $_tempName; | ||||
| 	private $_type; | ||||
| 	private $_size; | ||||
| 	private $_error; | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Constructor. | ||||
| 	 * Instead of using the constructor to create a new instance, | ||||
| 	 * you should normally call [[getInstance()]] or [[getInstances()]] | ||||
| 	 * to obtain new instances. | ||||
| 	 * @param string $name the original name of the file being uploaded | ||||
| 	 * @param string $tempName the path of the uploaded file on the server. | ||||
| 	 * @param string $type the MIME-type of the uploaded file (such as "image/gif"). | ||||
| 	 * @param integer $size the actual size of the uploaded file in bytes | ||||
| 	 * @param integer $error the error code | ||||
| 	 */ | ||||
| 	public function __construct($name, $tempName, $type, $size, $error) | ||||
| 	{ | ||||
| 		$this->_name = $name; | ||||
| 		$this->_tempName = $tempName; | ||||
| 		$this->_type = $type; | ||||
| 		$this->_size = $size; | ||||
| 		$this->_error = $error; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * String output. | ||||
| 	 * This is PHP magic method that returns string representation of an object. | ||||
| 	 * The implementation here returns the uploaded file's name. | ||||
| 	 * @return string the string representation of the object | ||||
| 	 */ | ||||
| 	public function __toString() | ||||
| 	{ | ||||
| 		return $this->_name; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns an uploaded file for the given model attribute. | ||||
| 	 * The file should be uploaded using [[ActiveForm::fileInput()]]. | ||||
| 	 * @param \yii\base\Model $model the data model | ||||
| 	 * @param string $attribute the attribute name. The attribute name may contain array indexes. | ||||
| 	 * For example, '[1]file' for tabular file uploading; and 'file[1]' for an element in a file array. | ||||
| 	 * @return UploadedFile the instance of the uploaded file. | ||||
| 	 * Null is returned if no file is uploaded for the specified model attribute. | ||||
| 	 * @see getInstanceByName | ||||
| 	 */ | ||||
| 	public static function getInstance($model, $attribute) | ||||
| 	{ | ||||
| 		$name = ActiveForm::getInputName($model, $attribute); | ||||
| 		return static::getInstanceByName($name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns all uploaded files for the given model attribute. | ||||
| 	 * @param \yii\base\Model $model the data model | ||||
| 	 * @param string $attribute the attribute name. The attribute name may contain array indexes | ||||
| 	 * for tabular file uploading, e.g. '[1]file'. | ||||
| 	 * @return UploadedFile[] array of UploadedFile objects. | ||||
| 	 * Empty array is returned if no available file was found for the given attribute. | ||||
| 	 */ | ||||
| 	public static function getInstances($model, $attribute) | ||||
| 	{ | ||||
| 		$name = ActiveForm::getInputName($model, $attribute); | ||||
| 		return static::getInstancesByName($name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns an uploaded file according to the given file input name. | ||||
| 	 * The name can be a plain string or a string like an array element (e.g. 'Post[imageFile]', or 'Post[0][imageFile]'). | ||||
| 	 * @param string $name the name of the file input field. | ||||
| 	 * @return UploadedFile the instance of the uploaded file. | ||||
| 	 * Null is returned if no file is uploaded for the specified name. | ||||
| 	 */ | ||||
| 	public static function getInstanceByName($name) | ||||
| 	{ | ||||
| 		$files = static::loadFiles(); | ||||
| 		return isset($files[$name]) ? $files[$name] : null; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns an array of uploaded files corresponding to the specified file input name. | ||||
| 	 * This is mainly used when multiple files were uploaded and saved as 'files[0]', 'files[1]', | ||||
| 	 * 'files[n]'..., and you can retrieve them all by passing 'files' as the name. | ||||
| 	 * @param string $name the name of the array of files | ||||
| 	 * @return UploadedFile[] the array of CUploadedFile objects. Empty array is returned | ||||
| 	 * if no adequate upload was found. Please note that this array will contain | ||||
| 	 * all files from all sub-arrays regardless how deeply nested they are. | ||||
| 	 */ | ||||
| 	public static function getInstancesByName($name) | ||||
| 	{ | ||||
| 		$files = static::loadFiles(); | ||||
| 		if (isset($files[$name])) { | ||||
| 			return array($files[$name]); | ||||
| 		} | ||||
| 		$results = array(); | ||||
| 		foreach ($files as $key => $file) { | ||||
| 			if (strpos($key, "{$name}[") === 0) { | ||||
| 				$results[] = self::$_files[$key]; | ||||
| 			} | ||||
| 		} | ||||
| 		return $results; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Cleans up the loaded UploadedFile instances. | ||||
| 	 * This method is mainly used by test scripts to set up a fixture. | ||||
| 	 */ | ||||
| 	public static function reset() | ||||
| 	{ | ||||
| 		self::$_files = null; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Saves the uploaded file. | ||||
| 	 * Note that this method uses php's move_uploaded_file() method. If the target file `$file` | ||||
| 	 * already exists, it will be overwritten. | ||||
| 	 * @param string $file the file path used to save the uploaded file | ||||
| 	 * @param boolean $deleteTempFile whether to delete the temporary file after saving. | ||||
| 	 * If true, you will not be able to save the uploaded file again in the current request. | ||||
| 	 * @return boolean true whether the file is saved successfully | ||||
| 	 * @see error | ||||
| 	 */ | ||||
| 	public function saveAs($file, $deleteTempFile = true) | ||||
| 	{ | ||||
| 		if ($this->_error == UPLOAD_ERR_OK) { | ||||
| 			if ($deleteTempFile) { | ||||
| 				return move_uploaded_file($this->_tempName, $file); | ||||
| 			} elseif (is_uploaded_file($this->_tempName)) { | ||||
| 				return copy($this->_tempName, $file); | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string the original name of the file being uploaded | ||||
| 	 */ | ||||
| 	public function getName() | ||||
| 	{ | ||||
| 		return $this->_name; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string the path of the uploaded file on the server. | ||||
| 	 * Note, this is a temporary file which will be automatically deleted by PHP | ||||
| 	 * after the current request is processed. | ||||
| 	 */ | ||||
| 	public function getTempName() | ||||
| 	{ | ||||
| 		return $this->_tempName; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string the MIME-type of the uploaded file (such as "image/gif"). | ||||
| 	 * Since this MIME type is not checked on the server side, do not take this value for granted. | ||||
| 	 * Instead, use [[FileHelper::getMimeType()]] to determine the exact MIME type. | ||||
| 	 */ | ||||
| 	public function getType() | ||||
| 	{ | ||||
| 		return $this->_type; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return integer the actual size of the uploaded file in bytes | ||||
| 	 */ | ||||
| 	public function getSize() | ||||
| 	{ | ||||
| 		return $this->_size; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns an error code describing the status of this file uploading. | ||||
| 	 * @return integer the error code | ||||
| 	 * @see http://www.php.net/manual/en/features.file-upload.errors.php | ||||
| 	 */ | ||||
| 	public function getError() | ||||
| 	{ | ||||
| 		return $this->_error; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return boolean whether there is an error with the uploaded file. | ||||
| 	 * Check [[error]] for detailed error code information. | ||||
| 	 */ | ||||
| 	public function getHasError() | ||||
| 	{ | ||||
| 		return $this->_error != UPLOAD_ERR_OK; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Creates UploadedFile instances from $_FILE. | ||||
| 	 * @return array the UploadedFile instances | ||||
| 	 */ | ||||
| 	private static function loadFiles() | ||||
| 	{ | ||||
| 		if (self::$_files === null) { | ||||
| 			self::$_files = array(); | ||||
| 			if (isset($_FILES) && is_array($_FILES)) { | ||||
| 				foreach ($_FILES as $class => $info) { | ||||
| 					self::loadFilesRecursive($class, $info['name'], $info['tmp_name'], $info['type'], $info['size'], $info['error']); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return self::$_files; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Creates UploadedFile instances from $_FILE recursively. | ||||
| 	 * @param string $key key for identifying uploaded file: class name and sub-array indexes | ||||
| 	 * @param mixed $names file names provided by PHP | ||||
| 	 * @param mixed $tempNames temporary file names provided by PHP | ||||
| 	 * @param mixed $types file types provided by PHP | ||||
| 	 * @param mixed $sizes file sizes provided by PHP | ||||
| 	 * @param mixed $errors uploading issues provided by PHP | ||||
| 	 */ | ||||
| 	private static function loadFilesRecursive($key, $names, $tempNames, $types, $sizes, $errors) | ||||
| 	{ | ||||
| 		if (is_array($names)) { | ||||
| 			foreach ($names as $i => $name) { | ||||
| 				self::loadFilesRecursive($key . '[' . $i . ']', $name, $tempNames[$i], $types[$i], $sizes[$i], $errors[$i]); | ||||
| 			} | ||||
| 		} else { | ||||
| 			self::$_files[$key] = new self($names, $tempNames, $types, $sizes, $errors); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue