Alexander Makarov
12 years ago
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