Fixes #2655: Arrayable and ArrayableTrait are incompatible for some PHP versions.

This commit is contained in:
Qiang Xue
2014-03-07 19:08:27 -05:00
parent 6d97ded6c6
commit fad635440b
15 changed files with 131 additions and 175 deletions

View File

@ -8,7 +8,14 @@
namespace yii\base;
/**
* Arrayable should be implemented by classes that need to be represented in array format.
* Arrayable is the interface that should be implemented by classes who want to support customizable representation of their instances.
*
* For example, if a class implements Arrayable, by calling [[toArray()]], an instance of this class
* can be turned into an array (including all its embedded objects) which can then be further transformed easily
* into other formats, such as JSON, XML.
*
* The methods [[fields()]] and [[extraFields()]] allow the implementing classes to customize how and which of their data
* should be formatted and put into the result of [[toArray()]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
@ -16,8 +23,68 @@ namespace yii\base;
interface Arrayable
{
/**
* Converts the object into an array.
* @return array the array representation of this object
* Returns the list of fields that should be returned by default by [[toArray()]] when no specific fields are specified.
*
* A field is a named element in the returned array by [[toArray()]].
*
* This method should return an array of field names or field definitions.
* If the former, the field name will be treated as an object property name whose value will be used
* as the field value. If the latter, the array key should be the field name while the array value should be
* the corresponding field definition which can be either an object property name or a PHP callable
* returning the corresponding field value. The signature of the callable should be:
*
* ```php
* function ($field, $model) {
* // return field value
* }
* ```
*
* For example, the following code declares four fields:
*
* - `email`: the field name is the same as the property name `email`;
* - `firstName` and `lastName`: the field names are `firstName` and `lastName`, and their
* values are obtained from the `first_name` and `last_name` properties;
* - `fullName`: the field name is `fullName`. Its value is obtained by concatenating `first_name`
* and `last_name`.
*
* ```php
* return [
* 'email',
* 'firstName' => 'first_name',
* 'lastName' => 'last_name',
* 'fullName' => function () {
* return $this->first_name . ' ' . $this->last_name;
* },
* ];
* ```
*
* @return array the list of field names or field definitions.
* @see toArray()
*/
public function toArray();
public function fields();
/**
* Returns the list of additional fields that can be returned by [[toArray()]] in addition to those listed in [[fields()]].
*
* This method is similar to [[fields()]] except that the list of fields declared
* by this method are not returned by default by [[toArray()]]. Only when a field in the list
* is explicitly requested, will it be included in the result of [[toArray()]].
*
* @return array the list of expandable field names or field definitions. Please refer
* to [[fields()]] on the format of the return value.
* @see toArray()
* @see fields()
*/
public function extraFields();
/**
* Converts the object into an array.
*
* @param array $fields the fields that the output array should contain. Fields not specified
* in [[fields()]] will be ignored. If this parameter is empty, all fields as specified in [[fields()]] will be returned.
* @param array $expand the additional fields that the output array should contain.
* Fields not specified in [[extraFields()]] will be ignored. If this parameter is empty, no extra fields
* will be returned.
* @param boolean $recursive whether to recursively return array representation of embedded objects.
* @return array the array representation of the object
*/
public function toArray(array $fields = [], array $expand = [], $recursive = true);
}

View File

@ -13,6 +13,10 @@ use yii\web\Link;
use yii\web\Linkable;
/**
* ArrayableTrait provides a common implementation of the [[Arrayable]] interface.
*
* ArrayableTrait implements [[toArray()]] by respecting the field definitions as declared
* in [[fields()]] and [[extraFields()]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0

View File

@ -15,7 +15,7 @@ use Yii;
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class ErrorException extends \ErrorException implements Arrayable
class ErrorException extends \ErrorException
{
/**
* Constructs the exception.
@ -93,32 +93,4 @@ class ErrorException extends \ErrorException implements Arrayable
];
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : 'Error';
}
/**
* Returns the array representation of this object.
* @return array the array representation of this object.
*/
public function toArray()
{
return $this->toArrayRecursive($this);
}
/**
* Returns the array representation of the exception and all previous exceptions recursively.
* @param \Exception $exception object
* @return array the array representation of the exception.
*/
protected function toArrayRecursive($exception)
{
$array = [
'type' => get_class($exception),
'name' => $exception instanceof self ? $exception->getName() : 'Exception',
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
];
if (($prev = $exception->getPrevious()) !== null) {
$array['previous'] = $this->toArrayRecursive($prev);
}
return $array;
}
}

View File

@ -119,15 +119,8 @@ class ErrorHandler extends Component
'exception' => $exception,
]);
}
} elseif ($exception instanceof Arrayable) {
$response->data = $exception->toArray();
} else {
$response->data = [
'type' => get_class($exception),
'name' => 'Exception',
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
];
$response->data = $this->convertExceptionToArray($exception);
}
if ($exception instanceof HttpException) {
@ -139,6 +132,25 @@ class ErrorHandler extends Component
$response->send();
}
/**
* Converts an exception into an array.
* @param \Exception $exception the exception being converted
* @return array the array representation of the exception.
*/
protected function convertExceptionToArray($exception)
{
$array = [
'type' => get_class($exception),
'name' => $exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName() : 'Exception',
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
];
if (($prev = $exception->getPrevious()) !== null) {
$array['previous'] = $this->convertExceptionToArray($prev);
}
return $array;
}
/**
* Converts special characters to HTML entities.
* @param string $text to encode.

View File

@ -13,7 +13,7 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Exception extends \Exception implements Arrayable
class Exception extends \Exception
{
/**
* @return string the user-friendly name of this exception
@ -22,32 +22,4 @@ class Exception extends \Exception implements Arrayable
{
return 'Exception';
}
/**
* Returns the array representation of this object.
* @return array the array representation of this object.
*/
public function toArray()
{
return $this->toArrayRecursive($this);
}
/**
* Returns the array representation of the exception and all previous exceptions recursively.
* @param \Exception $exception object
* @return array the array representation of the exception.
*/
protected function toArrayRecursive($exception)
{
$array = [
'type' => get_class($exception),
'name' => $exception instanceof self ? $exception->getName() : 'Exception',
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
];
if (($prev = $exception->getPrevious()) !== null) {
$array['previous'] = $this->toArrayRecursive($prev);
}
return $array;
}
}