From 73ec0b17f60da2c8c6ce215ff6356f9685355cfe Mon Sep 17 00:00:00 2001
From: Clemens John <clemens.john@floh1111.de>
Date: Mon, 23 Jan 2017 10:42:36 +0100
Subject: [PATCH] Fix namespaces and paths. Add Exceptions and resources

Signed-off-by: Clemens John <clemens.john@floh1111.de>
---
 composer.json                                 |   3 +-
 resources/schemas/schema                      | 380 ++++++++++++++++++
 resources/schemas/schema-create               |  28 ++
 .../Exceptions/BodyValidationException.php    |  25 ++
 .../CollectionResourceController.php          |   4 +-
 .../Controllers/DefaultResourceController.php |   6 +-
 .../DocumentResourceController.php            |   4 +-
 src/Http/Controllers/JsonApiController.php    |   2 +-
 .../OneToOneResourceController.php            |   4 +-
 src/Serializers/BasicSerializer.php           |   2 +-
 src/Traits/CollectionResourceTrait.php        |   2 +-
 src/Traits/DocumentResourceTrait.php          |   2 +-
 src/Traits/StoreResourceTrait.php             |   8 +-
 13 files changed, 452 insertions(+), 18 deletions(-)
 create mode 100644 resources/schemas/schema
 create mode 100644 resources/schemas/schema-create
 create mode 100644 src/Exceptions/Exceptions/BodyValidationException.php

diff --git a/composer.json b/composer.json
index 370dd0e..2225274 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,8 @@
             "Netmon\\JsonApi\\": "src/",
             "Netmon\\JsonApi\\Http\\Controllers\\": "src/Http/Controllers/",
             "Netmon\\JsonApi\\Serializers\\": "src/Serializers/",
-            "Netmon\\JsonApi\\Traits\\": "src/Traits/"
+            "Netmon\\JsonApi\\Traits\\": "src/Traits/",
+            "Netmon\\JsonApi\\Exceptions\\Exceptions": "src/Exceptions/Exceptions/"
         }
     },
     "require": {
diff --git a/resources/schemas/schema b/resources/schemas/schema
new file mode 100644
index 0000000..7fe78cd
--- /dev/null
+++ b/resources/schemas/schema
@@ -0,0 +1,380 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "JSON API Schema",
+  "description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
+  "oneOf": [
+    {
+      "$ref": "file://schema#/definitions/success"
+    },
+    {
+      "$ref": "file://schema#/definitions/failure"
+    },
+    {
+      "$ref": "file://schema#/definitions/info"
+    }
+  ],
+
+  "definitions": {
+    "success": {
+      "type": "object",
+      "required": [
+        "data"
+      ],
+      "properties": {
+        "data": {
+          "$ref": "file://schema#/definitions/data"
+        },
+        "included": {
+          "description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".",
+          "type": "array",
+          "items": {
+            "$ref": "file://schema#/definitions/resource"
+          },
+          "uniqueItems": true
+        },
+        "meta": {
+          "$ref": "file://schema#/definitions/meta"
+        },
+        "links": {
+          "description": "Link members related to the primary data.",
+          "allOf": [
+            {
+              "$ref": "file://schema#/definitions/links"
+            },
+            {
+              "$ref": "file://schema#/definitions/pagination"
+            }
+          ]
+        },
+        "jsonapi": {
+          "$ref": "file://schema#/definitions/jsonapi"
+        }
+      },
+      "additionalProperties": false
+    },
+    "failure": {
+      "type": "object",
+      "required": [
+        "errors"
+      ],
+      "properties": {
+        "errors": {
+          "type": "array",
+          "items": {
+            "$ref": "file://schema#/definitions/error"
+          },
+          "uniqueItems": true
+        },
+        "meta": {
+          "$ref": "file://schema#/definitions/meta"
+        },
+        "jsonapi": {
+          "$ref": "file://schema#/definitions/jsonapi"
+        }
+      },
+      "additionalProperties": false
+    },
+    "info": {
+      "type": "object",
+      "required": [
+        "meta"
+      ],
+      "properties": {
+        "meta": {
+          "$ref": "file://schema#/definitions/meta"
+        },
+        "links": {
+          "$ref": "file://schema#/definitions/links"
+        },
+        "jsonapi": {
+          "$ref": "file://schema#/definitions/jsonapi"
+        }
+      },
+      "additionalProperties": false
+    },
+
+    "meta": {
+      "description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
+      "type": "object",
+      "additionalProperties": true
+    },
+    "data": {
+      "description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.",
+      "oneOf": [
+        {
+          "$ref": "file://schema#/definitions/resource"
+        },
+        {
+          "description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.",
+          "type": "array",
+          "items": {
+            "$ref": "file://schema#/definitions/resource"
+          },
+          "uniqueItems": true
+        }
+      ]
+    },
+
+    "newResource": {
+      "description": "\"Resource objects\" appear in a JSON API document to represent resources.",
+      "type": "object",
+      "required": [
+        "type"
+      ],
+      "properties": {
+        "type": {
+          "type": "string"
+        },
+        "id": {
+          "description": "A server **MAY** accept a client-generated ID along with a request to create a resource. An ID **MUST** be specified with an id key, the value of which **MUST** be a universally unique identifier. The client **SHOULD** use a properly generated and formatted UUID as described in RFC 4122.",
+          "type": "string"
+        },
+        "attributes": {
+          "$ref": "file://schema#/definitions/attributes"
+        },
+        "relationships": {
+          "$ref": "file://schema#/definitions/relationships"
+        },
+        "links": {
+          "$ref": "file://schema#/definitions/links"
+        },
+        "meta": {
+          "$ref": "file://schema#/definitions/meta"
+        }
+      },
+      "additionalProperties": false
+    },
+    "resource": {
+      "description": "\"Resource objects\" appear in a JSON API document to represent resources.",
+      "allOf": [
+        {
+          "$ref": "file://schema#/definitions/newResource"
+        },
+        {
+          "required": [
+            "type",
+            "id"
+          ]
+        }
+      ]
+    },
+
+    "links": {
+      "description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.",
+      "type": "object",
+      "properties": {
+        "self": {
+          "description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.",
+          "type": "string",
+          "format": "uri"
+        },
+        "related": {
+          "$ref": "file://schema#/definitions/link"
+        }
+      },
+      "additionalProperties": true
+    },
+    "link": {
+      "description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
+      "oneOf": [
+        {
+          "description": "A string containing the link's URL.",
+          "type": "string",
+          "format": "uri"
+        },
+        {
+          "type": "object",
+          "required": [
+            "href"
+          ],
+          "properties": {
+            "href": {
+              "description": "A string containing the link's URL.",
+              "type": "string",
+              "format": "uri"
+            },
+            "meta": {
+              "$ref": "file://schema#/definitions/meta"
+            }
+          }
+        }
+      ]
+    },
+
+    "attributes": {
+      "description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
+      "type": "object",
+      "patternProperties": {
+        "^(?!relationships$|links$)\\w[-\\w_]*$": {
+          "description": "Attributes may contain any valid JSON value."
+        }
+      },
+      "additionalProperties": false
+    },
+
+    "relationships": {
+      "description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
+      "type": "object",
+      "patternProperties": {
+        "^\\w[-\\w_]*$": {
+          "properties": {
+            "links": {
+              "$ref": "file://schema#/definitions/links"
+            },
+            "data": {
+              "description": "Member, whose value represents \"resource linkage\".",
+              "oneOf": [
+                {
+                  "$ref": "file://schema#/definitions/relationshipToOne"
+                },
+                {
+                  "$ref": "file://schema#/definitions/relationshipToMany"
+                }
+              ]
+            },
+            "meta": {
+              "$ref": "file://schema#/definitions/meta"
+            }
+          },
+          "additionalProperties": false
+        }
+      },
+      "additionalProperties": false
+    },
+    "relationshipToOne": {
+      "description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.",
+      "anyOf": [
+        {
+          "$ref": "file://schema#/definitions/empty"
+        },
+        {
+          "$ref": "file://schema#/definitions/linkage"
+        }
+      ]
+    },
+    "relationshipToMany": {
+      "description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
+      "type": "array",
+      "items": {
+        "$ref": "file://schema#/definitions/linkage"
+      },
+      "uniqueItems": true
+    },
+    "empty": {
+      "description": "Describes an empty to-one relationship.",
+      "type": ["object", "null"],
+      "properties": {},
+      "additionalProperties": false
+    },
+    "linkage": {
+      "description": "The \"type\" and \"id\" to non-empty members.",
+      "type": "object",
+      "required": [
+        "type",
+        "id"
+      ],
+      "properties": {
+        "type": {
+          "type": "string"
+        },
+        "id": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": false
+    },
+    "pagination": {
+      "type": "object",
+      "properties": {
+        "first": {
+          "description": "The first page of data",
+          "oneOf": [
+            { "type": "string", "format": "uri" },
+            { "type": "null" }
+          ]
+        },
+        "last": {
+          "description": "The last page of data",
+          "oneOf": [
+            { "type": "string", "format": "uri" },
+            { "type": "null" }
+          ]
+        },
+        "prev": {
+          "description": "The previous page of data",
+          "oneOf": [
+            { "type": "string", "format": "uri" },
+            { "type": "null" }
+          ]
+        },
+        "next": {
+          "description": "The next page of data",
+          "oneOf": [
+            { "type": "string", "format": "uri" },
+            { "type": "null" }
+          ]
+        }
+      }
+    },
+
+    "jsonapi": {
+      "description": "An object describing the server's implementation",
+      "type": "object",
+      "properties": {
+        "version": {
+          "type": "string"
+        },
+        "meta": {
+          "$ref": "file://schema#/definitions/meta"
+        }
+      },
+      "additionalProperties": false
+    },
+
+    "error": {
+      "type": "object",
+      "properties": {
+        "id": {
+          "description": "A unique identifier for this particular occurrence of the problem.",
+          "type": "string"
+        },
+        "links": {
+          "$ref": "file://schema#/definitions/links"
+        },
+        "status": {
+          "description": "The HTTP status code applicable to this problem, expressed as a string value.",
+          "type": "string"
+        },
+        "code": {
+          "description": "An application-specific error code, expressed as a string value.",
+          "type": "string"
+        },
+        "title": {
+          "description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
+          "type": "string"
+        },
+        "detail": {
+          "description": "A human-readable explanation specific to this occurrence of the problem.",
+          "type": "string"
+        },
+        "source": {
+          "type": "object",
+          "properties": {
+            "pointer": {
+              "description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].",
+              "type": "string"
+            },
+            "parameter": {
+              "description": "A string indicating which query parameter caused the error.",
+              "type": "string"
+            }
+          }
+        },
+        "meta": {
+          "$ref": "file://schema#/definitions/meta"
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/resources/schemas/schema-create b/resources/schemas/schema-create
new file mode 100644
index 0000000..e2abd78
--- /dev/null
+++ b/resources/schemas/schema-create
@@ -0,0 +1,28 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "JSON API Schema",
+  "description": "This is a schema for clients creating resources in the JSON API format. For more, see http://jsonapi.org",
+  "type": "object",
+  "required": [
+    "data"
+  ],
+  "properties": {
+    "data": {
+      "$ref": "file://schema-create#/definitions/newData"
+    },
+    "meta": {
+      "$ref": "file://schema#/definitions/meta"
+    },
+    "jsonapi": {
+      "$ref": "file://schema#/definitions/jsonapi"
+    }
+  },
+  "additionalProperties": false,
+
+  "definitions": {
+    "newData": {
+      "description": "A resource can be created by sending a `POST` request to a URL that represents a collection of resources. The request **MUST** include a single resource object as primary data.",
+      "$ref": "file://schema#/definitions/newResource"
+    }
+  }
+}
diff --git a/src/Exceptions/Exceptions/BodyValidationException.php b/src/Exceptions/Exceptions/BodyValidationException.php
new file mode 100644
index 0000000..52ced6f
--- /dev/null
+++ b/src/Exceptions/Exceptions/BodyValidationException.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Netmon\JsonApi\Exceptions\Exceptions;
+
+use Exception;
+use Illuminate\Support\MessageBag;
+
+class BodyValidationException extends Exception
+{
+    protected $code = 400;
+    protected $validationErrors;
+
+    public function __construct (
+        $message = "Request body validation failed.",
+        MessageBag $validationErrors,
+        Exception $previous = NULL
+    ) {
+        parent::__construct($message, $this->code, $previous);
+        $this->validationErrors = $validationErrors;
+    }
+
+    public function getValidationErrors() {
+        return $this->validationErrors;
+    }
+}
diff --git a/src/Http/Controllers/CollectionResourceController.php b/src/Http/Controllers/CollectionResourceController.php
index e27da6b..1dc153b 100644
--- a/src/Http/Controllers/CollectionResourceController.php
+++ b/src/Http/Controllers/CollectionResourceController.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Netmon\Server\App\Http\Controllers\JsonApi;
+namespace Netmon\JsonApi\Http\Controllers\JsonApi;
 
-use Netmon\Server\App\Traits\CollectionResourceTrait;
+use Netmon\JsonApi\Traits\CollectionResourceTrait;
 
 abstract class CollectionResourceController extends JsonApiController
 {
diff --git a/src/Http/Controllers/DefaultResourceController.php b/src/Http/Controllers/DefaultResourceController.php
index 06f1045..a489958 100644
--- a/src/Http/Controllers/DefaultResourceController.php
+++ b/src/Http/Controllers/DefaultResourceController.php
@@ -1,9 +1,9 @@
 <?php
 
-namespace Netmon\Server\App\Http\Controllers\JsonApi;
+namespace Netmon\JsonApi\Http\Controllers\JsonApi;
 
-use Netmon\Server\App\Traits\StoreResourceTrait;
-use Netmon\Server\App\Traits\CollectionResourceTrait;
+use Netmon\JsonApi\Traits\StoreResourceTrait;
+use Netmon\JsonApi\Traits\CollectionResourceTrait;
 
 abstract class DefaultResourceController extends JsonApiController
 {
diff --git a/src/Http/Controllers/DocumentResourceController.php b/src/Http/Controllers/DocumentResourceController.php
index c005a89..fd16ec9 100644
--- a/src/Http/Controllers/DocumentResourceController.php
+++ b/src/Http/Controllers/DocumentResourceController.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Netmon\Server\App\Http\Controllers\JsonApi;
+namespace Netmon\JsonApi\Http\Controllers\JsonApi;
 
-use Netmon\Server\App\Traits\DocumentResourceTrait;
+use Netmon\JsonApi\Traits\DocumentResourceTrait;
 
 abstract class DocumentResourceController extends JsonApiController
 {
diff --git a/src/Http/Controllers/JsonApiController.php b/src/Http/Controllers/JsonApiController.php
index 389556f..67b4367 100644
--- a/src/Http/Controllers/JsonApiController.php
+++ b/src/Http/Controllers/JsonApiController.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Netmon\Server\App\Http\Controllers\JsonApi;
+namespace Netmon\JsonApi\Http\Controllers\JsonApi;
 
 use Illuminate\Routing\Controller;
 
diff --git a/src/Http/Controllers/OneToOneResourceController.php b/src/Http/Controllers/OneToOneResourceController.php
index 089f106..3f8fba3 100644
--- a/src/Http/Controllers/OneToOneResourceController.php
+++ b/src/Http/Controllers/OneToOneResourceController.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Netmon\Server\App\Http\Controllers\JsonApi;
+namespace Netmon\JsonApi\Http\Controllers\JsonApi;
 
-use Netmon\Server\App\Traits\StoreResourceTrait;
+use Netmon\JsonApi\Traits\StoreResourceTrait;
 
 abstract class OneToOneResourceController extends JsonApiController
 {
diff --git a/src/Serializers/BasicSerializer.php b/src/Serializers/BasicSerializer.php
index a9cfc28..178c741 100644
--- a/src/Serializers/BasicSerializer.php
+++ b/src/Serializers/BasicSerializer.php
@@ -1,4 +1,4 @@
-<?php namespace Netmon\Server\App\Serializers;
+<?php namespace Netmon\JsonApi\Serializers;
 
 use Illuminate\Contracts\Container\Container;
 use DateTime;
diff --git a/src/Traits/CollectionResourceTrait.php b/src/Traits/CollectionResourceTrait.php
index 76c77f5..d011ecb 100644
--- a/src/Traits/CollectionResourceTrait.php
+++ b/src/Traits/CollectionResourceTrait.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Netmon\Server\App\Traits;
+namespace Netmon\JsonApi\Traits;
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
diff --git a/src/Traits/DocumentResourceTrait.php b/src/Traits/DocumentResourceTrait.php
index 630316f..ec685ec 100644
--- a/src/Traits/DocumentResourceTrait.php
+++ b/src/Traits/DocumentResourceTrait.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Netmon\Server\App\Traits;
+namespace Netmon\JsonApi\Traits;
 
 use Gate;
 
diff --git a/src/Traits/StoreResourceTrait.php b/src/Traits/StoreResourceTrait.php
index f351c7e..d8f432c 100644
--- a/src/Traits/StoreResourceTrait.php
+++ b/src/Traits/StoreResourceTrait.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Netmon\Server\App\Traits;
+namespace Netmon\JsonApi\Traits;
 
-use Netmon\Server\App\Exceptions\Exceptions\BodyValidationException;
+use Netmon\JsonApi\Exceptions\Exceptions\BodyValidationException;
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -42,10 +42,10 @@ trait StoreResourceTrait {
         $requestBody = $request->getContent();
         $requestBodyObject = json_decode($requestBody);
 
-        $jsonBaseSchema = file_get_contents(resource_path('schemas/schema'));
+        $jsonBaseSchema = file_get_contents(base_path('vendor/netmon-server/laravel-jsonapi/resources/schemas/schema'));
         $jsonBaseSchemaObject = json_decode($jsonBaseSchema);
 
-        $jsonCreateSchema = file_get_contents(resource_path('schemas/schema-create'));
+        $jsonCreateSchema = file_get_contents(base_path('vendor/netmon-server/laravel-jsonapi/resources/schemas/schema'));
         $jsonCreateSchemaObject = json_decode($jsonCreateSchema);
 
         // The SchemaStorage can resolve references, loading additional schemas from file as needed, etc.
-- 
GitLab