Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
UrlToMvcRouter
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
4 / 4
13
100.00% covered (success)
100.00%
1 / 1
 getRouters
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 requestToMvc
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
10
 snakeCaseToUpperCamelCase
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 snakeCaseToLowerCamelCase
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Miniframe\Middleware;
4
5use Miniframe\Core\AbstractController;
6use Miniframe\Core\AbstractMiddleware;
7
8/**
9 * Load this middleware to use basic routing (GET "/index/main" returns callable App\Controller\Index::main)
10 *
11 * This is the most basic way of routing
12 */
13class UrlToMvcRouter extends AbstractMiddleware
14{
15    /**
16     * Returns a reference to the UrlToMvcRouter::requestToMvc method
17     *
18     * @return callable[]
19     */
20    public function getRouters(): array
21    {
22        return [
23            array($this, 'requestToMvc'),
24        ];
25    }
26
27    /**
28     * Converts a request path to a controller+method (GET "/index/main" returns callable App\Controller\Index::main)
29     *
30     * @return callable
31     */
32    public function requestToMvc(): ?callable
33    {
34        $path = $this->request->getPath();
35
36        // Remove base path, if present
37        $baseHref = $this->config->get('framework', 'base_href');
38        if (!is_string($baseHref)) {
39            // @codeCoverageIgnoreStart
40            $baseHref = '/';
41            // @codeCoverageIgnoreEnd
42        }
43        $basePath = explode('/', trim((string)parse_url($baseHref, PHP_URL_PATH), '/'));
44        foreach ($basePath as $prefix) {
45            if (isset($path[0]) && $path[0] == $prefix) {
46                array_shift($path);
47                $path = array_values($path); // Reset indexes
48            }
49        }
50
51        if (count($path) == 0) {
52            $controller = 'Index';
53            $method = 'main';
54        } elseif (count($path) == 1) {
55            $controller = $this->snakeCaseToUpperCamelCase($path[0]);
56            $method = 'main';
57        } else {
58            $controller = $this->snakeCaseToUpperCamelCase($path[0]);
59            $method = $this->snakeCaseToLowerCamelCase($path[1]);
60        }
61
62        // Add Controller namespace
63        $controller = '\\App\\Controller\\' . $controller;
64        if (!class_exists($controller)) {
65            return null;
66        }
67        if (!is_subclass_of($controller, AbstractController::class)) {
68            throw new \RuntimeException('Controller invalid: ' . $controller . ' not a ' . AbstractController::class);
69        }
70        $callable = [new $controller($this->request, $this->config), $method];
71        if (!is_callable($callable)) {
72            return null;
73        }
74
75        return $callable;
76    }
77
78    /**
79     * Converts snake_case_text to UpperCamelCaseText
80     *
81     * @param string $snakeCase Text as snake_case.
82     *
83     * @return string
84     */
85    protected function snakeCaseToUpperCamelCase(string $snakeCase): string
86    {
87        return str_replace(' ', '', ucwords(str_replace(['_', '-'], [' ', ' '], $snakeCase)));
88    }
89
90    /**
91     * Converts snake_case_text to lowerCamelCaseText
92     *
93     * @param string $snakeCase Text as snake_case.
94     *
95     * @return string
96     */
97    protected function snakeCaseToLowerCamelCase(string $snakeCase): string
98    {
99        return lcfirst($this->snakeCaseToUpperCamelCase($snakeCase));
100    }
101}