Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
ChangeLogisticsObjectEndpoint
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
1 / 1
 handle
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace LambdaTwelve\OneRecord\Server\Endpoint;
6
7use LambdaTwelve\OneRecord\Api\RequestStatus;
8use LambdaTwelve\OneRecord\Change\Change;
9use LambdaTwelve\OneRecord\Server\ActionRequests;
10use LambdaTwelve\OneRecord\Server\Http\ContentNegotiation;
11use LambdaTwelve\OneRecord\Server\Http\HttpException;
12use LambdaTwelve\OneRecord\Server\Http\Negotiated;
13use LambdaTwelve\OneRecord\Server\Spi\Action;
14use LambdaTwelve\OneRecord\Server\Spi\Agent;
15use LambdaTwelve\OneRecord\Server\Spi\Decision;
16use LambdaTwelve\OneRecord\Vocabulary\Generated\Api;
17use Psr\Http\Message\ResponseInterface;
18use Psr\Http\Message\ServerRequestInterface;
19
20/**
21 * PATCH /logistics-objects/{id}: a Change becomes a pending ChangeRequest for
22 * the holder to decide (201 with its Location). The holder's own agents are
23 * accepted and applied at once, as the spec says a request by the holder
24 * SHOULD be. Access follows PATCH_LOGISTICS_OBJECT (spec question 16).
25 */
26final class ChangeLogisticsObjectEndpoint extends AbstractEndpoint
27{
28    public function handle(ServerRequestInterface $request, Agent $agent, Negotiated $negotiated, array $parameters): ResponseInterface
29    {
30        $stored = $this->requireObject($parameters['id'], $agent, Action::ChangeLogisticsObject);
31        (new ContentNegotiation($this->services->config))->bodyVersion($request, $negotiated);
32        $change = Change::fromJsonLd($this->services->body->json($request));
33        if (!$change->logisticsObject->equals($stored->object->iri)) {
34            throw HttpException::badRequest(\sprintf('api:hasLogisticsObject is %s but the request was sent to %s.', $change->logisticsObject->value, $stored->object->iri->value), Api::hasLogisticsObject, 'Invalid resource');
35        }
36        if ($change->revision > $stored->latestRevision) {
37            throw HttpException::unprocessable(\sprintf('The change applies to revision %d but the object is at revision %d.', $change->revision, $stored->latestRevision), Api::hasRevision);
38        }
39
40        $requests = new ActionRequests($this->services);
41        $created = $requests->create($change, $agent->iri);
42        // Unless a creation listener decided it already (R7-001).
43        if ($created->status === RequestStatus::Pending && $this->services->policy->decide($agent, Action::DecideActionRequest, $created->iri) === Decision::Allow) {
44            $requests->accept($created, $agent->iri);
45        }
46
47        return $this->services->responder->empty(201, $negotiated, ['Location' => $created->iri->value, 'Type' => Api::ChangeRequest]);
48    }
49}