Completed
Push — 3.x ( 3e834f...38b337 )
by Grégoire
03:36
created

src/Datagrid/DatagridMapper.php (2 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\AdminBundle\Datagrid;
15
16
use Sonata\AdminBundle\Admin\AdminInterface;
17
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
18
use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
19
use Sonata\AdminBundle\Mapper\BaseMapper;
20
21
/**
22
 * This class is use to simulate the Form API.
23
 *
24
 * @final since sonata-project/admin-bundle 3.52
25
 *
26
 * @author Thomas Rabaix <[email protected]>
27
 */
28
class DatagridMapper extends BaseMapper
29
{
30
    /**
31
     * @var DatagridInterface
32
     */
33
    protected $datagrid;
34
35
    public function __construct(
36
        DatagridBuilderInterface $datagridBuilder,
37
        DatagridInterface $datagrid,
38
        AdminInterface $admin
39
    ) {
40
        parent::__construct($datagridBuilder, $admin);
41
        $this->datagrid = $datagrid;
42
    }
43
44
    /**
45
     * @param FieldDescriptionInterface|string $name
46
     * @param string|null                      $type
47
     * @param string|null                      $fieldType
48
     * @param array|null                       $fieldOptions
49
     *
50
     * @throws \LogicException
51
     *
52
     * @return DatagridMapper
53
     */
54
    public function add(
55
        $name,
56
        $type = null,
57
        array $filterOptions = [],
58
        $fieldType = null,
59
        $fieldOptions = null,
60
        array $fieldDescriptionOptions = []
61
    ) {
62
        if (\is_array($fieldOptions)) {
63
            $filterOptions['field_options'] = $fieldOptions;
64
        }
65
66
        if ($fieldType) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldType of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
67
            $filterOptions['field_type'] = $fieldType;
68
        }
69
70
        if ($name instanceof FieldDescriptionInterface) {
71
            $fieldDescription = $name;
72
            $fieldDescription->mergeOptions($filterOptions);
73
        } elseif (\is_string($name)) {
74
            if ($this->admin->hasFilterFieldDescription($name)) {
75
                throw new \LogicException(sprintf('Duplicate field name "%s" in datagrid mapper. Names should be unique.', $name));
76
            }
77
78
            if (!isset($filterOptions['field_name'])) {
79
                $filterOptions['field_name'] = substr(strrchr('.'.$name, '.'), 1);
80
            }
81
82
            $fieldDescription = $this->admin->getModelManager()->getNewFieldDescriptionInstance(
83
                $this->admin->getClass(),
84
                $name,
85
                array_merge($filterOptions, $fieldDescriptionOptions)
86
            );
87
        } else {
88
            throw new \TypeError(
89
                'Unknown field name in datagrid mapper.'
90
                .' Field name should be either of FieldDescriptionInterface interface or string.'
91
            );
92
        }
93
94
        if (!isset($fieldDescriptionOptions['role']) || $this->admin->isGranted($fieldDescriptionOptions['role'])) {
95
            // add the field with the DatagridBuilder
96
            $this->builder->addFilter($this->datagrid, $type, $fieldDescription, $this->admin);
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Sonata\AdminBundle\Builder\BuilderInterface as the method addFilter() does only exist in the following implementations of said interface: Sonata\AdminBundle\Tests...Builder\DatagridBuilder.

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...
97
        }
98
99
        return $this;
100
    }
101
102
    public function get($name)
103
    {
104
        return $this->datagrid->getFilter($name);
105
    }
106
107
    public function has($key)
108
    {
109
        return $this->datagrid->hasFilter($key);
110
    }
111
112
    final public function keys()
113
    {
114
        return array_keys($this->datagrid->getFilters());
115
    }
116
117
    public function remove($key)
118
    {
119
        $this->admin->removeFilterFieldDescription($key);
120
        $this->datagrid->removeFilter($key);
121
122
        return $this;
123
    }
124
125
    public function reorder(array $keys)
126
    {
127
        $this->datagrid->reorderFilters($keys);
128
129
        return $this;
130
    }
131
}
132