Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.11% covered (success)
92.11%
35 / 38
77.78% covered (warning)
77.78%
7 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
GetItemAction
92.11% covered (success)
92.11%
35 / 38
77.78% covered (warning)
77.78%
7 / 9
16.13
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
 isAuthorized
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
7.23
 __invoke
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
2.00
 getInputType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOutputType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPossibleActionResponseStatuses
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getDescription
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTags
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRouteAttributes
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2namespace Apie\Common\Actions;
3
4use Apie\Core\Actions\ActionInterface;
5use Apie\Core\Actions\ActionResponse;
6use Apie\Core\Actions\ActionResponseStatus;
7use Apie\Core\Actions\ActionResponseStatusList;
8use Apie\Core\Actions\ApieFacadeInterface;
9use Apie\Core\BoundedContext\BoundedContextId;
10use Apie\Core\Context\ApieContext;
11use Apie\Core\ContextConstants;
12use Apie\Core\Entities\EntityInterface;
13use Apie\Core\Exceptions\InvalidTypeException;
14use Apie\Core\IdentifierUtils;
15use Apie\Core\Lists\PermissionList;
16use Apie\Core\Lists\StringList;
17use Apie\Core\Permissions\PermissionInterface;
18use Apie\Core\Permissions\RequiresPermissionsInterface;
19use Apie\Core\Utils\EntityUtils;
20use LogicException;
21use ReflectionClass;
22
23/**
24 * Action to get a single item resource.
25 */
26final class GetItemAction implements ActionInterface
27{
28    public function __construct(private readonly ApieFacadeInterface $apieFacade)
29    {
30    }
31
32    public static function isAuthorized(ApieContext $context, bool $runtimeChecks, bool $throwError = false): bool
33    {
34        $refl = new ReflectionClass($context->getContext(ContextConstants::RESOURCE_NAME, $throwError));
35        $resource = $context->getContext(ContextConstants::RESOURCE, false);
36        if ($resource instanceof RequiresPermissionsInterface) {
37            $requiredPermissions = $resource->getRequiredPermissions();
38            $user = $context->getContext(ContextConstants::AUTHENTICATED_USER, false);
39            if ($user instanceof PermissionInterface) {
40                $hasPermisions = $user->getPermissionIdentifiers();
41                return $hasPermisions->hasOverlap($requiredPermissions);
42            }
43            return $requiredPermissions->hasOverlap(new PermissionList(['']));
44        }
45        if (EntityUtils::isPolymorphicEntity($refl) && $runtimeChecks && $resource) {
46            $refl = new ReflectionClass($resource);
47        }
48        return $context->appliesToContext($refl, $runtimeChecks, $throwError ? new LogicException('Operation is not allowed') : null);
49    }
50
51    /**
52     * @param array<string|int, mixed> $rawContents
53     */
54    public function __invoke(ApieContext $context, array $rawContents): ActionResponse
55    {
56        $context->withContext(ContextConstants::APIE_ACTION, __CLASS__)->checkAuthorization();
57        $resourceClass = new ReflectionClass($context->getContext(ContextConstants::RESOURCE_NAME));
58        $id = $context->getContext(ContextConstants::RESOURCE_ID);
59        if (!$resourceClass->implementsInterface(EntityInterface::class)) {
60            throw new InvalidTypeException($resourceClass->name, 'EntityInterface');
61        }
62        $result = $this->apieFacade->find(
63            IdentifierUtils::idStringToIdentifier($id, $context),
64            new BoundedContextId($context->getContext(ContextConstants::BOUNDED_CONTEXT_ID))
65        );
66        $context = $context->withContext(ContextConstants::RESOURCE, $result);
67        $context->withContext(ContextConstants::APIE_ACTION, __CLASS__)->checkAuthorization();
68        return ActionResponse::createRunSuccess($this->apieFacade, $context, $result, $result);
69    }
70
71    /**
72     * @return ReflectionClass<EntityInterface>
73     */
74    public static function getInputType(ReflectionClass $class): ReflectionClass
75    {
76        return $class;
77    }
78
79    /**
80     * @return ReflectionClass<EntityInterface>
81     */
82    public static function getOutputType(ReflectionClass $class): ReflectionClass
83    {
84        return $class;
85    }
86
87    public static function getPossibleActionResponseStatuses(): ActionResponseStatusList
88    {
89        return new ActionResponseStatusList([
90            ActionResponseStatus::SUCCESS,
91            ActionResponseStatus::AUTHORIZATION_ERROR,
92            ActionResponseStatus::NOT_FOUND
93        ]);
94    }
95
96    public static function getDescription(ReflectionClass $class): string
97    {
98        return 'Gets a resource of ' . $class->getShortName() . ' with a specific id';
99    }
100    
101    public static function getTags(ReflectionClass $class): StringList
102    {
103        return new StringList([$class->getShortName(), 'resource']);
104    }
105
106    public static function getRouteAttributes(ReflectionClass $class): array
107    {
108        return [
109            ContextConstants::GET_OBJECT => true,
110            ContextConstants::RESOURCE_NAME => $class->name,
111        ];
112    }
113}