Issues (17)

src/HyperSonic.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Usox\HyperSonic;
6
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Usox\HyperSonic\Authentication\AuthenticationManager;
10
use Usox\HyperSonic\Authentication\AuthenticationManagerInterface;
11
use Usox\HyperSonic\Authentication\AuthenticationProviderInterface;
12
use Usox\HyperSonic\Authentication\Exception\AbstractAuthenticationException;
13
use Usox\HyperSonic\Exception\ErrorCodeEnum;
14
use Usox\HyperSonic\FeatureSet\FeatureSetMethodInterface;
15
use Usox\HyperSonic\FeatureSet\V1161\FeatureSetFactoryInterface;
16
use Usox\HyperSonic\Response\BinaryResponderInterface;
17
use Usox\HyperSonic\Response\FormattedResponderInterface;
18
use Usox\HyperSonic\Response\ResponderInterface;
19
use Usox\HyperSonic\Response\ResponseWriterFactory;
20
use Usox\HyperSonic\Response\ResponseWriterFactoryInterface;
21
22
final class HyperSonic implements HyperSonicInterface
23
{
24
    /**
25
     * @param array<string, callable(): FeatureSetMethodInterface> $dataProvider
26
     */
27 4
    public function __construct(
28
        private readonly FeatureSetFactoryInterface $featureSetFactory,
29
        private readonly array $dataProvider,
30
        private readonly ResponseWriterFactoryInterface $responseWriterFactory,
31
        private readonly AuthenticationManagerInterface $authenticationManager,
32
    ) {
33 4
    }
34
35
    /**
36
     * @param array<string, scalar> $args
37
     */
38 1
    public function __invoke(
39
        ServerRequestInterface $request,
40
        ResponseInterface $response,
41
        array $args
42
    ): ResponseInterface {
43 1
        return $this->run($request, $response, $args);
44
    }
45
46
    /**
47
     * @param array<string, scalar> $args
48
     */
49 3
    public function run(
50
        ServerRequestInterface $request,
51
        ResponseInterface $response,
52
        array $args
53
    ): ResponseInterface {
54 3
        $queryParams = $request->getQueryParams();
55
56
        // subsonic response format
57 3
        $responseFormat = $queryParams['f'] ?? 'xml';
58
59 3
        if ($responseFormat === 'xml') {
60 2
            $responseWriter = $this->responseWriterFactory->createXmlResponseWriter(
61 2
                $this->featureSetFactory->getVersion()
62 2
            );
63
        } else {
64 1
            $responseWriter = $this->responseWriterFactory->createJsonResponseWriter(
65 1
                $this->featureSetFactory->getVersion()
66 1
            );
67
        }
68
69
        try {
70 3
            $this->authenticationManager->auth($request);
71 1
        } catch (AbstractAuthenticationException $authenticationException) {
72 1
            return $responseWriter->writeError(
73 1
                $response,
74 1
                ErrorCodeEnum::WRONG_USERNAME_OR_PASSWORD,
75 1
                $authenticationException->getMessage()
76 1
            );
77
        }
78
79
        // ensure we filter all possible methods by the really implemented ones
80 2
        $methods = array_intersect_key(
81 2
            $this->featureSetFactory->getMethods(),
82 2
            $this->dataProvider
83 2
        );
84
85 2
        $methodName = $args['methodName'];
86
87
        /** @var callable():FeatureSetMethodInterface|null $handler */
88 2
        $handler = $methods[$methodName] ?? null;
89
90 2
        if ($handler !== null) {
0 ignored issues
show
The condition $handler !== null is always true.
Loading history...
91
            // Retrieve the data provider
92 1
            $dataProvider = call_user_func($this->dataProvider[$methodName]);
93
94
            // retrieve handler method callable from method mapping
95
            /** @var FeatureSetMethodInterface&callable(object,array<string, mixed>,array<string, mixed>):ResponderInterface $method */
96 1
            $method = call_user_func($handler);
97
98
            // execute handler method
99
            /** @var ResponderInterface $responder */
100 1
            $responder = call_user_func($method, $dataProvider, $queryParams, $args);
101 1
            if ($responder->isBinaryResponder()) {
102
                /** @var BinaryResponderInterface $responder */
103 1
                $response = $responder->writeResponse($response);
104
            } else {
105
                /** @var FormattedResponderInterface $responder */
106 1
                $response = $responseWriter->write($response, $responder);
107
            }
108
        } else {
109 1
            $response = $responseWriter->writeError($response, ErrorCodeEnum::SERVER_VERSION_INCOMPATIBLE);
110
        }
111
112 2
        return $response;
113
    }
114
115
    /**
116
     * Create a hypersonic instance
117
     *
118
     * Expects a list of so called `data providers` which consists
119
     * of a key (the method name) and a callable which creates the
120
     * data provider. See documentation
121
     *
122
     * @param array<string, callable(): FeatureSetMethodInterface> $dataProvider
123
     */
124 1
    public static function init(
125
        FeatureSetFactoryInterface $featureSetFactory,
126
        AuthenticationProviderInterface $authenticationProvider,
127
        array $dataProvider,
128
    ): self {
129 1
        return new self(
130 1
            $featureSetFactory,
131 1
            $dataProvider,
132 1
            new ResponseWriterFactory(),
133 1
            new AuthenticationManager(
134 1
                $authenticationProvider,
135 1
            ),
136 1
        );
137
    }
138
}
139