diff --git a/examples/errors_all_options.php b/examples/errors_all_options.php index 68d86f5..d6eb968 100644 --- a/examples/errors_all_options.php +++ b/examples/errors_all_options.php @@ -25,10 +25,15 @@ $error->add_meta($key='foo', $meta_data='bar'); $error->fill_meta($meta_data=['bar' => 'baz']); +// or as object +$meta_object = new stdClass(); +$meta_object->property = 'value'; +$error->add_meta($key='object', $meta_object); + // the http status code // @note it is better to set this on the jsonapi\errors object .. // .. as only a single one can be consumed by the browser -$error->set_http_status($http_status=\alsvanzelf\jsonapi\base::STATUS_NOT_FOUND); +$error->set_http_status($http_status=\alsvanzelf\jsonapi\response::STATUS_NOT_FOUND); // if not set during construction, set them here $error->set_error_message($error_message='too much options'); @@ -40,7 +45,7 @@ */ $another_error = new \alsvanzelf\jsonapi\error('kiss', 'Error objects can be small and simple as well.'); -$some_exception = new Exception('please don\'t throw things', \alsvanzelf\jsonapi\base::STATUS_INTERNAL_SERVER_ERROR); +$some_exception = new Exception('please don\'t throw things', \alsvanzelf\jsonapi\response::STATUS_INTERNAL_SERVER_ERROR); /** * building up the json response @@ -56,7 +61,7 @@ $jsonapi->add_error($another_error); $jsonapi->add_exception($some_exception); -$jsonapi->set_http_status(\alsvanzelf\jsonapi\base::STATUS_BAD_REQUEST); +$jsonapi->set_http_status(\alsvanzelf\jsonapi\response::STATUS_BAD_REQUEST); /** * sending the response diff --git a/examples/errors_exception.php b/examples/errors_exception.php index 981b0d7..17dab29 100644 --- a/examples/errors_exception.php +++ b/examples/errors_exception.php @@ -14,7 +14,7 @@ */ try { - throw new Exception('unknown user', \alsvanzelf\jsonapi\base::STATUS_NOT_FOUND); + throw new Exception('unknown user', \alsvanzelf\jsonapi\response::STATUS_NOT_FOUND); } catch (Exception $e) { $jsonapi = new \alsvanzelf\jsonapi\errors($e); diff --git a/src/base.php b/src/base.php index 0ee343e..109b5b2 100644 --- a/src/base.php +++ b/src/base.php @@ -5,30 +5,31 @@ class base { /** - * advised http status codes + * @deprecated + * @see response::STATUS_* */ -const STATUS_BAD_REQUEST = 400; -const STATUS_UNAUTHORIZED = 401; -const STATUS_FORBIDDEN = 403; -const STATUS_NOT_FOUND = 404; -const STATUS_METHOD_NOT_ALLOWED = 405; -const STATUS_UNPROCESSABLE_ENTITY = 422; -const STATUS_INTERNAL_SERVER_ERROR = 500; -const STATUS_SERVICE_UNAVAILABLE = 503; +const STATUS_BAD_REQUEST = response::STATUS_BAD_REQUEST; +const STATUS_UNAUTHORIZED = response::STATUS_UNAUTHORIZED; +const STATUS_FORBIDDEN = response::STATUS_FORBIDDEN; +const STATUS_NOT_FOUND = response::STATUS_NOT_FOUND; +const STATUS_METHOD_NOT_ALLOWED = response::STATUS_METHOD_NOT_ALLOWED; +const STATUS_UNPROCESSABLE_ENTITY = response::STATUS_UNPROCESSABLE_ENTITY; +const STATUS_INTERNAL_SERVER_ERROR = response::STATUS_INTERNAL_SERVER_ERROR; +const STATUS_SERVICE_UNAVAILABLE = response::STATUS_SERVICE_UNAVAILABLE; /** - * content type headers + * @deprecated + * @see response::CONTENT_TYPE_* */ -const CONTENT_TYPE_OFFICIAL = 'application/vnd.api+json'; -const CONTENT_TYPE_DEBUG = 'application/json'; +const CONTENT_TYPE_OFFICIAL = response::CONTENT_TYPE_OFFICIAL; +const CONTENT_TYPE_DEBUG = response::CONTENT_TYPE_DEBUG; /** - * json encode options - * default is JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE - * in debug mode (@see ::$debug) JSON_PRETTY_PRINT is added + * @deprecated + * @see response::ENCODE_* */ -const ENCODE_DEFAULT = 320; -const ENCODE_DEBUG = 448; +const ENCODE_DEFAULT = response::ENCODE_DEFAULT; +const ENCODE_DEBUG = response::ENCODE_DEBUG; /** * debug modus for non-production environments @@ -36,8 +37,8 @@ class base { * this is automatically set based on the display_errors directive * it can be overridden by setting it to a boolean value * - * - encodes json with in pretty print (@see ::ENCODE_DEBUG) (*) - * - makes browser display json instead of offering a file (@see ::CONTENT_TYPE_DEBUG) (*) + * - encodes json with in pretty print (@see response::ENCODE_DEBUG) (*) + * - makes browser display json instead of offering a file (@see response::CONTENT_TYPE_DEBUG) (*) * - outputs the error message for errors (@see error->get_array()) * - outputs exception details for errors (@see errors->add_exception()) * @@ -47,201 +48,16 @@ class base { public static $debug = null; /** - * internal data containers - */ -protected $links = array(); -protected $meta_data = array(); -protected $included_resources = array(); - -/** - * base constructor for all response objects (resource, collection, errors) + * base constructor for all objects * - * a few things are arranged here: + * few things are arranged here: * - determines ::$debug based on the display_errors directive - * - sets the self link using $_SERVER variables - * - * @see ->set_self_link() to override this default behavior */ public function __construct() { // set debug mode based on display_errors if (is_null(self::$debug)) { self::$debug = (bool)ini_get('display_errors'); } - - // auto-fill the self link based on the current request - $self_link = $_SERVER['REQUEST_URI']; - if (isset($_SERVER['PATH_INFO'])) { - $self_link = $_SERVER['PATH_INFO']; - } - - $this->set_self_link($self_link); -} - -/** - * alias for ->get_json() - * - * @see ->get_json() - * - * @return string - */ -public function __toString() { - return $this->get_json(); -} - -/** - * returns the whole response body as json - * it generates the response via ->get_array() - * - * @see ->get_array() for the structure - * @see json_encode() options - * - * @param int $encode_options optional, $options for json_encode() - * defaults to ::ENCODE_DEFAULT or ::ENCODE_DEBUG, @see ::$debug - * @return json - */ -public function get_json($encode_options=null) { - if (is_int($encode_options) == false) { - $encode_options = self::ENCODE_DEFAULT; - } - if (self::$debug || strpos($_SERVER['HTTP_ACCEPT'], '/json') == false) { - $encode_options = self::ENCODE_DEBUG; - } - - $response = $this->get_array(); - - $json = json_encode($response, $encode_options); - - return $json; -} - -/** - * sends out the json response to the browser - * this will fetch the response from ->get_json() if not given via $response - * - * @param string $content_type optional, defaults to ::CONTENT_TYPE_OFFICIAL (the official IANA registered one) .. - * .. or to ::CONTENT_TYPE_DEBUG, @see ::$debug - * @param int $encode_options optional, $options for json_encode() - * defaults to ::ENCODE_DEFAULT or ::ENCODE_DEBUG, @see ::$debug - * @param json $response optional, defaults to ::get_json() - * @return void however, a string will be echo'd to the browser - */ -public function send_response($content_type=null, $encode_options=null, $response=null) { - if (is_null($response)) { - $response = $this->get_json($encode_options); - } - - if (empty($content_type)) { - $content_type = self::CONTENT_TYPE_OFFICIAL; - } - if (self::$debug || strpos($_SERVER['HTTP_ACCEPT'], '/json') == false) { - $content_type = self::CONTENT_TYPE_DEBUG; - } - - header('Content-Type: '.$content_type.'; charset=utf-8'); - echo $response; -} - -/** - * returns the included resource objects - * this is used by a collection to work with the actual objects - * - * @return array - */ -public function get_included_resources() { - return $this->included_resources; -} - -/** - * sets the link to the request used to give this response - * this will end up in response.links.self .. - * and in response.data.links.self for single resource objects - * - * by default this is already set using $_SERVER variables - * use this method to override this default behavior - * @see ::__construct() - * - * @param string $link - * @return void - */ -public function set_self_link($link) { - $this->links['self'] = $link; -} - -/** - * adds an included resource - * this will end up in response.included[] - * - * prefer using ->add_relation() instead - * - * a $resource should have its 'id' set - * - * @note this can only be used by resource and collection, not by errors - * - * @param \alsvanzelf\jsonapi\resource $resource - */ -public function add_included_resource(\alsvanzelf\jsonapi\resource $resource) { - if (property_exists($this, 'included_resources') == false) { - throw new \Exception(get_class($this).' can not contain included resources'); - } - - $resource_array = $resource->get_array(); - if (empty($resource_array['data']['id'])) { - return; - } - - $resource_array = $resource_array['data']; - unset($resource_array['relationships'], $resource_array['meta']); - - $key = $resource_array['type'].'/'.$resource_array['id']; - - $this->included_data[$key] = $resource_array; - - // make a backup of the actual resource, to pass on to a collection - $this->included_resources[$key] = $resource; -} - -/** - * fills the included resources - * this will end up in response.included[] - * - * prefer using ->fill_relations() instead - * - * @param array $resources of \alsvanzelf\jsonapi\resource objects - * @return void - */ -public function fill_included_resources($resources) { - foreach ($resources as $resource) { - $this->add_included_resource($resource); - } -} - -/** - * adds some meta data - * this will end up in response.meta.{$key} - * - * @param string $key - * @param mixed $meta_data objects are converted in arrays, @see ::convert_object_to_array() - * @return void - */ -public function add_meta($key, $meta_data) { - if (is_object($meta_data)) { - $meta_data = self::convert_object_to_array($meta_data); - } - - $this->meta_data[$key] = $meta_data; -} - -/** - * fills the meta data - * this will end up in response.meta - * - * @param array $meta_data - * @return void - */ -public function fill_meta($meta_data) { - foreach ($meta_data as $key => $single_meta_data) { - $this->add_meta($key, $single_meta_data); - } } /** diff --git a/src/collection.php b/src/collection.php index 6d551b8..66bd199 100644 --- a/src/collection.php +++ b/src/collection.php @@ -15,7 +15,7 @@ * - included although possible, you should set those via the resource */ -class collection extends base { +class collection extends response { /** * internal data containers diff --git a/src/error.php b/src/error.php index fdfb406..1334b1f 100644 --- a/src/error.php +++ b/src/error.php @@ -9,7 +9,7 @@ * it is used, and can be used, to fill an errors collection */ -class error { +class error extends base { /** * internal data containers @@ -34,6 +34,8 @@ class error { * @param string $about_link optional, @see ->set_about_link() */ public function __construct($error_message, $friendly_message=null, $about_link=null) { + parent::__construct(); + $this->set_error_message($error_message); if ($friendly_message) { @@ -224,7 +226,7 @@ public function set_identifier($identifier) { */ public function add_meta($key, $meta_data) { if (is_object($meta_data)) { - $meta_data = base::convert_object_to_array($meta_data); + $meta_data = parent::convert_object_to_array($meta_data); } $this->meta_data[$key] = $meta_data; diff --git a/src/errors.php b/src/errors.php index 0b2c058..ef344eb 100644 --- a/src/errors.php +++ b/src/errors.php @@ -28,7 +28,7 @@ * ``` */ -class errors extends base { +class errors extends response { /** * http status messages used for string output diff --git a/src/resource.php b/src/resource.php index 4d7dd97..16ac037 100644 --- a/src/resource.php +++ b/src/resource.php @@ -17,7 +17,7 @@ * - included @see ->add_included_resource() or ->fill_included_resources() */ -class resource extends base { +class resource extends response { /** * internal data containers @@ -259,13 +259,13 @@ public function fill_links($links) { /** * sets the link to the request used to give this response * this will end up in response.links.self and response.data.links.self - * this overrides the jsonapi\base->set_self_link() which only adds it to response.links.self + * this overrides the jsonapi\response->set_self_link() which only adds it to response.links.self * - * @see jsonapi\base->set_self_link() + * @see jsonapi\response->set_self_link() * * by default this is already set using $_SERVER variables * use this method to override this default behavior - * @see jsonapi\base::__construct() + * @see jsonapi\response::__construct() * * @param string $link * @return void diff --git a/src/response.php b/src/response.php new file mode 100644 index 0000000..404f43b --- /dev/null +++ b/src/response.php @@ -0,0 +1,227 @@ +set_self_link() to override this default behavior + */ +public function __construct() { + parent::__construct(); + + // auto-fill the self link based on the current request + $self_link = $_SERVER['REQUEST_URI']; + if (isset($_SERVER['PATH_INFO'])) { + $self_link = $_SERVER['PATH_INFO']; + } + + $this->set_self_link($self_link); +} + +/** + * alias for ->get_json() + * + * @see ->get_json() + * + * @return string + */ +public function __toString() { + return $this->get_json(); +} + +/** + * returns the whole response body as json + * it generates the response via ->get_array() + * + * @see ->get_array() for the structure + * @see json_encode() options + * + * @param int $encode_options optional, $options for json_encode() + * defaults to ::ENCODE_DEFAULT or ::ENCODE_DEBUG, @see ::$debug + * @return json + */ +public function get_json($encode_options=null) { + if (is_int($encode_options) == false) { + $encode_options = self::ENCODE_DEFAULT; + } + if (base::$debug || strpos($_SERVER['HTTP_ACCEPT'], '/json') == false) { + $encode_options = self::ENCODE_DEBUG; + } + + $response = $this->get_array(); + + $json = json_encode($response, $encode_options); + + return $json; +} + +/** + * sends out the json response to the browser + * this will fetch the response from ->get_json() if not given via $response + * + * @param string $content_type optional, defaults to ::CONTENT_TYPE_OFFICIAL (the official IANA registered one) .. + * .. or to ::CONTENT_TYPE_DEBUG, @see ::$debug + * @param int $encode_options optional, $options for json_encode() + * defaults to ::ENCODE_DEFAULT or ::ENCODE_DEBUG, @see ::$debug + * @param json $response optional, defaults to ::get_json() + * @return void however, a string will be echo'd to the browser + */ +public function send_response($content_type=null, $encode_options=null, $response=null) { + if (is_null($response)) { + $response = $this->get_json($encode_options); + } + + if (empty($content_type)) { + $content_type = self::CONTENT_TYPE_OFFICIAL; + } + if (base::$debug || strpos($_SERVER['HTTP_ACCEPT'], '/json') == false) { + $content_type = self::CONTENT_TYPE_DEBUG; + } + + header('Content-Type: '.$content_type.'; charset=utf-8'); + echo $response; +} + +/** + * returns the included resource objects + * this is used by a collection to work with the actual objects + * + * @return array + */ +public function get_included_resources() { + return $this->included_resources; +} + +/** + * sets the link to the request used to give this response + * this will end up in response.links.self .. + * and in response.data.links.self for single resource objects + * + * by default this is already set using $_SERVER variables + * use this method to override this default behavior + * @see ::__construct() + * + * @param string $link + * @return void + */ +public function set_self_link($link) { + $this->links['self'] = $link; +} + +/** + * adds an included resource + * this will end up in response.included[] + * + * prefer using ->add_relation() instead + * + * a $resource should have its 'id' set + * + * @note this can only be used by resource and collection, not by errors + * + * @param \alsvanzelf\jsonapi\resource $resource + */ +public function add_included_resource(\alsvanzelf\jsonapi\resource $resource) { + if (property_exists($this, 'included_resources') == false) { + throw new \Exception(get_class($this).' can not contain included resources'); + } + + $resource_array = $resource->get_array(); + if (empty($resource_array['data']['id'])) { + return; + } + + $resource_array = $resource_array['data']; + unset($resource_array['relationships'], $resource_array['meta']); + + $key = $resource_array['type'].'/'.$resource_array['id']; + + $this->included_data[$key] = $resource_array; + + // make a backup of the actual resource, to pass on to a collection + $this->included_resources[$key] = $resource; +} + +/** + * fills the included resources + * this will end up in response.included[] + * + * prefer using ->fill_relations() instead + * + * @param array $resources of \alsvanzelf\jsonapi\resource objects + * @return void + */ +public function fill_included_resources($resources) { + foreach ($resources as $resource) { + $this->add_included_resource($resource); + } +} + +/** + * adds some meta data + * this will end up in response.meta.{$key} + * + * @param string $key + * @param mixed $meta_data objects are converted in arrays, @see base::convert_object_to_array() + * @return void + */ +public function add_meta($key, $meta_data) { + if (is_object($meta_data)) { + $meta_data = parent::convert_object_to_array($meta_data); + } + + $this->meta_data[$key] = $meta_data; +} + +/** + * fills the meta data + * this will end up in response.meta + * + * @param array $meta_data + * @return void + */ +public function fill_meta($meta_data) { + foreach ($meta_data as $key => $single_meta_data) { + $this->add_meta($key, $single_meta_data); + } +} + +}