diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..0b98694
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: Lansoweb
diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md
new file mode 100644
index 0000000..1d003a7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Bug_Report.md
@@ -0,0 +1,35 @@
+---
+name: Bug Report
+about: Create a bug report to help us improve
+labels: bug
+assignees:
+---
+
+
+## Description
+
+
+## Steps to reproduce
+
+1. Step one...
+2. Step two...
+3. Step three...
+
+## Expected behavior
+
+
+## Screenshots or output
+
+
+## Environment details
+
+- version of this package: *e.g. 1.0.0, 1.0.1, 1.1.0*
+- PHP version: *e.g. 7.3.16, 7.4.4*
+- OS: *e.g. Windows 10, Linux (Ubuntu 18.04.1), macOS Catalina (10.15.3)*
+
+## Additional context
+
diff --git a/.github/ISSUE_TEMPLATE/Feature_Request.md b/.github/ISSUE_TEMPLATE/Feature_Request.md
new file mode 100644
index 0000000..fdde4b2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Feature_Request.md
@@ -0,0 +1,31 @@
+---
+name: Feature Request
+about: Suggest a feature for this project
+labels: enhancement
+assignees:
+---
+
+
+
+## My feature title
+
+
+## Background/problem
+
+
+## Proposal/solution
+
+
+## Alternatives
+
+
+## Additional context
+
diff --git a/.github/ISSUE_TEMPLATE/Question.md b/.github/ISSUE_TEMPLATE/Question.md
new file mode 100644
index 0000000..5c76b2a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Question.md
@@ -0,0 +1,19 @@
+---
+name: Question
+about: Ask a question about how to use this library
+labels: question
+assignees:
+---
+
+
+
+## How do I... ?
+
+
+## Example code
+
diff --git a/.github/PULL_REQUEST_TEMPLATE/Pull_Request_Template.md b/.github/PULL_REQUEST_TEMPLATE/Pull_Request_Template.md
new file mode 100644
index 0000000..df4646c
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/Pull_Request_Template.md
@@ -0,0 +1,30 @@
+
+
+## Description
+
+
+## Motivation and context
+
+
+
+## How has this been tested?
+
+
+
+
+## Types of changes
+
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to change)
+
+## PR checklist
+
+
+- [ ] My code follows the code style of this project.
+- [ ] My change requires a change to the documentation.
+- [ ] I have updated the documentation accordingly.
+- [ ] I have read the **CONTRIBUTING** document.
+- [ ] I have added tests to cover my changes.
+- [ ] All new and existing tests passed.
+- [ ] I have run `composer test` locally, and there were no failures or errors.
diff --git a/.github/workflows/coding-standard.yml b/.github/workflows/coding-standard.yml
new file mode 100644
index 0000000..4d504e2
--- /dev/null
+++ b/.github/workflows/coding-standard.yml
@@ -0,0 +1,45 @@
+name: "Check Coding Standards"
+
+on:
+ pull_request:
+ push:
+ branches:
+ - "master"
+
+jobs:
+ coding-standards:
+ name: "Check Coding Standards"
+
+ runs-on: ${{ matrix.operating-system }}
+
+ strategy:
+ matrix:
+ dependencies:
+ - "highest"
+ php-version:
+ - "8.2"
+ operating-system:
+ - "ubuntu-latest"
+
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v3"
+
+ - name: "Install PHP"
+ uses: "shivammathur/setup-php@v2"
+ with:
+ coverage: "pcov"
+ php-version: "${{ matrix.php-version }}"
+ ini-values: memory_limit=-1
+ tools: composer:v2
+
+ - uses: "ramsey/composer-install@v1"
+ with:
+ dependency-versions: "${{ matrix.dependencies }}"
+ composer-options: "${{ matrix.composer-options }}"
+
+ - name: "phpcs"
+ run: "vendor/bin/phpcs"
+
+ - name: "phpstan"
+ run: "vendor/bin/phpstan analyze"
diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml
new file mode 100644
index 0000000..c7613e4
--- /dev/null
+++ b/.github/workflows/release-on-milestone-closed.yml
@@ -0,0 +1,65 @@
+name: "Automatic Releases"
+
+on:
+ milestone:
+ types:
+ - "closed"
+
+jobs:
+ release:
+ name: "GIT tag, release & create merge-up PR"
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v3"
+
+ - name: "Release"
+ uses: "laminas/automatic-releases@v1"
+ with:
+ command-name: "laminas:automatic-releases:release"
+ env:
+ "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
+ "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
+ "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
+ "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
+
+ - name: "Create Merge-Up Pull Request"
+ uses: "laminas/automatic-releases@v1"
+ with:
+ command-name: "laminas:automatic-releases:create-merge-up-pull-request"
+ env:
+ "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
+ "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
+ "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
+ "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
+
+ - name: "Create and/or Switch to new Release Branch"
+ uses: "laminas/automatic-releases@v1"
+ with:
+ command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
+ env:
+ "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
+ "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
+ "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
+ "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
+
+ - name: "Bump Changelog Version On Originating Release Branch"
+ uses: "laminas/automatic-releases@v1"
+ with:
+ command-name: "laminas:automatic-releases:bump-changelog"
+ env:
+ "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
+ "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
+ "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
+ "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
+
+ - name: "Create new milestones"
+ uses: "laminas/automatic-releases@v1"
+ with:
+ command-name: "laminas:automatic-releases:create-milestones"
+ env:
+ "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
+ "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
+ "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
+ "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
diff --git a/.gitignore b/.gitignore
index e58358a..74180cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
.~lock.*
vendor
/composer.lock
+/build
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b6b2db..ba7b649 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,28 @@ All notable changes to this project will be documented in this file, in reverse
- Nothing.
+## 3.5.2 - TBD
+
+### Added
+
+- Nothing.
+
+### Changed
+
+- Nothing.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
## 3.4.1 - 2020-03-06
### Added
diff --git a/composer.json b/composer.json
index a28ef75..cc42555 100644
--- a/composer.json
+++ b/composer.json
@@ -1,59 +1,59 @@
{
"name": "los/api-server",
"description": "PHP api server middleware",
+ "license": "MIT",
+ "type": "library",
+ "authors": [
+ {
+ "name": "Leandro Silva",
+ "homepage": "https://sillotec.com/"
+ }
+ ],
+ "homepage": "https://github.com/lansoweb/api-server",
"require": {
- "php": "^7.4 | ^8.0",
+ "php": "^8.0",
"ext-json": "*",
- "psr/container": "^1.0 | ^2.0",
- "psr/http-message": "^1.0",
- "laminas/laminas-inputfilter": "^2.7",
- "laminas/laminas-paginator": "^2.7",
+ "laminas/laminas-diactoros": "^3.2",
"laminas/laminas-eventmanager": "^3.0",
- "psr/http-server-middleware": "^1.0",
+ "laminas/laminas-inputfilter": "^2.27",
+ "laminas/laminas-paginator": "^2.7",
+ "los/uql": "^1.1",
"mezzio/mezzio-hal": "^2.0",
"mezzio/mezzio-helpers": "^5.6",
"mezzio/mezzio-problem-details": "^1.0",
- "laminas/laminas-diactoros": "^1.7 || ^2.2",
- "los/uql": "^1.1",
- "doctrine/coding-standard": "^9.0"
+ "psr/container": "^1.0 || ^2.0",
+ "psr/http-message": "^1.0 || ^2.0",
+ "psr/http-server-middleware": "^1.0"
},
"require-dev": {
- "squizlabs/php_codesniffer": "^3.6",
- "phpstan/phpstan": "^0.12",
+ "doctrine/coding-standard": "^12.0",
"laminas/laminas-db": "^2.10",
- "laminas/laminas-hydrator": "^4.0"
+ "laminas/laminas-hydrator": "^4.0",
+ "phpstan/phpstan": "^1.10",
+ "squizlabs/php_codesniffer": "^3.6"
},
- "license": "MIT",
- "autoload-dev": {
+ "autoload": {
"psr-4": {
- "LosMiddleware\\ApiServerTest\\": "test/"
+ "Los\\ApiServer\\": "src/"
}
},
- "autoload": {
+ "autoload-dev": {
"psr-4": {
- "LosMiddleware\\ApiServer\\": "src/"
+ "Los\\ApiServerTest\\": "test/"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
}
},
- "type": "library",
"scripts": {
- "cs-check": "phpcs",
- "cs-fix": "phpcbf",
"check": [
"@cs-check",
"@phpstan"
],
- "phpstan": "phpstan analyse -l 4 -c phpstan.neon src"
- },
- "homepage": "https://github.com/lansoweb/api-server",
- "authors": [
- {
- "name": "Leandro Silva",
- "homepage": "http://leandrosilva.info/"
- }
- ],
- "extra": {
- "zf": {
- "config-provider": "LosMiddleware\\ApiServer\\ConfigProvider"
- }
+ "cs-check": "phpcs",
+ "cs-fix": "phpcbf",
+ "phpstan": "phpstan analyse"
}
}
diff --git a/phpcs.xml b/phpcs.xml
deleted file mode 100644
index ce46b35..0000000
--- a/phpcs.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
- config
- src
-
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 0000000..1b68193
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,23 @@
+
+
+
+ Project coding standards
+
+
+
+
+
+ ./src
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpstan.neon b/phpstan.neon
deleted file mode 100644
index 309d9e3..0000000
--- a/phpstan.neon
+++ /dev/null
@@ -1,3 +0,0 @@
-parameters:
- ignoreErrors:
- - '#Method LosMiddleware\\ApiServer\\Mapper\\ZendDbMapper::findOneBy\(\) should return LosMiddleware\\ApiServer\\Entity\\EntityInterface|null but returns array|ArrayObject|null.#'
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..0f7b07e
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,10 @@
+parameters:
+ level: max
+ tmpDir: ./build/cache/phpstan
+ checkMissingIterableValueType: false
+ paths:
+ - ./src
+ ignoreErrors:
+ - '#no type specified#'
+ - '#mixed#'
+ - '#not specify its types#'
diff --git a/src/Auth/AuthFactory.php b/src/Auth/AuthFactory.php
deleted file mode 100644
index 51b6661..0000000
--- a/src/Auth/AuthFactory.php
+++ /dev/null
@@ -1,26 +0,0 @@
-get('config')['los']['api_server']['auth'] ?? [];
- $users = $config['clients'] ?? [];
- $allowedPaths = $config['allowedPaths'] ?? [];
-
- return new AuthMiddleware($users, $allowedPaths, $container->get(ProblemDetailsResponseFactory::class));
- }
-}
diff --git a/src/Auth/AuthMiddleware.php b/src/Auth/AuthMiddleware.php
deleted file mode 100644
index b8365d1..0000000
--- a/src/Auth/AuthMiddleware.php
+++ /dev/null
@@ -1,98 +0,0 @@
-users = $users;
- $this->allowedPaths = $allowedPaths;
- $this->problemDetailsResponseFactory = $problemDetailsResponseFactory;
- }
-
- /**
- * @param Request $request
- * @param RequestHandlerInterface $handler
- * @return Response
- */
- public function process(Request $request, RequestHandlerInterface $handler): Response
- {
- try {
- $this->validate($request);
- } catch (RuntimeException $ex) {
- return $this->problemDetailsResponseFactory->createResponseFromThrowable($request, $ex);
- }
-
- return $handler->handle($request);
- }
-
- /**
- * @param Request $request
- */
- protected function validate(Request $request) : void
- {
- if (in_array($request->getUri()->getPath(), $this->allowedPaths)) {
- return;
- }
-
- if (! $request->hasHeader('authorization')) {
- throw AuthorizationException::create('Missing Authorization header');
- }
-
- $token = $request->getHeader('authorization');
-
- if (empty($token)) {
- throw AuthorizationException::create('Missing Authorization header');
- }
- $token = $token[0];
-
- if (! preg_match('/^basic/i', $token)) {
- throw AuthorizationException::create('Invalid Authorization header');
- }
-
- $auth = base64_decode(substr($token, 6));
- if (! $auth) {
- throw AuthorizationException::create('Unable to parse Authorization header');
- }
-
- $tokens = explode(':', $auth);
- if (count($tokens) != 2) {
- throw AuthorizationException::create('Invalid Authorization header during parse');
- }
-
- $identity = $tokens[0];
- $credential = $tokens[1];
- if (! array_key_exists($identity, $this->users)) {
- throw AuthorizationException::create('Authorization failed');
- }
-
- if ($this->users[$identity] != $credential && ! hash_equals($this->users[$identity], $credential)) {
- throw AuthorizationException::create('Authorization failed');
- }
- }
-}
diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php
index 7a009c6..d156b64 100644
--- a/src/ConfigProvider.php
+++ b/src/ConfigProvider.php
@@ -1,9 +1,8 @@
[
- Auth\AuthMiddleware::class => Auth\AuthFactory::class,
- ],
+ 'factories' => [],
];
}
}
diff --git a/src/Entity/Collection.php b/src/Entity/Collection.php
index 4303767..996b76c 100644
--- a/src/Entity/Collection.php
+++ b/src/Entity/Collection.php
@@ -1,7 +1,8 @@
$value) {
$fieldName = $filter($key);
- $method = 'set'.ucfirst($fieldName);
+ $method = 'set' . ucfirst($fieldName);
if (method_exists($this, $method)) {
$this->$method($value);
} elseif (property_exists($this, $fieldName)) {
@@ -38,28 +51,29 @@ public function exchangeArray(array $data)
/**
* Return an array representation of the object
+ *
* @see \Laminas\Stdlib\ArraySerializableInterface::getArrayCopy()
*/
- public function getArrayCopy() : array
+ public function getArrayCopy(): array
{
-
if (empty($this->fields)) {
$fields = get_object_vars($this);
unset($fields['inputFilter']);
unset($fields['fields']);
$this->fields = array_keys($fields);
}
- $filter = new CamelCaseToUnderscore();
+
+ $filter = new CamelCaseToUnderscore();
$filterStudly = new UnderscoreToStudlyCase();
$list = [];
foreach ($this->fields as $field) {
- $property = $filterStudly($field);
+ $property = $filterStudly($field);
$fieldName = extension_loaded('mbstring')
? mb_strtolower($filter($field))
: strtolower($filter($field));
- $method = 'get'.ucfirst($property);
+ $method = 'get' . ucfirst($property);
if (method_exists($this, $method)) {
$list[$fieldName] = $this->$method();
} elseif (property_exists($this, $property)) {
@@ -76,32 +90,37 @@ public function getArrayCopy() : array
* Returns the $data filtered by existant properties only.
*
* @param array $data
+ *
* @return array
*/
- public function filterData(array $data) : array
+ public function filterData(array $data): array
{
$this->exchangeArray($data);
+
return $this->getArrayCopy();
}
/**
* Define which fields will be returned by getArrayCopy
+ *
* @param array $fields
*/
- public function setFields(array $fields) : void
+ public function setFields(array $fields): void
{
- $this->fields = array_merge([static::IDENTIFIER_NAME], $fields);
+ $this->fields = array_merge([self::IDENTIFIER_NAME], $fields);
}
/**
* @param array $data
+ *
* @return array
*/
- public function prepareDataForStorage(array $data = []) : array
+ public function prepareDataForStorage(array $data = []): array
{
if (empty($data)) {
$data = $this->getArrayCopy();
}
+
return $data;
}
}
diff --git a/src/Entity/EntityInterface.php b/src/Entity/EntityInterface.php
index 277399c..f99f0e1 100644
--- a/src/Entity/EntityInterface.php
+++ b/src/Entity/EntityInterface.php
@@ -1,5 +1,8 @@
status = 401;
$exception->detail = $message;
- $exception->type = '';
- $exception->title = '';
+ $exception->type = '';
+ $exception->title = '';
+
return $exception;
}
}
diff --git a/src/Exception/MethodNotAllowedException.php b/src/Exception/MethodNotAllowedException.php
index 0a4a832..d3381e1 100644
--- a/src/Exception/MethodNotAllowedException.php
+++ b/src/Exception/MethodNotAllowedException.php
@@ -1,7 +1,8 @@
status = 405;
$exception->detail = $message;
- $exception->type = '';
- $exception->title = '';
+ $exception->type = '';
+ $exception->title = '';
+
return $exception;
}
}
diff --git a/src/Exception/NotFoundException.php b/src/Exception/NotFoundException.php
index b1b943f..84f3464 100644
--- a/src/Exception/NotFoundException.php
+++ b/src/Exception/NotFoundException.php
@@ -1,7 +1,8 @@
status = 404;
$exception->detail = $message;
- $exception->type = '';
- $exception->title = '';
+ $exception->type = '';
+ $exception->title = '';
+
return $exception;
}
}
diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php
index 740564b..08a54e1 100644
--- a/src/Exception/RuntimeException.php
+++ b/src/Exception/RuntimeException.php
@@ -1,7 +1,8 @@
status = 422;
- $exception->detail = 'Unprocessable Entity';
- $exception->type = '';
- $exception->title = '';
+ $exception = new self('Unprocessable Entity', 422);
+ $exception->status = 422;
+ $exception->detail = 'Unprocessable Entity';
+ $exception->type = '';
+ $exception->title = '';
$exception->additional = ['messages' => $messages];
+
return $exception;
}
}
diff --git a/src/Handler/AbstractRestHandler.php b/src/Handler/AbstractRestHandler.php
index 6e29464..844b838 100644
--- a/src/Handler/AbstractRestHandler.php
+++ b/src/Handler/AbstractRestHandler.php
@@ -1,72 +1,64 @@
urlHelper = $urlHelper;
- $this->problemDetailsResponseFactory = $problemDetailsResponseFactory;
- $this->resourceGenerator = $resourceGenerator;
- $this->responseFactory = $responseFactory;
}
/**
* Method to return the resource name for collections generation
- *
- * @return string
*/
- public function getResourceName() : string
+ public function getResourceName(): string
{
- $tokens = explode('\\', get_class($this));
+ $tokens = explode('\\', static::class);
$className = end($tokens);
+
return strtolower(str_replace('Handler', '', $className));
}
- /**
- * @param Request $request
- * @return Response
- */
public function handle(Request $request): Response
{
$requestMethod = strtoupper($request->getMethod());
@@ -79,36 +71,44 @@ public function handle(Request $request): Response
}
}
- protected function handleMethods(string $requestMethod) : Response
+ protected function handleMethods(string $requestMethod): Response
{
- $id = $this->request->getAttribute(static::IDENTIFIER_NAME);
+ $id = $this->request->getAttribute(self::IDENTIFIER_NAME);
switch ($requestMethod) {
case 'GET':
return isset($id)
? $this->handleFetch($id)
: $this->handleFetchAll();
+
case 'POST':
if (isset($id)) {
throw MethodNotAllowedException::create('Method Not Allowed for Entity');
}
+
return $this->handlePost();
+
case 'PUT':
return isset($id)
? $this->handleUpdate($id)
: $this->handleUpdateList();
+
case 'PATCH':
return isset($id)
? $this->handlePatch($id)
: $this->handlePatchList();
+
case 'DELETE':
return isset($id)
? $this->handleDelete($id)
: $this->handleDeleteList();
+
case 'HEAD':
return $this->head();
+
case 'OPTIONS':
return $this->options();
+
default:
throw MethodNotAllowedException::create();
}
@@ -117,10 +117,11 @@ protected function handleMethods(string $requestMethod) : Response
/**
* Call the inputfilter to filter and validate data
*
- * @throws ValidationException
* @return array
+ *
+ * @throws ValidationException
*/
- protected function validateBody() : array
+ protected function validateBody(): array
{
$data = $this->request->getParsedBody();
@@ -128,11 +129,11 @@ protected function validateBody() : array
$data = [];
}
- if ($this->entityPrototype == null || ! ($this->entityPrototype instanceof InputFilterAwareInterface)) {
+ if (! isset($this->entityPrototype) || ! ($this->entityPrototype instanceof InputFilterAwareInterface)) {
return $data;
}
- if (strtoupper($this->request->getMethod()) == 'PATCH') {
+ if (strtoupper($this->request->getMethod()) === 'PATCH') {
$this->entityPrototype->getInputFilter()->setValidationGroup(array_keys($data));
}
@@ -144,32 +145,37 @@ protected function validateBody() : array
$parsed = [];
foreach ($values as $key => $value) {
- if (array_key_exists($key, $data)) {
- $parsed[$key] = $value;
+ if (! array_key_exists($key, $data)) {
+ continue;
}
+
+ $parsed[$key] = $value;
}
+
return $parsed;
}
/**
* Generates a proper response based on the Entity ot Collection
*/
- protected function generateResponse($entity, int $code = 200) : Response
+ protected function generateResponse($entity, int $code = 200): Response
{
if ($entity instanceof Entity) {
$resource = $this->resourceGenerator->fromObject($entity, $this->request);
+
return $this->responseFactory->createResponse($this->request, $resource);
}
$queryParams = $this->request->getQueryParams();
$metadataMap = $this->resourceGenerator->getMetadataMap();
- /** @var RouteBasedCollectionMetadata $metadata */
- $metadata = $metadataMap->get(get_class($entity));
+ $metadata = $metadataMap->get($entity::class);
+ assert($metadata instanceof RouteBasedCollectionMetadata);
$metadataQuery = $origMetadataQuery = $metadata->getQueryStringArguments();
foreach ($queryParams as $key => $value) {
$metadataQuery = array_merge($metadataQuery, [$key => $value]);
}
+
$metadata->setQueryStringArguments($metadataQuery);
$resource = $this->resourceGenerator->fromObject($entity, $this->request);
@@ -188,35 +194,30 @@ protected function generateResponse($entity, int $code = 200) : Response
/**
* Fetch an Entity
- *
- * @param mixed $id
- * @return Response
*/
- protected function handleFetch($id) : Response
+ protected function handleFetch(mixed $id): Response
{
$entity = $this->fetch($id);
+
return $this->generateResponse($entity);
}
/**
* Fetch a collection
- *
- * @return Response
*/
- protected function handleFetchAll() : Response
+ protected function handleFetchAll(): Response
{
$list = $this->fetchAll();
+
return $this->generateResponse($list);
}
/**
* Create a new Entity
- *
- * @return Response
*/
- protected function handlePost() : Response
+ protected function handlePost(): Response
{
- $data = $this->validateBody();
+ $data = $this->validateBody();
$entity = $this->create($data);
return $this->generateResponse($entity, 201);
@@ -224,13 +225,10 @@ protected function handlePost() : Response
/**
* Update an Entity
- *
- * @param mixed $id
- * @return Response
*/
- protected function handleUpdate($id) : Response
+ protected function handleUpdate(mixed $id): Response
{
- $data = $this->validateBody();
+ $data = $this->validateBody();
$entity = $this->update($id, $data);
return $this->generateResponse($entity);
@@ -238,10 +236,8 @@ protected function handleUpdate($id) : Response
/**
* Update a collection
- *
- * @return Response
*/
- protected function handleUpdateList() : Response
+ protected function handleUpdateList(): Response
{
$data = $this->validateBody();
$list = $this->updateList($data);
@@ -251,13 +247,10 @@ protected function handleUpdateList() : Response
/**
* Update some properties from an Entity
- *
- * @param mixed $id
- * @return Response
*/
- protected function handlePatch($id) : Response
+ protected function handlePatch(mixed $id): Response
{
- $data = $this->validateBody();
+ $data = $this->validateBody();
$entity = $this->patch($id, $data);
return $this->generateResponse($entity);
@@ -265,10 +258,8 @@ protected function handlePatch($id) : Response
/**
* Updates some properties from a Collection
- *
- * @return Response
*/
- protected function handlePatchList() : Response
+ protected function handlePatchList(): Response
{
$data = $this->validateBody();
$list = $this->patchList($data);
@@ -279,12 +270,12 @@ protected function handlePatchList() : Response
/**
* Delete an Entity
*
- * @param mixed $id
* @return EmptyResponse
*/
- protected function handleDelete($id) : Response
+ protected function handleDelete(mixed $id): Response
{
$this->delete($id);
+
return new EmptyResponse(204);
}
@@ -293,18 +284,15 @@ protected function handleDelete($id) : Response
*
* @return EmptyResponse
*/
- protected function handleDeleteList() : Response
+ protected function handleDeleteList(): Response
{
$this->deleteList();
+
return new EmptyResponse(204);
}
- /**
- * @param mixed $id
- * @param array $where
- * @return EntityInterface
- */
- public function fetch($id, array $where = []): EntityInterface
+ /** @param array $where */
+ public function fetch(mixed $id, array $where = []): EntityInterface
{
throw MethodNotAllowedException::create();
}
@@ -312,48 +300,39 @@ public function fetch($id, array $where = []): EntityInterface
/**
* @param array $where
* @param array $options
- * @return Collection
*/
public function fetchAll(array $where = [], array $options = []): Collection
{
throw MethodNotAllowedException::create();
}
- /**
- * @param array $data
- * @return EntityInterface
- */
- public function create(array $data) : EntityInterface
+ /** @param array $data */
+ public function create(array $data): EntityInterface
{
throw MethodNotAllowedException::create();
}
/**
- * @param mixed $id
* @param array $data
* @param array $where
- * @return EntityInterface
*/
- public function update($id, array $data, array $where = []): EntityInterface
+ public function update(mixed $id, array $data, array $where = []): EntityInterface
{
throw MethodNotAllowedException::create();
}
- public function updateList(array $data) : Collection
+ public function updateList(array $data): Collection
{
throw MethodNotAllowedException::create();
}
- /**
- * @param mixed $id
- * @param array $where
- */
- public function delete($id, array $where = [])
+ /** @param array $where */
+ public function delete(mixed $id, array $where = []): void
{
throw MethodNotAllowedException::create();
}
- public function deleteList()
+ public function deleteList(): void
{
throw MethodNotAllowedException::create();
}
@@ -369,17 +348,15 @@ public function options(): Response
}
/**
- * @param mixed $id
* @param array $data
* @param array $where
- * @return EntityInterface
*/
- public function patch($id, array $data, array $where = []): EntityInterface
+ public function patch(mixed $id, array $data, array $where = []): EntityInterface
{
throw MethodNotAllowedException::create();
}
- public function patchList(array $data) : Collection
+ public function patchList(array $data): Collection
{
throw MethodNotAllowedException::create();
}
diff --git a/src/Handler/MapperRestHandler.php b/src/Handler/MapperRestHandler.php
index 641850f..e88daf6 100644
--- a/src/Handler/MapperRestHandler.php
+++ b/src/Handler/MapperRestHandler.php
@@ -1,52 +1,62 @@
mapper = $mapper;
$this->entityPrototype = $entityPrototype;
}
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::getResourceName()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::getResourceName()
*/
public function getResourceName(): string
{
- $tokens = explode('\\', get_class($this));
+ $tokens = explode('\\', static::class);
+
return strtolower(str_replace('Handler', '', end($tokens)));
}
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::create()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::create()
*/
public function create(array $data): EntityInterface
{
@@ -61,37 +71,40 @@ public function create(array $data): EntityInterface
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::fetch()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::fetch()
*/
public function fetch($id, array $where = []): EntityInterface
{
- $where = array_merge([static::IDENTIFIER_NAME => $id], $where);
+ $where = array_merge([self::IDENTIFIER_NAME => $id], $where);
$entity = $this->mapper->findOneBy($where);
if ($entity === null) {
throw NotFoundException::create();
}
- $query = $this->request->getQueryParams();
+ $query = $this->request->getQueryParams();
$fields = $query['fields'] ?? '';
if (! empty($fields)) {
$entity->setFields(explode(',', $fields));
}
+
return $entity;
}
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::fetchAll()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::fetchAll()
*/
public function fetchAll(array $where = [], array $options = []): Collection
{
$queryParams = $this->request->getQueryParams();
- $query = array_key_exists('q', $queryParams) ? json_decode($queryParams['q'], true) : [];
- $hint = array_key_exists('h', $queryParams) ? json_decode($queryParams['h'], true) : [];
+ $query = array_key_exists('q', $queryParams) ? json_decode($queryParams['q'], true) : [];
+ $hint = array_key_exists('h', $queryParams) ? json_decode($queryParams['h'], true) : [];
$where = array_merge($where, $query);
- $hint = array_merge($options, $hint);
+ $hint = array_merge($options, $hint);
$collection = $this->mapper->findBy($where, $hint);
@@ -110,11 +123,12 @@ public function fetchAll(array $where = [], array $options = []): Collection
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::delete()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::delete()
*/
- public function delete($id, array $where = [])
+ public function delete($id, array $where = []): void
{
- $where = array_merge([static::IDENTIFIER_NAME => $id], $where);
+ $where = array_merge([self::IDENTIFIER_NAME => $id], $where);
$entity = $this->mapper->findOneBy($where);
if ($entity === null) {
@@ -126,11 +140,12 @@ public function delete($id, array $where = [])
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::patch()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::patch()
*/
public function patch($id, array $data, array $where = []): EntityInterface
{
- $where = array_merge([static::IDENTIFIER_NAME => $id], $where);
+ $where = array_merge([self::IDENTIFIER_NAME => $id], $where);
$entity = $this->mapper->findOneBy($where);
if ($entity === null) {
@@ -147,11 +162,12 @@ public function patch($id, array $data, array $where = []): EntityInterface
/**
* {@inheritDoc}
- * @see \LosMiddleware\ApiServer\Handler\AbstractRestHandler::update()
+ *
+ * @see \Los\ApiServer\Handler\AbstractRestHandler::update()
*/
public function update($id, array $data, array $where = []): EntityInterface
{
- $where = array_merge([static::IDENTIFIER_NAME => $id], $where);
+ $where = array_merge([self::IDENTIFIER_NAME => $id], $where);
$entity = $this->mapper->findOneBy($where);
if ($entity === null) {
diff --git a/src/Mapper/MapperInterface.php b/src/Mapper/MapperInterface.php
index 103a64b..cc74a12 100644
--- a/src/Mapper/MapperInterface.php
+++ b/src/Mapper/MapperInterface.php
@@ -1,17 +1,27 @@
table = $table;
- $this->collectionClass = $collectionClass;
}
- /**
- * @param mixed $id
- * @return EntityInterface|null
- */
- public function findById($id): ?EntityInterface
+ public function findById(mixed $id): EntityInterface|null
{
return $this->findOneBy(['id' => $id]);
}
@@ -44,9 +37,8 @@ public function findById($id): ?EntityInterface
/**
* @param array $where
* @param array $options
- * @return EntityInterface|null
*/
- public function findOneBy(array $where = [], array $options = []): ?EntityInterface
+ public function findOneBy(array $where = [], array $options = []): EntityInterface|null
{
$predicate = new Where();
@@ -54,14 +46,14 @@ public function findOneBy(array $where = [], array $options = []): ?EntityInterf
$predicate->equalTo($key, $value);
}
- /** @var \Laminas\Db\ResultSet\ResultSet $resultSet */
$resultSet = $this->table->select($predicate);
- if (count($resultSet) == 0) {
+ assert($resultSet instanceof ResultSet);
+ if (count($resultSet) === 0) {
return null;
}
- /* @var EntityInterface $entity */
$entity = $resultSet->current();
+ assert($entity instanceof EntityInterface);
$fields = (string) ($options['fields'] ?? '');
if (! empty($fields)) {
$entity->setFields(explode(',', $fields));
@@ -70,10 +62,7 @@ public function findOneBy(array $where = [], array $options = []): ?EntityInterf
return $entity;
}
- /**
- * @param array $where
- * @return int
- */
+ /** @param array $where */
public function count(array $where = []): int
{
$predicate = new Where();
@@ -83,38 +72,29 @@ public function count(array $where = []): int
}
$resultSet = $this->table->select($predicate);
+
return $resultSet->count();
}
- /**
- * @param EntityInterface $entity
- * @return bool
- */
- public function insert(EntityInterface $entity) : bool
+ public function insert(EntityInterface $entity): bool
{
$data = $entity->prepareDataForStorage();
+
return $this->table->insert($data) > 0;
}
- /**
- * @param array $data
- * @param EntityInterface $entity
- * @return bool
- */
- public function update(array $data, EntityInterface $entity) : bool
+ /** @param array $data */
+ public function update(array $data, EntityInterface $entity): bool
{
$data = $entity->prepareDataForStorage($data);
+
return $this->table->update(
$data,
- [self::IDENTIFIER_NAME => $entity->getArrayCopy()[self::IDENTIFIER_NAME]]
+ [self::IDENTIFIER_NAME => $entity->getArrayCopy()[self::IDENTIFIER_NAME]],
) > 0;
}
- /**
- * @param EntityInterface $entity
- * @return bool
- */
- public function delete(EntityInterface $entity) : bool
+ public function delete(EntityInterface $entity): bool
{
return $this->table->delete([self::IDENTIFIER_NAME => $entity->getArrayCopy()[self::IDENTIFIER_NAME]]) > 0;
}
@@ -122,9 +102,8 @@ public function delete(EntityInterface $entity) : bool
/**
* @param array $where
* @param array $options
- * @return Collection
*/
- public function findBy(array $where = [], array $options = []) : Collection
+ public function findBy(array $where = [], array $options = []): Collection
{
$sql = $this->table->getSql();
$select = $sql->select();
@@ -133,24 +112,22 @@ public function findBy(array $where = [], array $options = []) : Collection
$dbAdapter = new DbSelect(
$select,
$sql,
- $this->table->getResultSetPrototype()
+ $this->table->getResultSetPrototype(),
);
- /** @var Collection $collection */
$collection = new $this->collectionClass($dbAdapter);
+ assert($collection instanceof Collection);
return $collection;
}
- /**
- * @param array $fields
- */
+ /** @param array $fields */
public function setFields(array $fields): void
{
- /** @var HydratingResultSet $resultSetPrototype */
$resultSetPrototype = $this->table->getResultSetPrototype();
- /** @var EntityInterface $entityPrototype */
+ assert($resultSetPrototype instanceof HydratingResultSet);
$entityPrototype = $resultSetPrototype->getObjectPrototype();
+ assert($entityPrototype instanceof EntityInterface);
$entityPrototype->setFields($fields);
}
}
diff --git a/src/Paginator/MapperAdapter.php b/src/Paginator/MapperAdapter.php
index 20bc3b5..1d3bf21 100644
--- a/src/Paginator/MapperAdapter.php
+++ b/src/Paginator/MapperAdapter.php
@@ -1,28 +1,25 @@
mapper = $mapper;
- $this->where = $where;
- $this->order = $order;
- $this->group = $group;
+ public function __construct(
+ private MapperInterface $mapper,
+ private array $where = [],
+ private $order = null,
+ private $group = null,
+ ) {
}
/**
* {@inheritDoc}
+ *
* @see \Laminas\Paginator\Adapter\AdapterInterface::getItems()
*/
public function getItems($offset, $itemCountPerPage)
@@ -37,9 +34,10 @@ public function getItems($offset, $itemCountPerPage)
/**
* {@inheritDoc}
+ *
* @see Countable::count()
*/
- public function count()
+ public function count(): int
{
return $this->mapper->count($this->where);
}