2015-07-15 23:05:46 +06:00
|
|
|
<?php
|
|
|
|
namespace GraphQL;
|
|
|
|
|
|
|
|
use GraphQL\Language\Source;
|
2016-10-18 22:15:21 +07:00
|
|
|
use GraphQL\Language\SourceLocation;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class Error
|
|
|
|
* A GraphQLError describes an Error found during the parse, validate, or
|
|
|
|
* execute phases of performing a GraphQL operation. In addition to a message
|
|
|
|
* and stack trace, it also includes information about the locations in a
|
|
|
|
* GraphQL document and/or execution result that correspond to the Error.
|
|
|
|
*
|
|
|
|
* @package GraphQL
|
|
|
|
*/
|
|
|
|
class Error extends \Exception implements \JsonSerializable
|
2015-07-15 23:05:46 +06:00
|
|
|
{
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* A message describing the Error for debugging purposes.
|
|
|
|
*
|
2015-07-15 23:05:46 +06:00
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
public $message;
|
|
|
|
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* An array of [ line => x, column => y] locations within the source GraphQL document
|
|
|
|
* which correspond to this error.
|
|
|
|
*
|
|
|
|
* Errors during validation often contain multiple locations, for example to
|
|
|
|
* point out two things with the same name. Errors during execution include a
|
|
|
|
* single location, the field which produced the error.
|
|
|
|
*
|
|
|
|
* @var SourceLocation[]
|
2015-07-15 23:05:46 +06:00
|
|
|
*/
|
2016-10-18 22:15:21 +07:00
|
|
|
private $locations;
|
2015-07-15 23:05:46 +06:00
|
|
|
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* An array describing the JSON-path into the execution response which
|
|
|
|
* corresponds to this error. Only included for errors during execution.
|
|
|
|
*
|
2015-07-15 23:05:46 +06:00
|
|
|
* @var array
|
|
|
|
*/
|
2016-10-18 22:15:21 +07:00
|
|
|
public $path;
|
2015-07-15 23:05:46 +06:00
|
|
|
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* An array of GraphQL AST Nodes corresponding to this error.
|
|
|
|
*
|
|
|
|
* @var array
|
2015-07-15 23:05:46 +06:00
|
|
|
*/
|
2016-10-18 22:15:21 +07:00
|
|
|
public $nodes;
|
2015-07-15 23:05:46 +06:00
|
|
|
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* The source GraphQL document corresponding to this error.
|
|
|
|
*
|
2015-07-15 23:05:46 +06:00
|
|
|
* @var Source|null
|
|
|
|
*/
|
2015-08-16 16:39:30 +06:00
|
|
|
private $source;
|
2015-07-15 23:05:46 +06:00
|
|
|
|
2016-10-18 22:15:21 +07:00
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $positions;
|
|
|
|
|
2015-07-15 23:05:46 +06:00
|
|
|
/**
|
2015-08-16 16:39:30 +06:00
|
|
|
* Given an arbitrary Error, presumably thrown while attempting to execute a
|
|
|
|
* GraphQL operation, produce a new GraphQLError aware of the location in the
|
|
|
|
* document responsible for the original Error.
|
|
|
|
*
|
2015-07-15 23:05:46 +06:00
|
|
|
* @param $error
|
2015-08-16 16:39:30 +06:00
|
|
|
* @param array|null $nodes
|
2016-10-18 22:15:21 +07:00
|
|
|
* @param array|null $path
|
2015-08-16 16:39:30 +06:00
|
|
|
* @return Error
|
2015-07-15 23:05:46 +06:00
|
|
|
*/
|
2016-10-18 22:15:21 +07:00
|
|
|
public static function createLocatedError($error, $nodes = null, $path = null)
|
2015-07-15 23:05:46 +06:00
|
|
|
{
|
2016-10-18 22:15:21 +07:00
|
|
|
if ($error instanceof self) {
|
|
|
|
return $error;
|
|
|
|
}
|
|
|
|
|
2015-08-16 16:39:30 +06:00
|
|
|
if ($error instanceof \Exception) {
|
|
|
|
$message = $error->getMessage();
|
|
|
|
$previous = $error;
|
2015-07-15 23:05:46 +06:00
|
|
|
} else {
|
|
|
|
$message = (string) $error;
|
2015-08-16 16:39:30 +06:00
|
|
|
$previous = null;
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|
|
|
|
|
2016-10-18 22:15:21 +07:00
|
|
|
return new Error($message, $nodes, null, null, $path, $previous);
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-08-16 16:39:30 +06:00
|
|
|
* @param Error $error
|
2015-08-17 02:53:11 +06:00
|
|
|
* @return array
|
2015-08-16 16:39:30 +06:00
|
|
|
*/
|
|
|
|
public static function formatError(Error $error)
|
|
|
|
{
|
2016-10-21 04:47:07 +07:00
|
|
|
return $error->toSerializableArray();
|
2015-08-16 16:39:30 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* @param string $message
|
2015-07-15 23:05:46 +06:00
|
|
|
* @param array|null $nodes
|
2015-08-16 16:39:30 +06:00
|
|
|
* @param Source $source
|
2016-10-18 22:15:21 +07:00
|
|
|
* @param array|null $positions
|
|
|
|
* @param array|null $path
|
|
|
|
* @param \Exception $previous
|
2015-08-16 16:39:30 +06:00
|
|
|
*/
|
2016-10-18 22:15:21 +07:00
|
|
|
public function __construct($message, $nodes = null, Source $source = null, $positions = null, $path = null, \Exception $previous = null)
|
2015-08-16 16:39:30 +06:00
|
|
|
{
|
|
|
|
parent::__construct($message, 0, $previous);
|
|
|
|
|
2015-08-17 02:53:11 +06:00
|
|
|
if ($nodes instanceof \Traversable) {
|
|
|
|
$nodes = iterator_to_array($nodes);
|
|
|
|
}
|
|
|
|
|
2015-08-16 16:39:30 +06:00
|
|
|
$this->nodes = $nodes;
|
|
|
|
$this->source = $source;
|
2015-08-17 02:53:11 +06:00
|
|
|
$this->positions = $positions;
|
2016-10-18 22:15:21 +07:00
|
|
|
$this->path = $path;
|
2015-08-16 16:39:30 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Source|null
|
2015-07-15 23:05:46 +06:00
|
|
|
*/
|
2015-08-16 16:39:30 +06:00
|
|
|
public function getSource()
|
2015-07-15 23:05:46 +06:00
|
|
|
{
|
2015-08-16 16:39:30 +06:00
|
|
|
if (null === $this->source) {
|
|
|
|
if (!empty($this->nodes[0]) && !empty($this->nodes[0]->loc)) {
|
|
|
|
$this->source = $this->nodes[0]->loc->source;
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|
|
|
|
}
|
2015-08-16 16:39:30 +06:00
|
|
|
return $this->source;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getPositions()
|
|
|
|
{
|
|
|
|
if (null === $this->positions) {
|
|
|
|
if (!empty($this->nodes)) {
|
|
|
|
$positions = array_map(function($node) { return isset($node->loc) ? $node->loc->start : null; }, $this->nodes);
|
2016-10-18 22:15:21 +07:00
|
|
|
$this->positions = array_filter($positions, function($p) {return $p !== null;});
|
2015-08-16 16:39:30 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this->positions;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-10-18 22:15:21 +07:00
|
|
|
* @return SourceLocation[]
|
2015-08-16 16:39:30 +06:00
|
|
|
*/
|
|
|
|
public function getLocations()
|
|
|
|
{
|
|
|
|
if (null === $this->locations) {
|
|
|
|
$positions = $this->getPositions();
|
|
|
|
$source = $this->getSource();
|
|
|
|
|
|
|
|
if ($positions && $source) {
|
|
|
|
$this->locations = array_map(function ($pos) use ($source) {
|
|
|
|
return $source->getLocation($pos);
|
|
|
|
}, $positions);
|
|
|
|
} else {
|
|
|
|
$this->locations = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->locations;
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|
2016-10-18 22:15:21 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns array representation of error suitable for serialization
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function toSerializableArray()
|
|
|
|
{
|
|
|
|
$arr = [
|
|
|
|
'message' => $this->getMessage(),
|
|
|
|
];
|
|
|
|
|
2016-10-21 04:47:07 +07:00
|
|
|
$locations = Utils::map($this->getLocations(), function(SourceLocation $loc) {
|
|
|
|
return $loc->toSerializableArray();
|
|
|
|
});
|
|
|
|
|
2016-10-18 22:15:21 +07:00
|
|
|
if (!empty($locations)) {
|
|
|
|
$arr['locations'] = $locations;
|
|
|
|
}
|
|
|
|
if (!empty($this->path)) {
|
|
|
|
$arr['path'] = $this->path;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $arr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Specify data which should be serialized to JSON
|
|
|
|
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
|
|
|
* @return mixed data which can be serialized by <b>json_encode</b>,
|
|
|
|
* which is a value of any type other than a resource.
|
|
|
|
* @since 5.4.0
|
|
|
|
*/
|
|
|
|
function jsonSerialize()
|
|
|
|
{
|
|
|
|
return $this->toSerializableArray();
|
|
|
|
}
|
2015-07-15 23:05:46 +06:00
|
|
|
}
|