Completed
Push — master ( bb6905...021686 )
by Grégoire
18s queued 12s
created

src/Admin/BaseMediaAdmin.php (4 issues)

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\MediaBundle\Admin;
15
16
use Sonata\AdminBundle\Admin\AbstractAdmin;
17
use Sonata\AdminBundle\Datagrid\ListMapper;
18
use Sonata\AdminBundle\Form\FormMapper;
19
use Sonata\AdminBundle\Form\Type\ModelListType;
20
use Sonata\BlockBundle\Meta\Metadata;
21
use Sonata\MediaBundle\Form\DataTransformer\ProviderDataTransformer;
22
use Sonata\MediaBundle\Model\CategoryManagerInterface;
23
use Sonata\MediaBundle\Provider\MediaProviderInterface;
24
use Sonata\MediaBundle\Provider\Pool;
25
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
26
27
abstract class BaseMediaAdmin extends AbstractAdmin
28
{
29
    /**
30
     * @var Pool
31
     */
32
    protected $pool;
33
34
    /**
35
     * @var CategoryManagerInterface
36
     */
37
    protected $categoryManager;
38
39
    protected $classnameLabel = 'Media';
40
41
    /**
42
     * @param string                   $code
43
     * @param string                   $class
44
     * @param string                   $baseControllerName
45
     * @param CategoryManagerInterface $categoryManager
46
     */
47
    public function __construct($code, $class, $baseControllerName, Pool $pool, CategoryManagerInterface $categoryManager = null)
48
    {
49
        parent::__construct($code, $class, $baseControllerName);
50
51
        $this->pool = $pool;
52
53
        $this->categoryManager = $categoryManager;
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function prePersist($media): void
60
    {
61
        $parameters = $this->getPersistentParameters();
62
        $media->setContext($parameters['context']);
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function getPersistentParameters()
69
    {
70
        $parameters = parent::getPersistentParameters();
71
72
        if (!$this->hasRequest()) {
73
            return $parameters;
74
        }
75
76
        $filter = $this->getRequest()->get('filter');
77
        if ($filter && \array_key_exists('context', $this->getRequest()->get('filter'))) {
78
            $context = $filter['context']['value'];
79
        } else {
80
            $context = $this->getRequest()->get('context', $this->pool->getDefaultContext());
81
        }
82
83
        $providers = $this->pool->getProvidersByContext($context);
84
        $provider = $this->getRequest()->get('provider');
85
86
        // if the context has only one provider, set it into the request
87
        // so the intermediate provider selection is skipped
88
        if (1 === \count($providers) && null === $provider) {
89
            $provider = array_shift($providers)->getName();
90
            $this->getRequest()->query->set('provider', $provider);
91
        }
92
93
        // if there is a post server error, provider is not posted and in case of
94
        // multiple providers, it has to be persistent to not being lost
95
        if (1 < \count($providers) && null !== $provider) {
96
            $parameters['provider'] = $provider;
97
        }
98
99
        $categoryId = $this->getRequest()->get('category');
100
101
        if (null !== $this->categoryManager && !$categoryId) {
102
            $categoryId = $this->categoryManager->getRootCategory($context)->getId();
0 ignored issues
show
The method getId() does not seem to exist on object<Sonata\Classifica...odel\CategoryInterface>.

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...
103
        }
104
105
        return array_merge($parameters, [
106
            'context' => $context,
107
            'category' => $categoryId,
108
            'hide_context' => (bool) $this->getRequest()->get('hide_context'),
109
        ]);
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function getNewInstance()
116
    {
117
        $media = parent::getNewInstance();
118
119
        if ($this->hasRequest()) {
120
            if ($this->getRequest()->isMethod('POST')) {
121
                $uniqid = $this->getUniqid();
122
                $media->setProviderName($this->getRequest()->get($uniqid)['providerName']);
123
            } else {
124
                $media->setProviderName($this->getRequest()->get('provider'));
125
            }
126
127
            $media->setContext($context = $this->getRequest()->get('context'));
128
129
            if (null !== $this->categoryManager && $categoryId = $this->getPersistentParameter('category')) {
130
                $category = $this->categoryManager->find($categoryId);
131
132
                if ($category && $category->getContext()->getId() === $context) {
0 ignored issues
show
The method getContext cannot be called on $category (of type array<integer,object<Son...del\CategoryInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug Best Practice introduced by
The expression $category of type Sonata\ClassificationBun...del\CategoryInterface[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
133
                    $media->setCategory($category);
134
                }
135
            }
136
        }
137
138
        return $media;
139
    }
140
141
    /**
142
     * @return Pool
143
     */
144
    public function getPool()
145
    {
146
        return $this->pool;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function getObjectMetadata($object)
153
    {
154
        $provider = $this->pool->getProvider($object->getProviderName());
155
156
        $url = $provider->generatePublicUrl(
157
            $object,
158
            $provider->getFormatName($object, MediaProviderInterface::FORMAT_ADMIN)
159
        );
160
161
        return new Metadata($object->getName(), $object->getDescription(), $url);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Sonata\Block...etDescription(), $url); (Sonata\BlockBundle\Meta\Metadata) is incompatible with the return type declared by the interface Sonata\AdminBundle\Admin...face::getObjectMetadata of type Sonata\AdminBundle\Object\MetadataInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    protected function configureListFields(ListMapper $listMapper): void
168
    {
169
        $listMapper
170
            ->addIdentifier('name')
171
            ->add('description')
172
            ->add('enabled')
173
            ->add('size')
174
        ;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180
    protected function configureFormFields(FormMapper $formMapper): void
181
    {
182
        $media = $this->getSubject();
183
184
        if (!$media) {
185
            $media = $this->getNewInstance();
186
        }
187
188
        if (!$media || !$media->getProviderName()) {
189
            return;
190
        }
191
192
        $formMapper->add('providerName', HiddenType::class);
193
194
        $formMapper->getFormBuilder()->addModelTransformer(new ProviderDataTransformer($this->pool, $this->getClass()), true);
195
196
        $provider = $this->pool->getProvider($media->getProviderName());
197
198
        if ($media->getId()) {
199
            $provider->buildEditForm($formMapper);
200
        } else {
201
            $provider->buildCreateForm($formMapper);
202
        }
203
204
        if (null !== $this->categoryManager) {
205
            $formMapper->add('category', ModelListType::class, [], [
206
                'link_parameters' => [
207
                    'context' => $media->getContext(),
208
                    'hide_context' => true,
209
                    'mode' => 'tree',
210
                ],
211
            ]);
212
        }
213
    }
214
}
215