willow icon indicating copy to clipboard operation
willow copied to clipboard

Revamp WriteValidatorBase

Open RyanNerd opened this issue 3 years ago • 0 comments

<?php
declare(strict_types=1);

namespace Willow\Controllers;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Respect\Validation\Validator as V;
use Willow\Middleware\ResponseBody;

abstract class WriteValidatorBase
{
    public function __invoke(Request $request, RequestHandler $handler): ResponseInterface
    {
        $responseBody = $this->processValidation($request->getAttribute('response_body'));

        // If there are any missing or required data points then we short circuit and return invalid request.
        if ($responseBody->hasMissingRequiredOrInvalid()) {
            $responseBody = $responseBody
                ->setStatus(ResponseBody::HTTP_BAD_REQUEST)
                ->setMessage('Missing or invalid request');
            return $responseBody();
        }

            return $handler->handle($request);
    }

    /**
     * You should override this function to perform the validations
     * @param ResponseBody $responseBody
     * @return ResponseBody
     */
    protected function processValidation(ResponseBody $responseBody): ResponseBody {
        return $responseBody;
    }

    /**
     * Default processValidation() for generic validations
     * @param ResponseBody $responseBody
     * @param array $fields
     * @return ResponseBody
     */
    protected function defaultValidation(ResponseBody $responseBody, array $fields): ResponseBody {
        $parsedRequest = $responseBody->getParsedRequest();
        // Iterate all the model fields
        foreach($fields as $field => $dataType) {
            $protectedField = $dataType[0] === '*';
            // Is the model field NOT in the request?
            if (!V::key($field)->validate($parsedRequest)) {
                // Any dataType proceeded with an * are protected fields and can not be changed (e.g. password_hash)
                if ($protectedField) {
                    continue;
                }
                // If the request is missing this field so register it as optional
                $responseBody->registerParam('optional', $field, $dataType);
            } else {
                // If Datatype is proceeded with an * it means the field is protected and can not be changed (e.g. password_hash)
                if ($protectedField) {
                    $responseBody->registerParam('invalid', $field, null);
                }
                // Don't allow emoji characters -- this prevents SQL Errors
                if ($dataType === 'string') {
                    $fieldValue = $parsedRequest[$field];
                    if (V::notEmpty()->validate($fieldValue) && !V::notEmoji()->validate($fieldValue)) {
                        $responseBody->registerParam('invalid', $field, 'alpha-numeric. Value given: ' . $fieldValue);
                    }
                }
            }
        }
        return $responseBody;
    }
}

RyanNerd avatar Jun 17 '21 22:06 RyanNerd