Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
84.09% covered (warning)
84.09%
37 / 44
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
FormCommitController
84.09% covered (warning)
84.09%
37 / 44
66.67% covered (warning)
66.67%
2 / 3
14.79
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
 __invoke
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 createResponse
82.05% covered (warning)
82.05%
32 / 39
0.00% covered (danger)
0.00%
0 / 1
12.83
1<?php
2namespace Apie\Cms\Controllers;
3
4use Apie\Cms\Services\ResponseFactory;
5use Apie\Common\ApieFacade;
6use Apie\Core\Actions\ActionResponse;
7use Apie\Core\Actions\ActionResponseStatus;
8use Apie\Core\BoundedContext\BoundedContextHashmap;
9use Apie\Core\BoundedContext\BoundedContextId;
10use Apie\Core\ContextBuilders\ContextBuilderFactory;
11use Apie\Core\ContextConstants;
12use Apie\Core\Entities\EntityInterface;
13use Apie\Core\Identifiers\UuidV4;
14use Apie\HtmlBuilders\Configuration\ApplicationConfiguration;
15use Apie\Serializer\Exceptions\ValidationException;
16use Psr\Http\Message\ResponseInterface;
17use Psr\Http\Message\ServerRequestInterface;
18use ReflectionClass;
19use Symfony\Component\HttpFoundation\Session\SessionInterface;
20
21class FormCommitController
22{
23    public function __construct(
24        protected readonly ContextBuilderFactory $contextBuilderFactory,
25        private readonly ApieFacade $apieFacade,
26        private readonly ApplicationConfiguration $applicationConfiguration,
27        private readonly BoundedContextHashmap $boundedContextHashmap,
28        private readonly ResponseFactory $responseFactory,
29    ) {
30    }
31
32    public function __invoke(ServerRequestInterface $request): ResponseInterface
33    {
34        $context = $this->contextBuilderFactory->createFromRequest($request, [ContextConstants::CMS => true]);
35        $action = $this->apieFacade->createAction($context);
36        $data = ($action)($context, $context->getContext(ContextConstants::RAW_CONTENTS));
37        return $this->createResponse($request, $data);
38    }
39
40    /**
41     * Creates redirect response and stores a few things in the session. It redirects to the most sensible layout.
42     * If the action gave an error:
43     * - store validation errors and the filled in values in the session
44     * - redirect to the same uri again.
45     * If the action succeeded:
46     * - remove values in the session
47     * - redirect to if applicable:
48     *   - resource/<resource>/<id>
49     *   - resource/<resource>
50     *   - last-action-result/<result-id>
51     */
52    protected function createResponse(ServerRequestInterface $request, ActionResponse $output): ResponseInterface
53    {
54        if ($output->result instanceof ResponseInterface) {
55            return $output->result;
56        }
57        $configuration = $this->applicationConfiguration->createConfiguration(
58            $output->apieContext,
59            $this->boundedContextHashmap,
60            new BoundedContextId($output->apieContext->getContext(ContextConstants::BOUNDED_CONTEXT_ID))
61        );
62
63        $redirectUrl = (string) $request->getUri();
64        $session = $output->apieContext->getContext(SessionInterface::class);
65        assert($session instanceof SessionInterface);
66        if ($output->getStatusCode() < 300) {
67            $session->remove('_filled_in');
68            $session->remove('_validation_errors');
69            if ($output->apieContext->hasContext(ContextConstants::RESOURCE_NAME)) {
70                $class = new ReflectionClass($output->apieContext->getContext(ContextConstants::RESOURCE_NAME));
71                $redirectUrl = $configuration->getContextUrl('resource/' . $class->getShortName());
72                if ($output->apieContext->hasContext(ContextConstants::RESOURCE_ID) && $output->status !== ActionResponseStatus::DELETED) {
73                    $redirectUrl = $configuration->getContextUrl(
74                        'resource/' . $class->getShortName() . '/' . $output->apieContext->getContext(ContextConstants::RESOURCE_ID)
75                    );
76                }
77            }
78            if (isset($output->result) && $output->status !== ActionResponseStatus::DELETED) {
79                if ($output->result instanceof EntityInterface) {
80                    $baseClass = $output->result->getId()::getReferenceFor();
81                    $redirectUrl = $configuration->getContextUrl(
82                        'resource/' . $baseClass->getShortName() . '/' . $output->result->getId()->toNative()
83                    );
84                } else {
85                    $previousResults = $session->get('_output_results', []);
86                    $uniqueId = UuidV4::createRandom()->toNative();
87                    $previousResults[$uniqueId] = $output->result;
88                    $session->set('_output_results', $previousResults);
89                    $redirectUrl = $configuration->getContextUrl('last-action-result/' . $uniqueId);
90                }
91            }
92        }
93
94        if (isset($output->error) && $output->apieContext->hasContext(SessionInterface::class)) {
95            $contents = $output->apieContext->getContext(ContextConstants::RAW_CONTENTS);
96            unset($contents['_csrf']);
97            $session->set('_filled_in', $contents);
98        
99            if (
100                $output->error instanceof ValidationException
101            ) {
102                $session->set('_validation_errors', $output->error->getErrors()->toArray());
103            } else {
104                $session->set('_validation_errors', ['' => $output->error->getMessage()]);
105            }
106        }
107
108        return $this->responseFactory->createRedirect($redirectUrl, $output->apieContext);
109    }
110}