Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
26 / 26
UrlToMvcRouter
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
4 / 4
12
100.00% covered (success)
100.00%
26 / 26
 getRouters
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 requestToMvc
100.00% covered (success)
100.00%
1 / 1
9
100.00% covered (success)
100.00%
23 / 23
 snakeCaseToUpperCamelCase
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 snakeCaseToLowerCamelCase
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
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        $basePath = explode('/', trim(parse_url($this->config->get('framework', 'base_href'), PHP_URL_PATH), '/'));
38        foreach ($basePath as $prefix) {
39            if (isset($path[0]) && $path[0] == $prefix) {
40                array_shift($path);
41                $path = array_values($path); // Reset indexes
42            }
43        }
44
45        if (count($path) == 0) {
46            $controller = 'Index';
47            $method = 'main';
48        } elseif (count($path) == 1) {
49            $controller = $this->snakeCaseToUpperCamelCase($path[0]);
50            $method = 'main';
51        } else {
52            $controller = $this->snakeCaseToUpperCamelCase($path[0]);
53            $method = $this->snakeCaseToLowerCamelCase($path[1]);
54        }
55
56        // Add Controller namespace
57        $controller = '\\App\\Controller\\' . $controller;
58        if (!class_exists($controller)) {
59            return null;
60        }
61        if (!is_subclass_of($controller, AbstractController::class)) {
62            throw new \RuntimeException('Controller invalid: ' . $controller . ' not a ' . AbstractController::class);
63        }
64        $callable = [new $controller($this->request, $this->config), $method];
65        if (!is_callable($callable)) {
66            return null;
67        }
68
69        return $callable;
70    }
71
72    /**
73     * Converts snake_case_text to UpperCamelCaseText
74     *
75     * @param string $snakeCase Text as snake_case.
76     *
77     * @return string
78     */
79    protected function snakeCaseToUpperCamelCase(string $snakeCase): string
80    {
81        return str_replace(' ', '', ucwords(str_replace(['_', '-'], [' ', ' '], $snakeCase)));
82    }
83
84    /**
85     * Converts snake_case_text to lowerCamelCaseText
86     *
87     * @param string $snakeCase Text as snake_case.
88     *
89     * @return string
90     */
91    protected function snakeCaseToLowerCamelCase(string $snakeCase): string
92    {
93        return lcfirst($this->snakeCaseToUpperCamelCase($snakeCase));
94    }
95}