Completed
Push — master ( 1117dd...39043c )
by Yonel Ceruto
10:43
created

BreadcrumbsBuilder::getRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 0
1
<?php
2
3
/*
4
 * This file is part of the BreadcrumbsBundle.
5
 *
6
 * (c) Yonel Ceruto <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Yceruto\Bundle\BreadcrumbsBundle;
13
14
use Symfony\Bundle\FrameworkBundle\Routing\Router;
15
use Symfony\Component\HttpFoundation\Request;
16
use Symfony\Component\HttpFoundation\RequestStack;
17
use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
18
19
/**
20
 * This builder works in 2 modes:
21
 *
22
 *  * 2.3 compatibility mode where you must call setRequest whenever the Request changes.
23
 *  * 2.4+ mode where you must pass a RequestStack instance in the constructor.
24
 *
25
 * @author Yonel Ceruto <[email protected]>
26
 */
27
class BreadcrumbsBuilder
28
{
29
    /**
30
     * @var RequestStack
31
     */
32
    private $requestStack;
33
34
    /**
35
     * @var Request
36
     */
37
    private $request;
38
39
    /**
40
     * @var Router
41
     */
42
    private $router;
43
44
    /**
45
     * @var TraceableUrlMatcher
46
     */
47
    private $matcher;
48
49
    public function __construct(Router $router, RequestStack $requestStack = null)
50
    {
51
        $this->router = $router;
52
        $this->requestStack = $requestStack;
53
    }
54
55
    /**
56
     * BC with SF 2.3
57
     *
58
     * @param Request|null $request
59
     */
60
    public function setRequest(Request $request = null)
61
    {
62
        $this->request = $request;
63
    }
64
65
    /**
66
     * Create a empty breadcrumb
67
     *
68
     * @return Breadcrumbs
69
     */
70
    public function create()
71
    {
72
        return new Breadcrumbs();
73
    }
74
75
    /**
76
     * Create a breadcrumb through current request path
77
     *
78
     * @return Breadcrumbs
79
     */
80
    public function createFromRequest()
81
    {
82
        if (empty($this->matcher)) {
83
            $this->matcher = new TraceableUrlMatcher($this->router->getRouteCollection(), $this->router->getContext());
84
        }
85
86
        $breadcrumbs = new Breadcrumbs();
87
88
        $parent = null;
89
        $paths = $this->getBreadcrumbsPaths();
90
        foreach ($paths as $path) {
91
            if ($node = $this->createBreadcrumbsNode($path, $parent)) {
92
                $breadcrumbs->addNode($node);
93
                $parent = $path;
94
            }
95
        }
96
97
        return $breadcrumbs;
98
    }
99
100
    /**
101
     * Get all breadcrumbs paths from current request path
102
     *
103
     * @return array of string
104
     */
105
    private function getBreadcrumbsPaths()
106
    {
107
        $parts = array();
108
        $pathInfo = trim($this->getRequest()->getPathInfo(), '/');
109
110
        if ($pathInfo) {
111
            $parts = explode('/', $pathInfo);
112
        }
113
114
        array_unshift($parts, '/');
115
116
        $path = '';
117
        $paths = array();
118
        foreach ($parts as $part) {
119
            $path .= $part;
120
            $paths[] = $path;
121
122
            if (strlen($part) > 1) {
123
                $path .= '/';
124
                $paths[] = $path;
125
            }
126
        }
127
128
        return $paths;
129
    }
130
131
    /**
132
     * Create a breadcrumbs node from path
133
     *
134
     * @param string $path
135
     * @param string $parent
136
     *
137
     * @return BreadcrumbsNode|bool
138
     */
139
    private function createBreadcrumbsNode($path, $parent)
140
    {
141
        // use $baseUrl for no prod environments e.g dev 'app_dev.php'
142
        $baseUrl = $this->getRequest()->getBaseUrl();
143
144
        $traces = $this->matcher->getTraces($path);
145
        foreach ($traces as $trace) {
146
            if (TraceableUrlMatcher::ROUTE_MATCHES == $trace['level']) {
147
                $route = $this->router->getRouteCollection()->get($trace['name']);
148
149
                // get label through settings
150
                $label = $route->getDefault('breadcrumbs_label');
151
152
                if (empty($label)) {
153
                    // get label through path
154
                    $compiledRoute = $route->compile();
155
                    $vars = $compiledRoute->getVariables();
156
157
                    if (empty($vars)) {
158
                        $label = substr($path, strlen($parent));
159
                    } elseif (preg_match($compiledRoute->getRegex(), $path, $match)) {
160
                        $label = $match[end($vars)];
161
                    }
162
                    $label = trim(preg_replace('[\W|_]', ' ', $label));
163
                }
164
165
                if (empty($label)) {
166
                    // get label through route name
167
                    $label = 'breadcrumbs.'.$trace['name'];
168
                }
169
170
                $node = new BreadcrumbsNode();
171
                $node->setLabel($label);
172
                $node->setPath($baseUrl.$path);
173
174
                return $node;
175
            }
176
        }
177
178
        return false;
179
    }
180
181
    private function getRequest()
182
    {
183
        return $this->requestStack ? $this->requestStack->getCurrentRequest() : $this->request;
184
    }
185
}
186