Mahdee Rajon  subception

File "Dto.php"

Full Path: /var/www/html/back/app/Responses/Dto.php
File size: 6.4 KB
MIME-type: text/x-php
Charset: utf-8

<?php

declare(strict_types=1);

namespace App\Responses;

use ReflectionClass;
use Spatie\LaravelData\Data;

class Dto extends Data
{
    public static function unAuthorized(): array
    {
        return [
            'status' => false,
            'message' => __('auth.unauthorized'),
            'errors' => null,
        ];
    }

    public static function tooManyRequests(): array
    {
        return [
            'status' => false,
            'message' => __('throttle.too_many_requests'),
            'errors' => null,
        ];
    }

    public static function validationError()
    {
        return [
            'status' => false,
            'message' => __('validation.failed'),
            'errors' => [
                'field' => [
                    'reason',
                ],
            ],
        ];
    }

    public static function dataExample($dto): string|array
    {
        $reflection = new \ReflectionClass($dto);
        $constructor = $reflection->getConstructor();

        $params = $constructor->getParameters();

        $fields = collect($params)->map(function ($param) {
            $val = $param->getType()->getName();
            if (class_exists($param->getType()->getName())) {
                $val = self::dataExample($param->getType()->getName());
            }

            return [
                $param->getName() => $val,
            ];
        })->collapse()->toArray();

        return $fields;
    }

    public static function notFound(string $class): array
    {
        return [
            'status' => false,
            'message' => __($class . '.not_found'),
            'errors' => null,
        ];
    }

    public static function ok($dto = null): array
    {
        if (!$dto) {
            $dto = __CLASS__;
        }

        return
            [
                'result' => Dto::dataExample($dto),
            ];
    }

    public static function example(string $description, $dto): array
    {
        if (in_array($description, ['ok', 'notFound', 'validationError', 'unAuthorized', 'tooManyRequests'], true) && !self::hasStaticMethod($dto, $description)) {
            return self::$description($dto);
        }


        return $dto::$description();
    }

    public static function hasStaticMethod($className, $methodName): bool
    {
        $reflection = new \ReflectionClass($className);

        if ($reflection->hasMethod($methodName)) {
            $method = $reflection->getMethod($methodName);

            if ($method->getDeclaringClass()->getName() === $className && $method->isStatic()) {
                return true;
            }
        }

        return false;
    }

    public static function getMethodExceptions($class_name, $method_name, &$visited = [])
    {
        // Создаем рефлексию класса и метода
        $reflection_class = new ReflectionClass($class_name);
        $reflection_method = $reflection_class->getMethod($method_name);

        // Получаем PHPDoc комментарии для метода
        $method_doc_comment = $reflection_method->getDocComment();

        // Получаем информацию об исключениях
        $exceptions = self::getExceptionsFromPhpDoc($method_doc_comment);


        // Получаем код метода
        $method_code = file($reflection_method->getFileName());
        $method_start_line = $reflection_method->getStartLine();
        $method_end_line = $reflection_method->getEndLine();

        $called_methods = [];

        // Читаем строки кода метода
        for ($line = $method_start_line; $line <= $method_end_line; $line++) {
            $code_line = $method_code[$line - 1];

            // Ищем вызовы методов через оператор ->
            if (preg_match_all('/\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*->\s*([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\(/', $code_line, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    $variable_name = $match[1];
                    $called_method = $match[2];

                    // Пытаемся определить класс переменной через PHPDoc
                    $variable_class = self::getClassFromPhpDoc($variable_name, $method_doc_comment);
                    if ($variable_name === 'this') {
                        $variable_class = $class_name;
                    }

                    if ($variable_class !== null) {

                        // Проверяем, чтобы не было циклических вызовов
                        $call_signature = $variable_class . '::' . $called_method;
                        if (!in_array($call_signature, $visited, true)) {
                            $visited[] = $call_signature;
                            // Рекурсивно находим вызываемые методы и исключения в них
                            $nested_methods = self::getMethodExceptions($variable_class, $called_method, $visited);

                            // Добавляем результаты в текущий список вызываемых методов
                            $called_methods = array_merge($called_methods, $nested_methods);
                        }
                    }
                }
            }
        }
        array_push($called_methods, ...$exceptions);

        $called_methods = array_diff($called_methods, 'Throwable');


        return array_unique($called_methods);
    }

    public static function getClassFromPhpDoc($variable_name, $method_doc_comment)
    {
        // Паттерн для поиска @param аннотаций
        $pattern = '/@param\s+(\S+)\s+\$' . preg_quote($variable_name, '/') . '/';

        // Ищем аннотации @param в PHPDoc
        if (preg_match($pattern, $method_doc_comment, $matches)) {
            return $matches[1]; // Возвращаем найденный класс
        }

        return null; // Если класс не найден
    }

    public static function getExceptionsFromPhpDoc($doc_comment)
    {
        $exceptions = [];

        // Ищем @throws аннотации в PHPDoc
        preg_match_all('/@throws\s+(\S+)/', $doc_comment, $matches);

        // Формируем массив исключений
        foreach ($matches[1] as $exception) {
            $exceptions[] = $exception;
        }

        return $exceptions;
    }

}