Completed
Pull Request — develop (#261)
by
unknown
08:05
created

SummaryForm::renderSummary()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 44
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 44
rs 6.7272
cc 7
eloc 28
nc 9
nop 1
1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
7
 * @license   MIT
8
 */
9
10
/**  */
11
namespace Core\Form\View\Helper;
12
13
use Core\Form\SummaryFormInterface;
14
use Zend\Form\Element\Hidden;
15
use Zend\Form\FormInterface;
16
use Zend\Form\View\Helper\AbstractHelper;
17
use Zend\Form\ElementInterface;
18
use Zend\Form\FieldsetInterface;
19
use Core\Form\ViewPartialProviderInterface;
20
use Core\Form\DescriptionAwareFormInterface;
21
use Core\Form\EmptySummaryAwareInterface;
22
23
/**
24
 * Helper to render a summary form container.
25
 *
26
 * @author Mathias Gelhausen <[email protected]>
27
 */
28
class SummaryForm extends AbstractHelper
29
{
30
    
31
    /**
32
     * Invoke as function.
33
     *
34
     * @param null|SummaryFormInterface $form
35
     * @param string $layout
36
     * @param array $parameter
37
     * @return \Core\Form\View\Helper\SummaryForm|string
0 ignored issues
show
Documentation introduced by
Should the return type not be SummaryForm|string|\Zend\View\Helper\Partial?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
38
     */
39
    public function __invoke(SummaryFormInterface $form = null, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
40
    {
41
        if (null === $form) {
42
            return $this;
43
        }
44
        
45
        $mode = $form->getRenderMode();
46
        if (SummaryFormInterface::RENDER_FORM == $mode) {
47
            return $this->renderForm($form, $layout, $parameter);
48
        }
49
        if (SummaryFormInterface::RENDER_SUMMARY == $mode) {
50
            return $this->renderSummary($form);
51
        }
52
        
53
        return $this->render($form, $layout, $parameter);
54
    }
55
    
56
    /**
57
     * Renders a summary form container.
58
     *
59
     * @param SummaryFormInterface $form
60
     * @param string $layout
61
     * @param array $parameter
62
     * @return string
63
     */
64
    public function render(SummaryFormInterface $form, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
65
    {
66
        $renderer = $this->getView();
67
        $renderer->headscript()->appendFile($renderer->basePath('Core/js/jquery.summary-form.js'));
68
        
69
        $label = $form->getLabel();
70
        $labelContent = $label ? '<div class="sf-headline"><h3>' . $this->getView()->translate($label) . '</h3></div>' : '';
0 ignored issues
show
Bug introduced by
The method translate() does not seem to exist on object<Zend\View\Renderer\RendererInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
71
        $formContent  = $this->renderForm($form, $layout, $parameter);
72
        $summaryContent = $this->renderSummary($form);
73
        
74
        $formContent = sprintf(
75
            '<div class="sf-form"><div class="panel panel-info"><div class="panel-body">%s</div></div></div>
76
                 <div class="sf-summary">%s</div>
77
                ',
78
            $formContent,
79
            $summaryContent
80
        );
81
        
82
        if ($form instanceof DescriptionAwareFormInterface && $form->isDescriptionsEnabled()) {
83
            $this->getView()->headscript()->appendFile(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\View\Renderer\RendererInterface as the method headscript() does only exist in the following implementations of said interface: Zend\View\Renderer\PhpRenderer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
84
                $this->getView()->basepath('Core/js/forms.descriptions.js')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\View\Renderer\RendererInterface as the method basepath() does only exist in the following implementations of said interface: Zend\View\Renderer\PhpRenderer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
85
            );
86
        
87
            if ($desc = $form->getOption('description', '')) {
88
                $translator = $this->getTranslator();
89
                $textDomain = $this->getTranslatorTextDomain();
90
        
91
                $desc = $translator->translate($desc, $textDomain);
92
            }
93
        
94
            $formContent = sprintf(
95
                '<div class="daf-form-container row">
96
                        <div class="daf-form col-md-8">%s</div>
97
                        <div class="daf-desc col-md-4">
98
                            <div class="daf-desc-content alert alert-info">%s</div>
99
                        </div>
100
                    </div>',
101
                $formContent,
102
                $desc
103
            );
104
        }
105
        
106
        $markup = '<div id="sf-%s" class="sf-container" data-display-mode="%s">'
107
                . '%s'
108
                . '%s'
109
                . '</div>';
110
        
111
        $content = sprintf(
112
            $markup,
113
            $form->getAttribute('name'),
114
            $form->getDisplayMode(),
115
            $labelContent,
116
            $formContent
117
        );
118
        
119
        
120
        return $content;
121
    }
122
123
    /**
124
     * Only renders the form representation of a summary form.
125
     *
126
     * @param SummaryFormInterface $form
127
     * @param string $layout
128
     * @param array $parameter
129
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|\Zend\View\Helper\Partial?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
130
     */
131
    public function renderForm(SummaryFormInterface $form, $layout = Form::LAYOUT_HORIZONTAL, $parameter = array())
132
    {
133
                                                    /* @var $form SummaryFormInterface|\Core\Form\SummaryForm */
134
        $renderer     = $this->getView();           /* @var $renderer \Zend\View\Renderer\PhpRenderer */
135
        $formHelper   = $renderer->plugin('form');  /* @var $formHelper \Core\Form\View\Helper\Form */
136
        $fieldset     = $form->getBaseFieldset();
137
        $resetPartial = false;
138
139
        if ($fieldset instanceof ViewPartialProviderInterface) {
140
            $origPartial = $fieldset->getViewPartial();
141
            $partial     = "$origPartial.form";
142
            if ($renderer->resolver($partial)) {
143
                $fieldset->setViewPartial($partial);
144
                $resetPartial = true;
145
            }
146
        }
147
148
        $markup = $formHelper->renderBare($form, $layout, $parameter);
149
150
        if ($resetPartial) {
151
            /** @noinspection PhpUndefinedVariableInspection */
152
            $fieldset->setViewPartial($origPartial);
0 ignored issues
show
Bug introduced by
The variable $origPartial does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
153
        }
154
155
        return $markup;
156
    }
157
    
158
    /**
159
     * Only renders the summary representation of a summary form
160
     *
161
     * @param SummaryFormInterface $form
162
     * @return string
163
     */
164
    public function renderSummary(SummaryFormInterface $form)
165
    {
166
        $form->prepare();
0 ignored issues
show
Bug introduced by
The method prepare() does not exist on Core\Form\SummaryFormInterface. Did you maybe mean prepareElement()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
167
        $baseFieldset = $form->getBaseFieldset();
168
        if (!isset($baseFieldset)) {
169
            throw new \InvalidArgumentException('For the Form ' . get_class($form) . ' there is no Basefieldset');
170
        }
171
172
        $dataAttributesMarkup = '';
173
        $dataAttributes = array_filter($form->getAttributes(), function ($key) {
174
            return preg_match('/^data-/', $key);
175
        }, ARRAY_FILTER_USE_KEY);
176
        
177
        foreach ($dataAttributes as $dataKey => $dataValue)
178
        {
179
            $dataAttributesMarkup .= sprintf(' %s="%s"', $dataKey, $dataValue);
180
        }
181
        
182
        $markup = '<div class="panel panel-default" style="min-height: 100px;"' . $dataAttributesMarkup . '>
183
                    <div class="panel-body"><div class="sf-controls">%s</div>%s</div></div>';
184
185
        $view = $this->getView();
186
        $buttonMarkup = false === $form->getOption('editable')
187
                      ? ''
188
                      : '<button type="button" class="btn btn-default btn-xs sf-edit">'
189
                        . '<span class="yk-icon yk-icon-edit"></span> '
190
                        . $view->translate('Edit')
0 ignored issues
show
Bug introduced by
The method translate() does not seem to exist on object<Zend\View\Renderer\RendererInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
191
                        . '</button>';
192
        
193
        if (($controlButtons = $form->getOption('control_buttons')) !== null)
194
        {
195
            $buttonMarkup .= PHP_EOL . implode(PHP_EOL, array_map(function (array $buttonSpec) use ($view) {
196
                return '<button type="button" class="btn btn-default btn-xs' . (isset($buttonSpec['class']) ? ' ' . $buttonSpec['class'] : '') . '">'
197
                    . (isset($buttonSpec['icon']) ? '<span class="yk-icon yk-icon-' . $buttonSpec['icon'] . '"></span> ' : '')
198
                    . $view->translate($buttonSpec['label'])
0 ignored issues
show
Bug introduced by
The method translate() does not seem to exist on object<Zend\View\Renderer\RendererInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
199
                    . '</button>';
200
            }, $controlButtons));
201
        }
202
203
        $elementMarkup = $this->renderSummaryElement($baseFieldset);
204
205
206
        return sprintf($markup, $buttonMarkup, $elementMarkup);
207
    }
208
    
209
    /**
210
     * Helper function to recurse into form elements when rendering summary.
211
     *
212
     * @param ElementInterface $element
213
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|\Zend\View\Helper\Partial?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
214
     */
215
    public function renderSummaryElement(ElementInterface $element)
216
    {
217
        if ($element instanceof Hidden || false === $element->getOption('render_summary')) {
218
            return '';
219
        }
220
221
        if ($element instanceof EmptySummaryAwareInterface && $element->isSummaryEmpty()) {
222
            /* @var $element EmptySummaryAwareInterface|ElementInterface */
223
            $emptySummaryNotice = $this->getTranslator()->translate(
224
                $element->getEmptySummaryNotice(),
0 ignored issues
show
Bug introduced by
The method getEmptySummaryNotice does only exist in Core\Form\EmptySummaryAwareInterface, but not in Zend\Form\ElementInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
225
                $this->getTranslatorTextDomain()
226
            );
227
228
            $markup = sprintf(
229
                '<div id="%s-empty-alert" class="empty-summary-notice alert alert-info"><p>%s</p></div>',
230
                $element->getAttribute('id'),
0 ignored issues
show
Bug introduced by
The method getAttribute does only exist in Zend\Form\ElementInterface, but not in Core\Form\EmptySummaryAwareInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
231
                $emptySummaryNotice
232
            );
233
            return $markup;
234
        }
235
236
        if ($element instanceof ViewPartialProviderInterface) {
237
            $renderer    = $this->getView();                 /* @var $renderer \Zend\View\Renderer\PhpRenderer */
238
            $origPartial = $element->getViewPartial();
239
            $partial     = "$origPartial.view";
240
            $partialParams  = array(
241
                'element' => $element
242
            );
243
            if (!$renderer->resolver($partial)) {
244
                $partial = $origPartial;
245
                $partialParams['renderSummary'] = true;
246
            }
247
    
248
            return $renderer->partial($partial, $partialParams);
249
        }
250
    
251
        $label  = $this->getTranslator()->translate($element->getLabel());
252
        $markup = '';
253
        
254
        if ($element instanceof FieldsetInterface) {
255
            if (!$element instanceof FormInterface && $label) {
256
                $markup .= '<h4>' . $label . '</h4>';
257
            }
258
            foreach ($element as $el) {
259
                $markup .= $this->renderSummaryElement($el);
260
            }
261
            return $markup;
262
        }
263
    
264
        $elementValue = $element instanceof \Zend\Form\Element\Textarea
265
                      ? nl2br($element->getValue())
266
                      : $element->getValue();
267
268
        if ('' != $elementValue && $element instanceof \Zend\Form\Element\Select) {
269
            $generalOptGroupName = '__general__';
270
            $options = $element->getValueOptions();
271
            $translator = $this->getTranslator();
272
            if (true == $element->getAttribute('multiple')) {
273
274
                $multiOptions = [];
275
                foreach ($elementValue as $optionKey) {
276
                    if (isset($options[$optionKey])) {
277
                        $multiOptions[$generalOptGroupName][] = $translator->translate($options[$optionKey]);
278
                        continue;
279
                    }
280
281
                    foreach ($options as $optKey => $optVal) {
282
                        if (!is_array($optVal) || !array_key_exists($optionKey, $optVal['options'])) { continue; }
283
284
                        $optGroupLabel = isset($optVal['label']) ? $translator->translate($optVal['label']) : $optKey;
285
                        $multiOptions[$optGroupLabel][] = $translator->translate($optVal['options'][$optionKey]);
286
                    }
287
                }
288
289
                $elementValue = [];
290
                $numberOfmultiOptions = count($multiOptions);
291
                foreach ($multiOptions as $optGroupLabel => $vals) {
292
                    $elementValue[] = ($numberOfmultiOptions > 1 || $optGroupLabel !== $generalOptGroupName ? "<b>$optGroupLabel</b><br>" : '') . join(', ', $vals);
293
                }
294
                $elementValue = join('<br>', $elementValue) . '<br>';
295
296
            } else {
297
                $elementValue = $translator->translate($options[$elementValue]);
298
            }
299
        }
300
301
        if ('' != $elementValue && $element instanceOf \Zend\Form\Element\File) {
302
            return '';
303
        }
304
                      
305
        $markup .= '<div class="row">';
306
        $col = 12;
307
        if ($label) {
308
            $markup .= '<div class="col-md-3 yk-label"><label>' . $label . '</label></div>';
309
            $col = 9;
310
        }
311
        $markup .= '<div class="col-md-' . $col . '">' . $elementValue . '</div>'
312
            . '</div>';
313
        return $markup;
314
    }
315
}
316