/var/www/html/back/app/Responses/Dto.php
<?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;
}
}