Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
56.25% covered (warning)
56.25%
27 / 48
60.00% covered (warning)
60.00%
6 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
GetterMethod
56.25% covered (warning)
56.25%
27 / 48
60.00% covered (warning)
60.00%
6 / 10
93.65
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getReflectionMethod
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 allowsNull
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isRequired
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isField
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 appliesToContext
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
7.90
 getValue
17.65% covered (danger)
17.65%
3 / 17
0.00% covered (danger)
0.00%
0 / 1
18.96
 getFieldPriority
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 getTypehint
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAttributes
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
7.29
1<?php
2namespace Apie\Core\Metadata\Fields;
3
4use Apie\Core\Attributes\ColumnPriority;
5use Apie\Core\Attributes\Optional;
6use Apie\Core\Attributes\RuntimeCheck;
7use Apie\Core\Context\ApieContext;
8use Apie\Core\Metadata\Concerns\UseContextKey;
9use Apie\Core\Metadata\GetterInterface;
10use Apie\Core\Utils\ConverterUtils;
11use Apie\TypeConverter\Exceptions\CanNotConvertObjectException;
12use ReflectionException;
13use ReflectionMethod;
14use ReflectionType;
15
16final class GetterMethod implements FieldInterface, GetterInterface
17{
18    use UseContextKey;
19
20    public function __construct(private readonly ReflectionMethod $method)
21    {
22    }
23
24    public function getReflectionMethod(): ReflectionMethod
25    {
26        return $this->method;
27    }
28
29    public function allowsNull(): bool
30    {
31        $type = $this->method->getReturnType();
32        return $type === null || $type->allowsNull();
33    }
34
35    public function isRequired(): bool
36    {
37        return empty($this->method->getAttributes(Optional::class)) && empty($this->method->getAttributes(RuntimeCheck::class));
38    }
39
40    public function isField(): bool
41    {
42        return true;
43    }
44
45    public function appliesToContext(ApieContext $apieContext): bool
46    {
47        if (!$apieContext->appliesToContext($this->method)) {
48            return false;
49        }
50        $parameters = $this->method->getParameters();
51        foreach ($parameters as $parameter) {
52            $contextKey = $this->getContextKey($apieContext, $parameter);
53            if ($contextKey === null || ($parameter->isDefaultValueAvailable() && !$apieContext->hasContext($contextKey))) {
54                return false;
55            }
56        }
57        return true;
58    }
59
60    public function getValue(object $object, ApieContext $apieContext): mixed
61    {
62        $arguments = [];
63        foreach ($this->method->getParameters() as $parameter) {
64            $contextKey = $this->getContextKey($apieContext, $parameter);
65            if ($contextKey === null || !$apieContext->hasContext($contextKey)) {
66                try {
67                    $arguments[] = $parameter->getDefaultValue();
68                } catch (ReflectionException $previous) {
69                    throw new \LogicException(
70                        sprintf(
71                            'Trouble with "%s" for parameter "%s" in method "%s"',
72                            $contextKey,
73                            $parameter->getName(),
74                            $this->method->getName()
75                        ),
76                        previous: $previous
77                    );
78                }
79            } else {
80                $arguments[] = $apieContext->getContext($contextKey);
81            }
82        }
83
84        return $this->method->invokeArgs($object, $arguments);
85    }
86
87    public function getFieldPriority(): ?int
88    {
89        $attributes = $this->method->getAttributes(ColumnPriority::class);
90        if (empty($attributes)) {
91            return null;
92        }
93
94        $attribute = reset($attributes);
95        return $attribute->newInstance()->priority;
96    }
97
98    public function getTypehint(): ?ReflectionType
99    {
100        return $this->method->getReturnType();
101    }
102
103    public function getAttributes(string $attributeClass, bool $classDocBlock = true, bool $propertyDocblock = true, bool $argumentDocBlock = true): array
104    {
105        $list = [];
106        if ($propertyDocblock) {
107            foreach ($this->method->getAttributes($attributeClass, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
108                $list[] = $attribute->newInstance();
109            }
110        }
111        try {
112            $class = ConverterUtils::toReflectionClass($this->method);
113        } catch (CanNotConvertObjectException) {
114            return $list;
115        }
116        if ($class && $classDocBlock) {
117            foreach ($class->getAttributes($attributeClass, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
118                $list[] = $attribute->newInstance();
119            }
120        }
121
122        return $list;
123    }
124}