Completed
Pull Request — master (#357)
by Paul
08:47 queued 02:41
created

LinkExtension::victoireBusinessLink()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
rs 8.8571
cc 3
eloc 16
nc 4
nop 3
1
<?php
2
3
namespace Victoire\Bundle\WidgetBundle\Twig;
4
5
use Doctrine\ORM\EntityManager;
6
use Symfony\Bundle\FrameworkBundle\Routing\Router;
7
use Symfony\Component\HttpFoundation\RequestStack;
8
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
9
use Victoire\Bundle\BusinessEntityBundle\Helper\BusinessEntityHelper;
10
use Victoire\Bundle\BusinessPageBundle\Helper\BusinessPageHelper;
11
use Victoire\Bundle\PageBundle\Helper\PageHelper;
12
use Victoire\Bundle\ViewReferenceBundle\ViewReference\ViewReference;
13
14
/**
15
 * Twig extension for rendering a link.
16
 */
17
class LinkExtension extends \Twig_Extension
18
{
19
    protected $router;
20
    protected $analytics;
21
    protected $businessEntityHelper; // @victoire_business_page.business_entity_helper
22
    protected $BusinessPageHelper; // @victoire_business_page.business_page_helper
23
    protected $pageHelper;
24
    protected $em; // @doctrine.orm.entity_manager
25
    protected $abstractBusinessTemplates;
26
27
    /**
28
     * LinkExtension constructor.
29
     *
30
     * @param Router       $router
31
     * @param RequestStack $requestStack
32
     * @param $analytics
33
     * @param BusinessEntityHelper $businessEntityHelper
34
     * @param BusinessPageHelper   $BusinessPageHelper
35
     * @param PageHelper           $pageHelper
36
     * @param EntityManager        $em
37
     * @param array                $abstractBusinessTemplates
38
     */
39
    public function __construct(
40
        Router $router,
41
        RequestStack $requestStack,
42
        $analytics,
43
        BusinessEntityHelper $businessEntityHelper,
44
        BusinessPageHelper $BusinessPageHelper,
45
        PageHelper $pageHelper,
46
        EntityManager $em,
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
47
        $abstractBusinessTemplates = []
48
    ) {
49
        $this->router = $router;
50
        $this->request = $requestStack->getCurrentRequest();
0 ignored issues
show
Bug introduced by
The property request does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
51
        $this->analytics = $analytics;
52
        $this->businessEntityHelper = $businessEntityHelper;
53
        $this->BusinessPageHelper = $BusinessPageHelper;
54
        $this->pageHelper = $pageHelper;
55
        $this->em = $em;
56
        $this->abstractBusinessTemplates = $abstractBusinessTemplates;
57
    }
58
59
    /**
60
     * Returns a list of functions to add to the existing list.
61
     *
62
     * @return \Twig_SimpleFunction[] An array of functions
63
     */
64
    public function getFunctions()
65
    {
66
        return [
67
            new \Twig_SimpleFunction('vic_link_url', [$this, 'victoireLinkUrl']),
68
            new \Twig_SimpleFunction('vic_link', [$this, 'victoireLink'], ['is_safe' => ['html']]),
69
            new \Twig_SimpleFunction('vic_menu_link', [$this, 'victoireMenuLink'], ['is_safe' => ['html']]),
70
            new \Twig_SimpleFunction('vic_business_link', [$this, 'victoireBusinessLink'], ['is_safe' => ['html']]),
71
        ];
72
    }
73
74
    /**
75
     * Generate the complete link (with the a tag).
76
     *
77
     * @param array  $parameters   The link parameters (go to LinkTrait to have the list)
78
     * @param string $avoidRefresh Do we have to refresh or not ?
79
     * @param array  $url          Fallback url
80
     *
81
     * @return string
82
     */
83
    public function victoireLinkUrl($parameters, $avoidRefresh = true, $url = '#')
84
    {
85
        $referenceType = isset($parameters['referenceType']) ? $parameters['referenceType'] : UrlGeneratorInterface::ABSOLUTE_PATH;
86
87
        $viewReference = isset($parameters['viewReference']) ? $parameters['viewReference'] : null;
88
        switch ($parameters['linkType']) {
89
            case 'viewReference':
90
                if ($viewReference instanceof ViewReference) {
91
                    $viewReference = $viewReference->getId();
92
                }
93
94
                if (isset($viewReferencePage) && $viewReferencePage) {
0 ignored issues
show
Bug introduced by
The variable $viewReferencePage does not exist. Did you mean $viewReference?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
95
                    $page = $viewReferencePage;
96
                } else {
97
                    $page = $this->pageHelper->findPageByParameters(['id' => $viewReference]);
98
                }
99
100
                $linkUrl = $this->router->generate(
101
                    'victoire_core_page_show', [
102
                        '_locale' => $page->getLocale(),
103
                        'url'     => $page->getReference()->getUrl(),
104
                    ],
105
                    $referenceType
106
                );
107
                if ($this->request->getRequestUri() != $linkUrl || !$avoidRefresh) {
108
                    $url = $linkUrl;
109
                }
110
                break;
111
            case 'route':
112
                $url = $this->router->generate($parameters['route'], $parameters['routeParameters'], $referenceType);
113
                break;
114
            case 'attachedWidget':
115
                $attachedWidget = $parameters['attachedWidget'];
116
                //fallback when a widget is deleted cascading the relation as null (widget_id = null)
117
                if ($attachedWidget && method_exists($attachedWidget->getView(), 'getUrl')) {
118
119
                    //create base url
120
                    $url = $this->router->generate('victoire_core_page_show', ['_locale' => $attachedWidget->getView()->getLocale(), 'url' => $attachedWidget->getView()->getUrl()], $referenceType);
121
122
                    //If widget in the same view
123
                    if (rtrim($this->request->getRequestUri(), '/') == rtrim($url, '/')) {
124
                        $url = '';
125
                    }
126
                    //Add anchor part
127
                    $url .= '#vic-widget-'.$attachedWidget->getId().'-container-anchor';
128
                }
129
                break;
130
            default:
131
                $url = $parameters['url'];
132
        }
133
134
        return $url;
135
    }
136
137
    /**
138
     * Generate the complete link (with the a tag).
139
     *
140
     * @param array  $parameters The link parameters (go to LinkTrait to have the list)
141
     * @param string $label      link label
142
     * @param array  $attr       custom attributes
143
     *
144
     * @return string
145
     */
146
    public function victoireLink($parameters, $label, $attr = [], $currentClass = 'active', $url = '#')
147
    {
148
        $referenceLink = UrlGeneratorInterface::ABSOLUTE_PATH;
149
        $attachedWidget = isset($parameters['attachedWidget']) ? $parameters['attachedWidget'] : null;
150
151
        if ($parameters['linkType'] == 'attachedWidget' && $attachedWidget && method_exists($attachedWidget->getView(), 'getUrl')) {
152
            $viewUrl = $this->router->generate('victoire_core_page_show', ['_locale' => $attachedWidget->getView()->getLocale(), 'url' => $attachedWidget->getView()->getUrl()], $referenceLink);
153
            if (rtrim($this->request->getRequestUri(), '/') == rtrim($viewUrl, '/')) {
154
                $attr['data-scroll'] = 'smooth';
155
            }
156
        }
157
158
        //Avoid to refresh page if not needed
159
        if ($this->request->getRequestUri() == $this->victoireLinkUrl($parameters, false)) {
160
            $this->addAttr('class', $currentClass, $attr);
161
        }
162
163
        //Build the target attribute
164
        if ($parameters['target'] == 'ajax-modal') {
165
            $attr['data-toggle'] = 'ajax-modal';
166
        } elseif ($parameters['target'] == '') {
167
            $attr['target'] = '_parent';
168
        } else {
169
            $attr['target'] = $parameters['target'];
170
        }
171
172
        //Add the analytics tracking code attribute
173
        if (isset($parameters['analyticsTrackCode'])) {
174
            $this->addAttr('onclick', $parameters['analyticsTrackCode'], $attr);
175
        }
176
177
        //Assemble and prepare attributes
178
        $attributes = [];
179 View Code Duplication
        foreach ($attr as $key => $_attr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
            if (is_array($_attr)) {
181
                $attr = implode($_attr, ' ');
182
            } else {
183
                $attr = $_attr;
184
            }
185
            $attributes[] = $key.'="'.$attr.'"';
186
        }
187
188
        $url = $this->victoireLinkUrl($parameters, true, $url);
189
        //Creates a new twig environment
190
        $twig = new \Twig_Environment(new \Twig_Loader_Array(['linkTemplate' => '{{ link|raw }}']));
191
192
        return $twig->render('linkTemplate', ['link' => '<a href="'.$url.'" '.implode($attributes, ' ').'>'.$label.'</a>']);
193
    }
194
195
    /**
196
     * Generate the complete menu link item (with the li tag).
197
     *
198
     * @param array  $parameters The link parameters (go to LinkTrait to have the list)
199
     * @param string $label      link label
200
     * @param array  $attr       custom attributes
201
     *
202
     * @return string
203
     */
204
    public function victoireMenuLink($parameters, $label, $attr = [])
205
    {
206
        $linkAttr = [];
207
        //is the link is active
208
        if ($this->request->getRequestUri() == $this->victoireLinkUrl($parameters, false)) {
209
            if (!isset($attr['class'])) {
210
                $linkAttr['class'] = '';
211
            }
212
            $linkAttr['class'] .= 'active'; //avoid to refresh page when not needed
213
        }
214
215
        $linkAttributes = [];
216 View Code Duplication
        foreach ($linkAttr as $key => $_attr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
            if (is_array($_attr)) {
218
                $linkAttr = implode($_attr, ' ');
219
            } else {
220
                $linkAttr = $_attr;
221
            }
222
            $linkAttributes[] = $key.'="'.$linkAttr.'"';
223
        }
224
225
        return '<li '.implode($linkAttributes, ' ').'>'.$this->victoireLink($parameters, $label, $attr, false, '#top').'</li>';
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
226
    }
227
228
    public function victoireBusinessLink($businessEntityInstance, $templateId = null, $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
229
    {
230
        if (isset($this->abstractBusinessTemplates[$templateId])) {
231
            $templateId = $this->abstractBusinessTemplates[$templateId];
232
        }
233
        if (!$templateId) {
234
            $templateId = $this->BusinessPageHelper
235
                ->guessBestPatternIdForEntity(new \ReflectionClass($businessEntityInstance), $businessEntityInstance->getId(), $this->em);
236
        }
237
238
        $page = $this->pageHelper->findPageByParameters([
239
            'templateId' => $templateId,
240
            'entityId'   => $businessEntityInstance->getId(),
241
        ]);
242
243
        $parameters = [
244
            'linkType'        => 'route',
245
            'route'           => 'victoire_core_page_show',
246
            'routeParameters' => [
247
                'url' => $page->getReference()->getUrl(),
248
            ],
249
            'referenceType' => $referenceType,
250
        ];
251
252
        return $this->victoireLinkUrl($parameters);
253
    }
254
255
    /**
256
     * Add a given attribute to given attributes.
257
     *
258
     * @param string $label
259
     * @param string $value
260
     * @param array  $attr  The current attributes array
261
     *
262
     * @return LinkExtension
263
     **/
264
    protected function addAttr($label, $value, &$attr)
265
    {
266
        if (!isset($attr[$label])) {
267
            $attr[$label] = '';
268
        } else {
269
            $attr[$label] .= ' ';
270
        }
271
        $attr[$label] .= $value;
272
273
        return $this;
274
    }
275
276
    /**
277
     * Returns the name of the extension.
278
     *
279
     * @return string The extension name
280
     */
281
    public function getName()
282
    {
283
        return 'victoire_link_extension';
284
    }
285
}
286