Completed
Push — master ( 3fd2dd...aba624 )
by Grégoire
04:19
created

src/Mapper/BaseGroupedMapper.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Mapper;
15
16
use Sonata\AdminBundle\Admin\AbstractAdmin;
17
18
/**
19
 * This class is used to simulate the Form API.
20
 *
21
 * @author Thomas Rabaix <[email protected]>
22
 */
23
abstract class BaseGroupedMapper extends BaseMapper
24
{
25
    /**
26
     * @var string|null
27
     */
28
    protected $currentGroup;
29
30
    /**
31
     * @var string|null
32
     */
33
    protected $currentTab;
34
35
    /**
36
     * @var bool|null
37
     */
38
    protected $apply;
39
40
    /**
41
     * Add new group or tab (if parameter "tab=true" is available in options).
42
     *
43
     * @param string $name
44
     *
45
     * @throws \RuntimeException
46
     *
47
     * @return $this
48
     */
49
    public function with($name, array $options = [])
50
    {
51
        /*
52
         * The current implementation should work with the following workflow:
53
         *
54
         *     $formMapper
55
         *        ->with('group1')
56
         *            ->add('username')
57
         *            ->add('password')
58
         *        ->end()
59
         *        ->with('tab1', ['tab' => true])
60
         *            ->with('group1')
61
         *                ->add('username')
62
         *                ->add('password')
63
         *            ->end()
64
         *            ->with('group2', ['collapsed' => true])
65
         *                ->add('enabled')
66
         *                ->add('createdAt')
67
         *            ->end()
68
         *        ->end();
69
         *
70
         */
71
        $defaultOptions = [
72
            'collapsed' => false,
73
            'class' => false,
74
            'description' => false,
75
            'label' => $name, // NEXT_MAJOR: Remove this line and uncomment the next one
76
//            'label' => $this->admin->getLabelTranslatorStrategy()->getLabel($name, $this->getName(), 'group'),
77
            'translation_domain' => null,
78
            'name' => $name,
79
            'box_class' => 'box box-primary',
80
        ];
81
82
        // NEXT_MAJOR: remove this code
83
        if ($this->admin instanceof AbstractAdmin && $pool = $this->admin->getConfigurationPool()) {
84
            if ($pool->getContainer()->getParameter('sonata.admin.configuration.translate_group_label')) {
85
                $defaultOptions['label'] = $this->admin->getLabelTranslatorStrategy()->getLabel($name, $this->getName(), 'group');
86
            }
87
        }
88
89
        $code = $name;
90
91
        // Open
92
        if (\array_key_exists('tab', $options) && $options['tab']) {
93
            $tabs = $this->getTabs();
94
95
            if ($this->currentTab) {
96
                if (isset($tabs[$this->currentTab]['auto_created']) && true === $tabs[$this->currentTab]['auto_created']) {
97
                    throw new \RuntimeException('New tab was added automatically when you have added field or group. You should close current tab before adding new one OR add tabs before adding groups and fields.');
98
                }
99
100
                throw new \RuntimeException(sprintf('You should close previous tab "%s" with end() before adding new tab "%s".', $this->currentTab, $name));
101
            } elseif ($this->currentGroup) {
102
                throw new \RuntimeException(sprintf('You should open tab before adding new group "%s".', $name));
103
            }
104
105
            if (!isset($tabs[$name])) {
106
                $tabs[$name] = [];
107
            }
108
109
            $tabs[$code] = array_merge($defaultOptions, [
110
                'auto_created' => false,
111
                'groups' => [],
112
            ], $tabs[$code], $options);
113
114
            $this->currentTab = $code;
115
        } else {
116
            if ($this->currentGroup) {
117
                throw new \RuntimeException(sprintf('You should close previous group "%s" with end() before adding new tab "%s".', $this->currentGroup, $name));
118
            }
119
120
            if (!$this->currentTab) {
121
                // no tab define
122
                $this->with('default', [
123
                    'tab' => true,
124
                    'auto_created' => true,
125
                    'translation_domain' => $options['translation_domain'] ?? null,
126
                ]); // add new tab automatically
127
            }
128
129
            // if no tab is selected, we go the the main one named '_' ..
130
            if ('default' !== $this->currentTab) {
131
                $code = $this->currentTab.'.'.$name; // groups with the same name can be on different tabs, so we prefix them in order to make unique group name
132
            }
133
134
            $groups = $this->getGroups();
135
            if (!isset($groups[$code])) {
136
                $groups[$code] = [];
137
            }
138
139
            $groups[$code] = array_merge($defaultOptions, [
140
                'fields' => [],
141
            ], $groups[$code], $options);
142
143
            $this->currentGroup = $code;
144
            $this->setGroups($groups);
145
            $tabs = $this->getTabs();
146
        }
147
148
        if ($this->currentGroup && isset($tabs[$this->currentTab]) && !\in_array($this->currentGroup, $tabs[$this->currentTab]['groups'], true)) {
149
            $tabs[$this->currentTab]['groups'][] = $this->currentGroup;
150
        }
151
152
        $this->setTabs($tabs);
153
154
        return $this;
155
    }
156
157
    /**
158
     * Only nested add if the condition match true.
159
     *
160
     * @param bool $bool
161
     *
162
     * @throws \RuntimeException
163
     *
164
     * @return $this
165
     */
166
    public function ifTrue($bool)
167
    {
168
        if (null !== $this->apply) {
169
            throw new \RuntimeException('Cannot nest ifTrue or ifFalse call');
170
        }
171
172
        $this->apply = (true === $bool);
173
174
        return $this;
175
    }
176
177
    /**
178
     * Only nested add if the condition match false.
179
     *
180
     * @param bool $bool
181
     *
182
     * @throws \RuntimeException
183
     *
184
     * @return $this
185
     */
186
    public function ifFalse($bool)
187
    {
188
        if (null !== $this->apply) {
189
            throw new \RuntimeException('Cannot nest ifTrue or ifFalse call');
190
        }
191
192
        $this->apply = (false === $bool);
193
194
        return $this;
195
    }
196
197
    /**
198
     * @return $this
199
     */
200
    public function ifEnd()
201
    {
202
        $this->apply = null;
203
204
        return $this;
205
    }
206
207
    /**
208
     * Add new tab.
209
     *
210
     * @param string $name
211
     *
212
     * @return $this
213
     */
214
    public function tab($name, array $options = [])
215
    {
216
        return $this->with($name, array_merge($options, ['tab' => true]));
217
    }
218
219
    /**
220
     * Close the current group or tab.
221
     *
222
     * @throws \RuntimeException
223
     *
224
     * @return $this
225
     */
226
    public function end()
227
    {
228
        if (null !== $this->currentGroup) {
229
            $this->currentGroup = null;
230
        } elseif (null !== $this->currentTab) {
231
            $this->currentTab = null;
232
        } else {
233
            throw new \RuntimeException('No open tabs or groups, you cannot use end()');
234
        }
235
236
        return $this;
237
    }
238
239
    /**
240
     * Returns a boolean indicating if there is an open tab at the moment.
241
     *
242
     * @return bool
243
     */
244
    public function hasOpenTab()
245
    {
246
        return null !== $this->currentTab;
247
    }
248
249
    /**
250
     * @return array
251
     */
252
    abstract protected function getGroups();
253
254
    /**
255
     * @return array
256
     */
257
    abstract protected function getTabs();
258
259
    abstract protected function setGroups(array $groups);
260
261
    abstract protected function setTabs(array $tabs);
262
263
    /**
264
     * NEXT_MAJOR: make this method abstract.
265
     *
266
     * @return string
267
     */
268
    protected function getName()
269
    {
270
        @trigger_error(__METHOD__.' should be implemented and will be abstract in 4.0.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
271
272
        return 'default';
273
    }
274
275
    /**
276
     * Add the field name to the current group.
277
     *
278
     * @param string $fieldName
279
     */
280
    protected function addFieldToCurrentGroup($fieldName)
281
    {
282
        // Note this line must happen before the next line.
283
        // See https://github.com/sonata-project/SonataAdminBundle/pull/1351
284
        $currentGroup = $this->getCurrentGroupName();
285
        $groups = $this->getGroups();
286
        $groups[$currentGroup]['fields'][$fieldName] = $fieldName;
287
        $this->setGroups($groups);
288
289
        return $groups[$currentGroup];
290
    }
291
292
    /**
293
     * Return the name of the currently selected group. The method also makes
294
     * sure a valid group name is currently selected.
295
     *
296
     * Note that this can have the side effect to change the 'group' value
297
     * returned by the getGroup function
298
     *
299
     * @return string
300
     */
301
    protected function getCurrentGroupName()
302
    {
303
        if (!$this->currentGroup) {
304
            $this->with($this->admin->getLabel(), ['auto_created' => true]);
305
        }
306
307
        return $this->currentGroup;
308
    }
309
}
310