diff --git a/phpcs.bonus.xml b/phpcs.bonus.xml
index be72666..ee7fe9e 100644
--- a/phpcs.bonus.xml
+++ b/phpcs.bonus.xml
@@ -4,13 +4,6 @@
./.ddev/*
./vendor/*
- ./src/base.php
- ./src/collection.php
- ./src/error.php
- ./src/errors.php
- ./src/exception.php
- ./src/resource.php
- ./src/response.php
diff --git a/phpcs.xml b/phpcs.xml
index dfe3e69..84e1035 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -4,13 +4,6 @@
./.ddev/*
./vendor/*
- ./src/base.php
- ./src/collection.php
- ./src/error.php
- ./src/errors.php
- ./src/exception.php
- ./src/resource.php
- ./src/response.php
diff --git a/phpstan.neon b/phpstan.neon
index 496ebc7..cab4788 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -5,14 +5,6 @@ parameters:
- src/
- tests/
- examples/
- excludePaths:
- - src/base.php
- - src/collection.php
- - src/error.php
- - src/errors.php
- - src/exception.php
- - src/resource.php
- - src/response.php
treatPhpDocTypesAsCertain: false
diff --git a/phpunitWithCodeCoverage.xml b/phpunitWithCodeCoverage.xml
index 4358d1a..9ef0558 100644
--- a/phpunitWithCodeCoverage.xml
+++ b/phpunitWithCodeCoverage.xml
@@ -16,13 +16,6 @@
src/interfaces
- src/base.php
- src/collection.php
- src/error.php
- src/errors.php
- src/exception.php
- src/resource.php
- src/response.php
diff --git a/rector.php b/rector.php
index 03c18b2..2a34ae9 100644
--- a/rector.php
+++ b/rector.php
@@ -12,15 +12,6 @@
__DIR__ . '/tests',
__DIR__ . '/examples',
])
- ->withSkip([
- __DIR__ . '/src/base.php',
- __DIR__ . '/src/collection.php',
- __DIR__ . '/src/error.php',
- __DIR__ . '/src/errors.php',
- __DIR__ . '/src/exception.php',
- __DIR__ . '/src/resource.php',
- __DIR__ . '/src/response.php',
- ])
// tab-based indenting
->withIndent(indentChar: "\t", indentSize: 1)
diff --git a/src/base.php b/src/base.php
deleted file mode 100644
index e8f7802..0000000
--- a/src/base.php
+++ /dev/null
@@ -1,97 +0,0 @@
-get_array())
- * - outputs exception details for errors (@see errors->add_exception())
- *
- * @note the effects marked with an asterisk (*) are automatically turned on ..
- * .. when requested by a human developer (request with an accept header w/o json)
- */
-public static $debug = null;
-
-/**
- * the root of the application using jsonapi
- * this is currently used to shorten filename of exception traces ..
- * .. and thus only used when ::$debug is set to true
- */
-public static $appRoot = __DIR__.'/../../../../';
-
-/**
- * base constructor for all objects
- *
- * few things are arranged here:
- * - determines ::$debug based on the display_errors directive
- */
-public function __construct() {
- // set debug mode based on display_errors
- if (is_null(self::$debug)) {
- self::$debug = (bool)ini_get('display_errors');
- }
-
- self::$appRoot = realpath(self::$appRoot).'/';
-}
-
-/**
- * converting an object to an array
- *
- * @param object $object by default, its public properties are used
- * if it is a \alsvanzelf\jsonapi\resource, its ->get_array() is used
- * @return array
- */
-protected static function convert_object_to_array($object) {
- if (is_object($object) == false) {
- throw new \Exception('can only convert objects');
- }
-
- if ($object instanceof \alsvanzelf\jsonapi\resource) {
- return $object->get_array();
- }
-
- return get_object_vars($object);
-}
-
-}
diff --git a/src/collection.php b/src/collection.php
deleted file mode 100644
index c32a968..0000000
--- a/src/collection.php
+++ /dev/null
@@ -1,143 +0,0 @@
-fill_collection() or ->add_resource()
- * - self link @see ->set_self_link()
- * - output @see ->send_response() or ->get_json()
- *
- * extra elements
- * - meta data @see ->add_meta() or ->fill_meta()
- * - included although possible, you should set those via the resource
- *
- * @deprecated {@see CollectionDocument}
- */
-class collection extends response {
-
-/**
- * internal data containers
- */
-protected $primary_type = null;
-protected $primary_collection = [];
-protected $primary_resource_objects = [];
-
-/**
- * creates a new collection
- *
- * @param string $type typically the name of the endpoint or database table
- */
-public function __construct($type=null) {
- parent::__construct();
-
- $this->primary_type = $type;
-}
-
-/**
- * get the primary type as set via the constructor
- *
- * @return string|null
- */
-public function get_type() {
- return $this->primary_type;
-}
-
-/**
- * generates an array for the whole response body
- *
- * @see jsonapi.org/format
- *
- * @return array, containing:
- * - links
- * - data []
- * - {everything from the resource's data-key}
- * - included {from the resource's included-key}
- * - meta
- */
-public function get_array() {
- $response = [];
-
- // links
- if ($this->links) {
- $response['links'] = $this->links;
- }
-
- // primary data
- $response['data'] = $this->primary_collection;
-
- // included resources
- if ($this->included_data) {
- $response['included'] = array_values($this->included_data);
- }
-
- // meta data
- if ($this->meta_data) {
- $response['meta'] = $this->meta_data;
- }
-
- return $response;
-}
-
-/**
- * returns the primary resource objects
- * this is used by a resource to add a collection or resource relations
- *
- * @return array
- */
-public function get_resources() {
- return $this->primary_resource_objects;
-}
-
-/**
- * adds a resource to the primary collection
- * this will end up in response.data[]
- *
- * @note only data and meta(root-level) of a resource are used
- * that is its type, id, attributes, relations, links, meta(data-level)
- * and meta(root-level) is added to response.meta[]
- * further, its included resources are separately added to response.included[]
- *
- * @see jsonapi\resource
- * @see ->fill_collection() for adding a whole array of resources directly
- *
- * @param \alsvanzelf\jsonapi\resource $resource
- * @return void
- */
-public function add_resource(\alsvanzelf\jsonapi\resource $resource) {
- $resource_array = $resource->get_array();
-
- $included_resources = $resource->get_included_resources();
- if (!empty($included_resources)) {
- $this->fill_included_resources($included_resources);
- }
-
- // root-level meta-data
- if (!empty($resource_array['meta'])) {
- $this->fill_meta($resource_array['meta']);
- }
-
- $this->primary_collection[] = $resource_array['data'];
-
- // make a backup of the actual resource, to pass on as a collection for a relation
- $this->primary_resource_objects[] = $resource;
-}
-
-/**
- * fills the primary collection with resources
- * this will end up in response.data[]
- *
- * @see ->add_resource()
- *
- * @param array $resources
- * @return void
- */
-public function fill_collection($resources) {
- foreach ($resources as $resource) {
- $this->add_resource($resource);
- }
-}
-
-}
diff --git a/src/error.php b/src/error.php
deleted file mode 100644
index 985c8fe..0000000
--- a/src/error.php
+++ /dev/null
@@ -1,291 +0,0 @@
- 'OK',
- 201 => 'Created',
- 204 => 'No Content',
- 304 => 'Not Modified',
- 307 => 'Temporary Redirect',
- 308 => 'Permanent Redirect',
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 422 => 'Unprocessable Entity',
- 500 => 'Internal Server Error',
- 503 => 'Service Unavailable',
-];
-
-/**
- * creates a new error for inclusion in the errors collection
- *
- * @note error message is only shown when debug mode is on (@see base::$debug)
- *
- * @param string $error_message
- * @param string $friendly_message optional, @see ->set_friendly_message()
- * @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) {
- $this->set_friendly_message($friendly_message);
- }
-
- if ($about_link) {
- $this->set_about_link($about_link);
- }
-}
-
-/**
- * generates an array for inclusion in the whole response body of an errors collection
- *
- * @note error message (`code`) is only shown when debug mode is on (@see base::$debug)
- *
- * @see jsonapi.org/format
- *
- * @return array, containing:
- * - status
- * - code
- * - title
- * - detail
- * - source
- * - pointer
- * - parameter
- * - links
- * - about
- * - id
- * - meta
- */
-public function get_array() {
- $response_part = [];
-
- // the basics
- $response_part['status'] = $this->http_status;
- if (base::$debug) {
- $response_part['code'] = $this->error_message;
- }
-
- // user guidance
- if ($this->friendly_message) {
- $response_part['title'] = $this->friendly_message;
- }
- if ($this->friendly_detail) {
- $response_part['detail'] = $this->friendly_detail;
- }
-
- // the source of the problem
- if ($this->post_body_pointer || $this->get_parameter_name) {
- $response_part['source'] = [];
-
- if ($this->post_body_pointer) {
- $response_part['source']['pointer'] = $this->post_body_pointer;
- }
- if ($this->get_parameter_name) {
- $response_part['source']['parameter'] = $this->get_parameter_name;
- }
- }
-
- // technical guidance
- if ($this->about_link) {
- $response_part['links'] = [
- 'about' => $this->about_link,
- ];
- }
- if ($this->identifier) {
- $response_part['id'] = $this->identifier;
- }
-
- // meta data
- if ($this->meta_data) {
- $response_part['meta'] = $this->meta_data;
- }
-
- return $response_part;
-}
-
-/**
- * returns the set status code apart from the response array
- * used by the errors collection to figure out the generic status code
- *
- * @return int probably one of the predefined ones in jsonapi\response::STATUS_*
- */
-public function get_http_status() {
- return (int)$this->http_status;
-}
-
-/**
- * sets a status code for the single error
- * this will end up in response.errors[].status
- *
- * @note this does only hint but not strictly set the actual status code send out to the browser
- * use jsonapi\errors->set_http_status() to be sure
- *
- * @param mixed $http_status string: an http status, should start with the numeric status code
- * integer: one of the predefined ones in response::STATUS_* ..
- * .. will be converted to string
- */
-public function set_http_status($http_status) {
- if (is_int($http_status)) {
- $http_status = (string)$http_status;
-
- // add status message for a few known ones
- if (isset(self::$http_status_messages[$http_status])) {
- $http_status .= ' '.self::$http_status_messages[$http_status];
- }
- }
-
- $this->http_status = $http_status;
-}
-
-/**
- * sets the main error message, aimed at developers
- * this will end up in response.errors[].code
- *
- * @note error message is only shown when debug mode is on (@see base::$debug)
- *
- * @param string $error_message
- */
-public function set_error_message($error_message) {
- $this->error_message = $error_message;
-}
-
-/**
- * sets a main user facing message
- * it should be human friendly and ready to show the user as the main problem
- * this will end up in response.errors[].title
- *
- * @note keep it short, more information can be added via ->set_friendly_detail()
- *
- * @param string $friendly_message
- */
-public function set_friendly_message($friendly_message) {
- $this->friendly_message = $friendly_message;
-}
-
-/**
- * sets a more detailed explanation of the problem, meant to the end user
- * this will end up in response.errors[].detail
- *
- * @param string $friendly_detail
- */
-public function set_friendly_detail($friendly_detail) {
- $this->friendly_detail = $friendly_detail;
-}
-
-/**
- * blames a specific field/value pair from the POST body as the source of the problem
- * this will end up in response.errors[].source.pointer
- *
- * @param string $post_body_pointer it should point out the field in the jsonapi structure
- * i.e. "/data/attributes/title"
- */
-public function blame_post_body($post_body_pointer) {
- $this->post_body_pointer = $post_body_pointer;
-}
-
-/**
- * blames a specific GET query string parameter as the source of the problem
- * this will end up in response.errors[].source.parameter
- *
- * @param string $get_parameter_name
- */
-public function blame_get_parameter($get_parameter_name) {
- $this->get_parameter_name = $get_parameter_name;
-}
-
-/**
- * sets a link which can help in solving the problem
- * this will end up in response.errors[].links.about
- *
- * @param string $about_link string with link
- * @param mixed $meta_data optional, meta data as key-value pairs
- * objects are converted in arrays, @see base::convert_object_to_array()
- */
-public function set_about_link($about_link, $meta_data=null) {
- if ($meta_data) {
- if (is_object($meta_data)) {
- $meta_data = parent::convert_object_to_array($meta_data);
- }
-
- $about_link = [
- 'href' => $about_link,
- 'meta' => $meta_data,
- ];
- }
-
- $this->about_link = $about_link;
-}
-
-/**
- * sets an id to help identifying the encountered problem
- * this could be an id used by internal logging which can help during a helpdesk issue
- * this will end up in response.errors[].id
- *
- * @param mixed $identifier can be an int or string
- */
-public function set_identifier($identifier) {
- $this->identifier = $identifier;
-}
-
-/**
- * adds some meta data
- * this will end up in response.errors[].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);
- }
-}
-
-}
diff --git a/src/errors.php b/src/errors.php
deleted file mode 100644
index 4b6bc67..0000000
--- a/src/errors.php
+++ /dev/null
@@ -1,251 +0,0 @@
-add_exception()
- * - error @see ::__construct() or ->add_error() or ->fill_errors()
- * - http status @see ->set_http_status()
- * - output @see ->send_response() or ->get_json()
- *
- * extra elements
- * - meta data @see ->add_meta() or ->fill_meta()
- * - self link @see ->set_self_link()
- *
- * @note ease error handling by using a jsonapi\exception
- * @see examples/errors_exception_direct.php
- * @see jsonapi\exception::__toString() when you want to use your own exception handling
- *
- * @deprecated {@see ErrorsDocument}
- */
-class errors extends response {
-
-/**
- * internal data containers
- */
-protected $links;
-protected $errors_collection;
-protected $http_status = response::STATUS_INTERNAL_SERVER_ERROR;
-protected $meta_data;
-
-/**
- * creates a new errors collection
- * it can be instantiated with a first/single exception/error to start the collection with
- * (further) errors can be added via ->add_exception() or ->add_error() or ->fill_errors()
- *
- * @note error message (if string) is only shown when debug mode is on (@see base::$debug)
- *
- * @param mixed $error_message optional, can be exception, jsonapi\error object, or string
- * @param string $friendly_message optional, @see jsonapi\error->set_friendly_message()
- * @param string $about_link optional, @see jsonapi\error->set_about_link()
- */
-public function __construct($error_message=null, $friendly_message=null, $about_link=null) {
- parent::__construct();
-
- if ($error_message instanceof \Exception) {
- $this->add_exception($error_message, $friendly_message, $about_link);
- return;
- }
-
- $this->add_error($error_message, $friendly_message, $about_link);
-}
-
-/**
- * generates an array for the whole response body
- *
- * @note error message (`code`) is only shown when debug mode is on (@see base::$debug)
- *
- * @see jsonapi.org/format
- *
- * @return array, containing:
- * - links
- * - errors []
- * - status
- * - code
- * - title
- * - detail
- * - source
- * - pointer
- * - parameter
- * - links
- * - about
- * - id
- * - meta
- * - meta
- */
-public function get_array() {
- $response = [];
-
- // links
- if ($this->links) {
- $response['links'] = $this->links;
- }
-
- // errors
- $response['errors'] = $this->errors_collection;
-
- // meta data
- if ($this->meta_data) {
- $response['meta'] = $this->meta_data;
- }
-
- return $response;
-}
-
-/**
- * sends out the json response to the browser
- * this will fetch the response from ->get_json() if not given via $response
- *
- * @note this is the same as jsonapi\response->send_response() ..
- * .. but it will also terminate script execution afterwards
- *
- * @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()
- * @param string $jsonp_callback optional, response as jsonp
- * @return void more so, a string will be echo'd to the browser ..
- * .. and script execution will terminate
- */
-public function send_response($content_type=null, $encode_options=null, $response=null, $jsonp_callback=null) {
- parent::send_response($content_type, $encode_options, $response, $jsonp_callback);
- exit;
-}
-
-/**
- * sets the http status code for this errors response
- *
- * @note this does the same as response->set_http_status() except it forces an error status
- *
- * @param int $http_status any will do, you can easily pass one of the predefined ones in ::STATUS_*
- */
-public function set_http_status($http_status) {
- if ($http_status < 400) {
- // can't use that as http status code
- return;
- }
-
- return parent::set_http_status($http_status);
-}
-
-/**
- * adds an error to the errors collection
- * this will end up in response.errors[]
- *
- * @note error message (if string) is only shown when debug mode is on (@see base::$debug)
- *
- * @param mixed $error_message optional, can be jsonapi\error object or string
- * @param string $friendly_message optional, @see jsonapi\error->set_friendly_message()
- * @param string $about_link optional, @see jsonapi\error->set_about_link()
- */
-public function add_error($error_message=null, $friendly_message=null, $about_link=null) {
- if ($error_message instanceof error == false) {
- $error_message = new error($error_message, $friendly_message, $about_link);
- }
-
- $this->add_error_object($error_message);
-}
-
-/**
- * fills the errors collection with an array of jsonapi\error objects
- * this will end up in response.errors[]
- *
- * @param array $errors with jsonapi\error objects inside
- * @return void
- */
-public function fill_errors($errors) {
- foreach ($errors as $error) {
- $this->add_error_object($error);
- }
-}
-
-/**
- * adds an exception as error to the errors collection
- * this will end up in response.errors[]
- *
- * @note exception meta data (file, line, trace) is only shown when debug mode is on (@see base::$debug)
- *
- * @param object $exception extending \Exception
- * @param string $friendly_message optional, @see jsonapi\error->set_friendly_message()
- * @param string $about_link optional, @see jsonapi\error->set_about_link()
- */
-public function add_exception($exception, $friendly_message=null, $about_link=null) {
- $error_message = $exception->getMessage();
- $error_status = $exception->getCode();
-
- $new_error = new error($error_message, $friendly_message, $about_link);
- if ($error_status) {
- $new_error->set_http_status($error_status);
- }
-
- // meta data
- if (base::$debug) {
- $file = $exception->getFile();
- if ($file) {
- $file = str_replace(base::$appRoot, '', $file);
- $new_error->add_meta('file', $file);
- }
-
- $line = $exception->getLine();
- if ($line) {
- $new_error->add_meta('line', $line);
- }
-
- $trace = $exception->getTrace();
- if ($trace) {
- foreach ($trace as &$place) {
- if (!empty($place['file'])) {
- $place['file'] = str_replace(base::$appRoot, '', $place['file']);
- }
- }
- $new_error->add_meta('trace', $trace);
- }
- }
-
- $this->add_error_object($new_error);
-
- $previous_exception = $exception->getPrevious();
- if ($previous_exception) {
- $this->add_exception($previous_exception);
- }
-}
-
-/**
- * adds a jsonapi\error object to the errors collection
- * used internally by ->add_error(), ->fill_errors() and ->add_exception()
- *
- * further, a generic http status is gathered from added objects
- *
- * @param jsonapi\error $error
- */
-private function add_error_object(\alsvanzelf\jsonapi\error $error) {
- $error_response_part = $error->get_array();
- $error_http_status = $error->get_http_status();
-
- $this->errors_collection[] = $error_response_part;
- if ($error_http_status) {
- $this->set_http_status($error_http_status);
- }
-}
-
-/**
- * blocks included resources on errors collections
- */
-public function add_included_resource(\alsvanzelf\jsonapi\resource $resource) {
- throw new \Exception('can not add included resources to errors, add them as meta data instead');
-}
-
-/**
- * blocks included resources on errors collections
- */
-public function fill_included_resources($resources) {
- throw new \Exception('can not add included resources to errors, add them as meta data instead');
-}
-
-}
diff --git a/src/exception.php b/src/exception.php
deleted file mode 100644
index 6a8ac49..0000000
--- a/src/exception.php
+++ /dev/null
@@ -1,98 +0,0 @@
-send_response()) output a errors collection response
- *
- * @note throwing the exception alone doesn't give you json output
- *
- * @deprecated {@see ErrorsDocument::fromException()}
- */
-class exception extends \Exception {
-
-/**
- * internal data containers
- */
-protected $friendly_message;
-protected $about_link;
-
-/**
- * custom exception for usage by jsonapi projects
- * when echo'd, sends a jsonapi\errors response with the exception in it
- *
- * can be thrown as a normal exception, optionally with two extra parameters
- *
- * @param string $message
- * @param integer $code optional, defaults to 500
- * if using one of the predefined ones in jsonapi\response::STATUS_*
- * sends out those as http status
- * @param Exception $previous
- * @param string $friendly_message optional, which message to output to clients
- * the exception $message is hidden unless base::$debug is true
- * @param string $about_link optional, a url to send clients to for more explanation
- * i.e. a link to the api documentation
- */
-public function __construct($message='', $code=0, $previous=null, $friendly_message=null, $about_link=null) {
- // exception is the only class not extending base
- new base();
-
- parent::__construct($message, $code, $previous);
-
- if ($friendly_message) {
- $this->set_friendly_message($friendly_message);
- }
- if ($about_link) {
- $this->set_about_link($about_link);
- }
-}
-
-/**
- * sets a main user facing message
- *
- * @see error->set_friendly_message()
- */
-public function set_friendly_message($friendly_message) {
- $this->friendly_message = $friendly_message;
-}
-
-/**
- * sets a link which can help in solving the problem
- *
- * @see error->set_about_link()
- */
-public function set_about_link($about_link) {
- $this->about_link = $about_link;
-}
-
-/**
- * sends out the json response of an jsonapi\errors object to the browser
- *
- * @see errors->send_response()
- */
-public function send_response($content_type=null, $encode_options=null, $response=null, $jsonp_callback=null) {
- $jsonapi = new errors($this, $this->friendly_message, $this->about_link);
- $jsonapi->send_response($content_type, $encode_options, $response, $jsonp_callback);
- exit; // sanity check
-}
-
-/**
- * alias for ->send_response()
- *
- * @deprecated as this causes hard to debug issues ..
- * .. when exceptions are called as a by-effect of this function
- *
- * @return string empty for sake of correctness
- * as ->send_response() already echo's the json and terminates script execution
- */
-public function __toString() {
- if (base::$debug) {
- trigger_error('toString conversion of exception is deprecated, use ->send_response() instead', E_USER_DEPRECATED);
- }
-
- $this->send_response();
- return '';
-}
-
-}
diff --git a/src/resource.php b/src/resource.php
deleted file mode 100644
index 7d34604..0000000
--- a/src/resource.php
+++ /dev/null
@@ -1,472 +0,0 @@
-add_data() or ->fill_data()
- * - self link @see ->set_self_link()
- * - output @see ->send_response() or ->get_json()
- *
- * extra elements
- * - relations @see ->add_relation() or ->fill_relations()
- * - links @see ->add_link() or ->fill_links()
- * - meta data @see ->add_meta() or ->fill_meta()
- * - included @see ->add_included_resource() or ->fill_included_resources()
- *
- * @deprecated {@see ResourceDocument}
- */
-class resource extends response {
-
-/**
- * relation types
- */
-const RELATION_TO_MANY = 'to_many';
-const RELATION_TO_ONE = 'to_one';
-
-/**
- * which links should be set for relations
- */
-const RELATION_LINKS_RELATIONSHIP = 'relationship';
-const RELATION_LINKS_RESOURCE = 'resource';
-const RELATION_LINKS_BOTH = 'both';
-const RELATION_LINKS_NONE = 'none';
-
-/**
- * placement of link objects
- */
-const LINK_LEVEL_DATA = 'data';
-const LINK_LEVEL_ROOT = 'root';
-const LINK_LEVEL_BOTH = 'both';
-
-/**
- * methods for filling the self link
- * @see ::$self_link_method
- */
-const SELF_LINK_SERVER = 'server';
-const SELF_LINK_TYPE = 'type';
-const SELF_LINK_NONE = 'none';
-
-/**
- * the method to use for filling the self link
- *
- * the current default ::SELF_LINK_SERVER fills the link using the $_SERVER request info
- * for backwards compatibility this stays for the 1.x releases
- * from 2.x this will (probably) switch to ::SELF_LINK_TYPE
- */
-public static $self_link_data_level = self::SELF_LINK_SERVER;
-
-/**
- * allow to toggle the auto generated links for relations
- * @todo allow to customize the format completly instead of only toggling
- */
-public static $relation_links = self::RELATION_LINKS_BOTH;
-
-/**
- * internal data containers
- */
-protected $primary_type = null;
-protected $primary_id = null;
-protected $primary_attributes = [];
-protected $primary_relationships = [];
-protected $primary_links = [];
-protected $primary_meta_data = [];
-
-/**
- * creates a new resource
- *
- * @param string $type typically the name of the endpoint or database table
- * @param mixed $id optional, provide if you want to provide this to the client
- * can be integer or hash or whatever
- */
-public function __construct($type, $id=null) {
- $this->primary_type = $type;
- $this->primary_id = $id;
-
- parent::__construct();
-}
-
-/**
- * get the primary type as set via the constructor
- *
- * @return string|null
- */
-public function get_type() {
- return $this->primary_type;
-}
-
-/**
- * get the primary id as set via the constructor
- *
- * @return mixed|null
- */
-public function get_id() {
- return $this->primary_id;
-}
-
-/**
- * whether data has been added via ->add_data()/->fill_data()
- * this can be useful when adding a resource to another one as included resource
- *
- * @return boolean
- */
-public function has_data() {
- return (bool)$this->primary_attributes;
-}
-
-/**
- * generates an array for the whole response body
- *
- * @see jsonapi.org/format
- *
- * @return array, containing:
- * - links
- * - data
- * - type
- * - id
- * - attributes
- * - relationships
- * - links
- * - meta
- * - included
- * - meta
- */
-public function get_array() {
- $response = [];
-
- // links
- if ($this->links) {
- $response['links'] = $this->links;
- }
-
- // primary data
- $response['data'] = [
- 'type' => $this->primary_type,
- ];
- if ($this->primary_id) {
- $response['data']['id'] = $this->primary_id;
- }
- if ($this->primary_attributes) {
- $response['data']['attributes'] = $this->primary_attributes;
- }
- if ($this->primary_relationships) {
- $response['data']['relationships'] = $this->primary_relationships;
- }
- if ($this->primary_links) {
- $response['data']['links'] = $this->primary_links;
- }
- if ($this->primary_meta_data) {
- $response['data']['meta'] = $this->primary_meta_data;
- }
-
- // included resources
- if ($this->included_data) {
- $response['included'] = array_values($this->included_data);
- }
-
- // meta data
- if ($this->meta_data) {
- $response['meta'] = $this->meta_data;
- }
-
- return $response;
-}
-
-/**
- * adds a data-point to the primary data
- * this will end up in response.data.attributes.{$key}
- *
- * values don't have to be scalar, it can be lists or objects as well
- *
- * @see ->fill_data() for adding a whole array directly
- *
- * @param string $key
- * @param mixed $value objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function add_data($key, $value) {
- if (is_object($value)) {
- $value = parent::convert_object_to_array($value);
- }
-
- $this->primary_attributes[$key] = $value;
-}
-
-/**
- * fills the primary data
- * this will end up in response.data.attributes
- *
- * this is meant for adding an array as the primary data
- * objects will be converted using their public keys
- *
- * @note skips an 'id'-key inside $values if identical to the $id given during construction
- *
- * @see ->add_data()
- *
- * @param mixed $values objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function fill_data($values) {
- if (is_object($values)) {
- $values = parent::convert_object_to_array($values);
- }
- if (is_array($values) == false) {
- throw new \Exception('use add_data() for adding scalar values');
- }
-
- if (isset($values['id']) && $values['id'] == $this->primary_id) {
- unset($values['id']);
- }
-
- foreach ($values as $key => $single_value) {
- $this->add_data($key, $single_value);
- }
-}
-
-/**
- * adds a relation to another resource
- * this will end up in response.data.relationships.{$key}
- *
- * $relation should be in the following format (any point can be omitted):
- * - links
- * - self
- * - related
- * - data
- * - type
- * - id
- *
- * if $relation is a jsonapi\resource or jsonapi\collection, it will also add an included resource
- * @see ->add_included_resource()
- *
- * @param string $key
- * @param mixed $relation can be array or jsonapi\resource or jsonapi\collection
- * @param boolean $skip_include optional, defaults to false
- * @param string $type optional, defaults to null
- * @return void
- *
- * @todo allow to add collections as well
- */
-public function add_relation($key, $relation, $skip_include=false, $type=null) {
- if ($type && in_array($type, [self::RELATION_TO_ONE, self::RELATION_TO_MANY]) == false) {
- throw new \Exception('unknown relation type');
- }
- if (isset($this->primary_relationships[$key]) && $relation instanceof \alsvanzelf\jsonapi\resource == false) {
- throw new \Exception('can not add a relation twice, unless using a resource object');
- }
- if (isset($this->primary_relationships[$key]) && $relation instanceof \alsvanzelf\jsonapi\resource) {
- if ($type != self::RELATION_TO_MANY || isset($this->primary_relationships[$key]['data']['type'])) {
- throw new \Exception('$type should be set to RELATION_TO_MANY for resources using the same key');
- }
- }
- if ($relation instanceof \alsvanzelf\jsonapi\collection && $type == self::RELATION_TO_ONE) {
- throw new \Exception('collections can only be added as RELATION_TO_MANY');
- }
-
- if ($relation instanceof \alsvanzelf\jsonapi\resource == false && $relation instanceof \alsvanzelf\jsonapi\collection == false && is_array($relation) == false) {
- throw new \Exception('unknown relation format');
- }
-
- if (is_array($relation)) {
- $this->primary_relationships[$key] = $relation;
- return;
- }
-
- if ($relation instanceof \alsvanzelf\jsonapi\resource) {
- // add whole resources as included resource, while keeping the relationship
- if ($relation->has_data() && $skip_include == false) {
- $this->add_included_resource($relation);
- }
-
- $base_url = (isset($this->primary_links['self']['href'])) ? $this->primary_links['self']['href'] : $this->primary_links['self'];
- $relation_id = $relation->get_id() ?: null;
- $relation_data = [
- 'type' => $relation->get_type(),
- 'id' => $relation_id,
- ];
-
- if (isset($this->primary_relationships[$key])) {
- $this->primary_relationships[$key]['data'][] = $relation_data;
- return;
- }
- if ($type == self::RELATION_TO_MANY) {
- $relation_data = [$relation_data];
- }
- }
- elseif ($relation instanceof \alsvanzelf\jsonapi\collection) {
- $relation_resources = $relation->get_resources();
-
- // add whole resources as included resource, while keeping the relationship
- if ($relation_resources && $skip_include == false) {
- $this->fill_included_resources($relation);
- }
-
- $base_url = (isset($this->primary_links['self']['href'])) ? $this->primary_links['self']['href'] : $this->primary_links['self'];
- $relation_data = [];
- foreach ($relation_resources as $relation_resource) {
- $relation_data[] = [
- 'type' => $relation_resource->get_type(),
- 'id' => $relation_resource->get_id(),
- ];
- }
- }
-
- $this->primary_relationships[$key] = [
- 'data' => $relation_data,
- ];
-
- $relation_links = [];
- if (self::$relation_links == self::RELATION_LINKS_RELATIONSHIP || self::$relation_links == self::RELATION_LINKS_BOTH) {
- $relation_links['self'] = $base_url.'/relationships/'.$key;
- }
- if (self::$relation_links == self::RELATION_LINKS_RESOURCE || self::$relation_links == self::RELATION_LINKS_BOTH) {
- $relation_links['related'] = $base_url.'/'.$key;
- }
-
- if ($relation_links) {
- $this->primary_relationships[$key]['links'] = $relation_links;
- }
-}
-
-/**
- * fills the relationships to other resources
- * this will end up in response.data.relationships
- *
- * @see ->add_relation()
- *
- * @param array $relations
- * @return void
- */
-public function fill_relations($relations, $skip_include=false) {
- foreach ($relations as $key => $relation) {
- $this->add_relation($key, $relation, $skip_include);
- }
-}
-
-/**
- * this will end up in response.data.links.{$key}
- * if $also_root is set to true, it will also end up in response.links.{$key}
- *
- * @see jsonapi\response->add_link()
- *
- * @param string $key
- * @param mixed $link objects are converted in arrays, @see base::convert_object_to_array()
- * @param mixed $meta_data should not be used if $link is non-string
- * @param string $level one of the predefined ones in ::LINK_LEVEL_*
- * @return void
- */
-public function add_link($key, $link, $meta_data=null, $level=self::LINK_LEVEL_DATA) {
- if (is_object($link)) {
- $link = parent::convert_object_to_array($link);
- }
-
- // can not combine both raw link object and extra meta data
- if ($meta_data && is_string($link) == false) {
- throw new \Exception('link "'.$key.'" should be a string if meta data is provided separate');
- }
-
- if ($level === self::LINK_LEVEL_DATA) {
- $revert_root_level = (isset($this->links[$key])) ? $this->links[$key] : null;
- }
-
- parent::add_link($key, $link, $meta_data);
-
- if ($level === self::LINK_LEVEL_DATA || $level === self::LINK_LEVEL_BOTH) {
- $this->primary_links[$key] = $this->links[$key];
- }
- if ($level === self::LINK_LEVEL_DATA) {
- if ($revert_root_level) {
- $this->links[$key] = $revert_root_level;
- }
- else {
- unset($this->links[$key]);
- }
- }
-}
-
-/**
- * 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\response->set_self_link() which only adds it to response.links.self
- *
- * @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\response::__construct()
- *
- * @param string $link
- * @param mixed $meta_data optional, meta data as key-value pairs
- * objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function set_self_link($link, $meta_data=null) {
- parent::set_self_link($link, $meta_data);
-
- if (self::$self_link_data_level == self::SELF_LINK_SERVER) {
- $this->add_link($key='self', $link, $meta_data);
- }
- if (self::$self_link_data_level == self::SELF_LINK_TYPE) {
- $link = '/'.$this->primary_type.'/'.$this->primary_id;
- $this->add_link($key='self', $link, $meta_data);
- }
-}
-
-/**
- * adds meta data to the default self link
- * this will end up in response.links.self.meta.{$key} and response.data.links.self.meta.{$key}
- * this overrides the jsonapi\response->add_self_link_meta() which only adds it to response.links.self.meta.{$key}
- *
- * @see jsonapi\response->add_self_link_meta()
- *
- * @note you can also use ->set_self_link() with the whole meta object at once
- *
- * @param string $key
- * @param mixed $meta_data objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function add_self_link_meta($key, $meta_data) {
- parent::add_self_link_meta($key, $meta_data);
-
- $this->primary_links['self'] = $this->links['self'];
-}
-
-/**
- * adds some meta data
- * this will end up in response.meta.{$key} or response.data.meta.{$key} ..
- * .. depending on $data_level
- *
- * @param string $key
- * @param mixed $meta_data objects are converted in arrays, @see base::convert_object_to_array()
- * @param boolean $data_level optional, defaults to false
- * @return void
- */
-public function add_meta($key, $meta_data, $data_level=false) {
- if ($data_level == false) {
- return parent::add_meta($key, $meta_data);
- }
-
- if (is_object($meta_data)) {
- $meta_data = parent::convert_object_to_array($meta_data);
- }
-
- $this->primary_meta_data[$key] = $meta_data;
-}
-
-/**
- * fills the meta data
- * this will end up in response.meta or response.data.meta ..
- * .. depending on $data_level
- *
- * @param array $meta_data
- * @param boolean $data_level optional, defaults to false
- * @return void
- */
-public function fill_meta($meta_data, $data_level=false) {
- foreach ($meta_data as $key => $single_meta_data) {
- $this->add_meta($key, $single_meta_data, $data_level);
- }
-}
-
-}
diff --git a/src/response.php b/src/response.php
deleted file mode 100644
index d41361d..0000000
--- a/src/response.php
+++ /dev/null
@@ -1,448 +0,0 @@
-send_response() sends out basic status headers
- * if set to true, it sends the status code and the location header
- */
-public static $send_status_headers = true;
-
-/**
- * internal data containers
- */
-protected $links = [];
-protected $meta_data = [];
-protected $included_data = [];
-protected $included_resources = [];
-protected $http_status = self::STATUS_OK;
-protected $redirect_location = null;
-
-/**
- * base constructor for all response objects (resource, collection, errors)
- *
- * a few things are arranged here:
- * - sets the self link using $_SERVER variables
- *
- * @see ->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();
-}
-
-/**
- * generates an array for the whole response body
- *
- * @see jsonapi.org/format
- *
- * @return array, containing:
- * - links
- * - meta
- */
-public function get_array() {
- $response = [];
-
- // links
- if ($this->links) {
- $response['links'] = $this->links;
- }
-
- // meta data
- if ($this->meta_data) {
- $response['meta'] = $this->meta_data;
- }
-
- return $response;
-}
-
-/**
- * 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
- *
- * @note this also sets the needed http headers (status, location and content-type)
- *
- * @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()
- * @param string $jsonp_callback optional, response as jsonp
- * @return void however, a string will be echo'd to the browser
- */
-public function send_response($content_type=null, $encode_options=null, $response=null, $jsonp_callback=null) {
- if (is_null($response) && $this->http_status != self::STATUS_NO_CONTENT) {
- $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;
- }
-
- if (self::$send_status_headers) {
- $this->send_status_headers();
- }
-
- header('Content-Type: '.$content_type.'; charset=utf-8');
-
- if ($this->http_status == self::STATUS_NO_CONTENT) {
- return;
- }
-
- // jsonp response
- if ($content_type == self::CONTENT_TYPE_JSONP) {
- if (empty($jsonp_callback)) {
- $jsonp_callback = self::JSONP_CALLBACK_DEFAULT;
- }
- echo $jsonp_callback.'('.$response.')';
- return;
- }
-
- echo $response;
-}
-
-/**
- * sends out the http status code and optional redirect location
- * defaults to ::STATUS_OK, or ::STATUS_INTERNAL_SERVER_ERROR for an errors response
- *
- * @return void
- */
-private function send_status_headers() {
- if ($this->redirect_location) {
- if ($this->http_status == self::STATUS_OK) {
- $this->set_http_status(self::STATUS_TEMPORARY_REDIRECT);
- }
-
- header('Location: '.$this->redirect_location, $replace=true, $this->http_status);
- return;
- }
-
- http_response_code($this->http_status);
-}
-
-/**
- * sets the http status code for this response
- *
- * @param int $http_status any will do, you can easily pass one of the predefined ones in ::STATUS_*
- */
-public function set_http_status($http_status) {
- $this->http_status = $http_status;
-}
-
-/**
- * sets a new location the client should follow
- *
- * @param string $location absolute url
- */
-public function set_redirect_location($location) {
- if (self::$send_status_headers == false && base::$debug) {
- trigger_error('location will not be send out unless response::$send_status_headers is true', E_USER_NOTICE);
- }
-
- $this->redirect_location = $location;
-}
-
-/**
- * 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;
-}
-
-/**
- * adds a link
- * this will end up in response.links.{$key}
- *
- * useful for links which can not be added as relation, @see ->add_relation()
- *
- * @param string $key
- * @param mixed $link string with link, or raw link object array/object
- * @param mixed $meta_data optional, meta data as key-value pairs
- * objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function add_link($key, $link, $meta_data=null) {
- if ($meta_data) {
- if (is_object($meta_data)) {
- $meta_data = parent::convert_object_to_array($meta_data);
- }
-
- $link = [
- 'href' => $link,
- 'meta' => $meta_data,
- ];
- }
-
- $this->links[$key] = $link;
-}
-
-/**
- * fills the set of links
- * this will end up in response.links
- *
- * @see ->add_link()
- *
- * @param array $links
- * @return void
- */
-public function fill_links($links) {
- foreach ($links as $key => $link) {
- $this->add_link($key, $link);
- }
-}
-
-/**
- * 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
- * @param mixed $meta_data optional, meta data as key-value pairs
- * objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function set_self_link($link, $meta_data=null) {
- if ($meta_data) {
- // can not combine both raw link object and extra meta data
- if (is_string($link) == false) {
- throw new \Exception('link "self" should be a string if meta data is provided separate');
- }
-
- if (is_object($meta_data)) {
- $meta_data = parent::convert_object_to_array($meta_data);
- }
-
- $link = [
- 'href' => $link,
- 'meta' => $meta_data,
- ];
- }
-
- $this->links['self'] = $link;
-}
-
-/**
- * adds meta data to the default self link
- * this will end up in response.links.self.meta.{$key}
- *
- * @note you can also use ->set_self_link() with the whole meta object at once
- *
- * @param string $key
- * @param mixed $meta_data objects are converted in arrays, @see base::convert_object_to_array()
- * @return void
- */
-public function add_self_link_meta($key, $meta_data) {
- if (is_object($meta_data)) {
- $meta_data = self::convert_to_array($meta_data);
- }
-
- // converts string-type link
- if (is_string($this->links['self'])) {
- $this->links['self'] = [
- 'href' => $this->links['self'],
- 'meta' => [],
- ];
- }
-
- $this->links['self']['meta'][$key] = $meta_data;
-}
-
-/**
- * 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;
- }
-
- // root-level meta-data
- if (!empty($resource_array['meta'])) {
- $this->fill_meta($resource_array['meta']);
- }
-
- $resource_array = $resource_array['data'];
-
- $key = $resource->get_type().'/'.$resource->get_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;
-
- // allow nesting relationshios
- foreach ($resource->get_included_resources() as $included_resource) {
- if (empty($included_resource->primary_id)) {
- continue;
- }
-
- $included_key = $included_resource->get_type().'/'.$included_resource->get_id();
-
- $this->included_resources[$included_key] = $included_resource;
-
- $included_array = $included_resource->get_array();
- $included_array = $included_array['data'];
- $this->included_data[$included_key] = $included_array;
- }
-}
-
-/**
- * fills the included resources
- * this will end up in response.included[]
- *
- * prefer using ->fill_relations() instead
- *
- * @param mixed $resources array of \alsvanzelf\jsonapi\resource objects
- * or \alsvanzelf\jsonapi\collection object
- * @return void
- */
-public function fill_included_resources($resources) {
- if ($resources instanceof \alsvanzelf\jsonapi\collection) {
- $resources = $resources->get_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);
- }
-}
-
-}