PHP Classes

File: src/Attributes/functions.php

Recommend this page to a friend!
  Classes of Rodolfo Berrios Arce   Parameter   src/Attributes/functions.php   Download  
File: src/Attributes/functions.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Parameter
Validate function parameters with PHP attributes
Author: By
Last change:
Date: 21 days ago
Size: 6,441 bytes
 

Contents

Class file image Download
<?php

/*
 * This file is part of Chevere.
 *
 * (c) Rodolfo Berrios <[email protected]>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace
Chevere\Parameter\Attributes;

use
Chevere\Parameter\Exceptions\ParameterException;
use
Chevere\Parameter\Interfaces\ArgumentsInterface;
use
Chevere\Parameter\Interfaces\ParameterInterface;
use
LogicException;
use
ReflectionFunction;
use
ReflectionMethod;
use
Throwable;
use function
Chevere\Message\message;
use function
Chevere\Parameter\parameterAttr;
use function
Chevere\Parameter\reflectionToParameters;

function
stringAttr(string $name): StringAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
enumAttr(string $name): EnumAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
intAttr(string $name): IntAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
floatAttr(string $name): FloatAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
boolAttr(string $name): BoolAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
nullAttr(string $name): NullAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
arrayAttr(string $name): ArrayAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
iteratorAttr(string $name): IterableAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
unionAttr(string $name): UnionAttr
{
   
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];

   
// @phpstan-ignore-next-line
   
return parameterAttr($name, $caller['function'], $caller['class'] ?? '');
}

function
returnAttr(): ReturnAttr
{
   
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
   
$caller = $trace[1];
   
$class = $caller['class'] ?? null;
   
$method = $caller['function'];
   
$convention = "{$class}::return";
   
$reflection = $class
       
? new ReflectionMethod($class, $method)
        : new
ReflectionFunction($method);
   
$attribute = $reflection->getAttributes(ReturnAttr::class)[0] ?? null;
    if (
$attribute === null) {
        if (!
is_callable($convention)) {
            throw new
LogicException(
                (string)
message(
                   
'No applicable return rules to validate',
                )
            );
        }
       
$parameter = $convention();
        if (!
$parameter instanceof ParameterInterface) {
            throw new
LogicException(
                (string)
message(
                   
'Callable `%callable%` must return a `%type%` instance',
                    callable:
$convention,
                   
type: ParameterInterface::class
                )
            );
        }
    } else {
       
$attribute = $attribute->newInstance();
    }

   
/** @var ReturnAttr $attribute */
   
return $attribute;
}

/**
 * Get Arguments for an array parameter.
 */
function arrayArguments(string $name): ArgumentsInterface
{
   
$caller = debug_backtrace(0, 2)[1];
   
$class = $caller['class'] ?? false;
   
$method = $caller['function'];
   
$args = $caller['args'] ?? [];
   
$reflection = $class
       
? new ReflectionMethod($class, $method)
        : new
ReflectionFunction($method);
   
$parameters = reflectionToParameters($reflection);
   
$parameters->assertHas($name);
   
$array = match ($parameters->optionalKeys()->contains($name)) {
       
true => $parameters->optional($name)->array(),
        default =>
$parameters->required($name)->array(),
    };
   
$pos = -1;
   
$arguments = [];
    foreach (
$parameters->keys() as $named) {
       
$pos++;
       
$arguments[$named] = match (true) {
           
array_key_exists($pos, $args) => $args[$pos],
            default =>
$parameters->get($named)->default(),
        };
    }

    return
$array->parameters()->__invoke(...$arguments[$name]);
}

/**
 * Validates argument `$name` against parameter attribute rules.
 *
 * @param ?string $name Argument name or `null` to validate all arguments.
 */
function valid(?string $name = null): void
{
   
$trace = debug_backtrace(0, 2);
   
$caller = $trace[1];
   
$class = $caller['class'] ?? false;
   
$method = $caller['function'];
   
$args = $caller['args'] ?? [];
   
$reflection = $class
       
? new ReflectionMethod($class, $method)
        : new
ReflectionFunction($method);
   
$parameters = reflectionToParameters($reflection);
   
$pos = -1;
   
$arguments = [];
    foreach (
$parameters->keys() as $named) {
       
$pos++;
        if (! isset(
$args[$pos])) {
            continue;
        }
       
$arguments[$named] = $args[$pos];
    }
    if (
$name === null) {
       
$parameters(...$arguments);

        return;
    }
    if (
$parameters->optionalKeys()->contains($name)
        && !
array_key_exists($name, $arguments)
    ) {
        return;
    }

    try {
        if (!
$parameters->has($name)) {
            throw new
LogicException(
                (string)
message(
                   
'Parameter `%name%` not found',
                   
name: $name,
                )
            );
        }
       
$parameter = $parameters->get($name);
       
$parameter->__invoke($arguments[$name]);
    } catch (
Throwable $e) {
       
$invoker = $trace[0];
       
$file = $invoker['file'] ?? 'na';
       
$line = $invoker['line'] ?? 0;

        throw new
ParameterException($e->getMessage(), $e, $file, $line);
    }
}