Completed
Push — master ( b17efa...63e741 )
by
unknown
04:17 queued 01:40
created

ChoicesBuilder::getChoicesFromRepository()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 28
rs 6.7273
cc 7
eloc 17
nc 8
nop 1
1
<?php
2
namespace Netdudes\DataSourceryBundle\DataSource\Util;
3
4
use Doctrine\ORM\EntityManager;
5
use Doctrine\ORM\EntityRepository;
6
7
class ChoicesBuilder
8
{
9
    /**
10
     * @var EntityManager
11
     */
12
    private $entityManager;
13
14
    /**
15
     * @param EntityManager $entityManager
16
     */
17
    public function __construct(EntityManager $entityManager)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $entityManager. 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...
18
    {
19
        $this->entityManager = $entityManager;
20
    }
21
22
    /**
23
     * @param array|callable $choicesConfiguration
24
     *
25
     * @return array
26
     *
27
     * @throws \Exception
28
     */
29
    public function build($choicesConfiguration)
30
    {
31
        if (is_callable($choicesConfiguration)) {
32
            return $this->getChoicesFromCallable($choicesConfiguration);
33
        }
34
35
        if (is_array($choicesConfiguration)) {
36
            if (isset($choicesConfiguration['repository'])) {
37
                return $this->getChoicesFromRepository($choicesConfiguration);
38
            }
39
40
            return $choicesConfiguration;
41
        }
42
43
        throw new \Exception('No usable configuration was found');
44
    }
45
46
    /**
47
     * @param array $choicesConfiguration
48
     *
49
     * @return array
50
     *
51
     * @throws \Exception
52
     */
53
    private function getChoicesFromRepository(array $choicesConfiguration)
54
    {
55
        if ($choicesConfiguration['repository'] instanceof EntityRepository) {
56
            $repository = $this->getSpecifiedRepository($choicesConfiguration['repository']);
0 ignored issues
show
Deprecated Code introduced by
The method Netdudes\DataSourceryBun...etSpecifiedRepository() has been deprecated with message: Specifying repository as an object is deprecated and will not be supported since 1.0.0. Specify it by it's name instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
57
        } else {
58
            $repository = $this->entityManager->getRepository($choicesConfiguration['repository']);
59
        }
60
61
        if (isset($choicesConfiguration['field']) && isset($choicesConfiguration['method'])) {
62
            throw new \Exception('Repository source expects field or method parameter, but not both');
63
        }
64
65
        if (isset($choicesConfiguration['field'])) {
66
            return $this->getChoicesFromRepositoryForField(
67
                $repository,
68
                $choicesConfiguration['field'],
69
                isset($choicesConfiguration['sort']) ? $choicesConfiguration['sort'] : null
70
            );
71
        }
72
        if (isset($choicesConfiguration['method'])) {
73
            return $this->getChoicesFromRepositoryWithMethod(
74
                $repository,
75
                $choicesConfiguration['method']
76
            );
77
        }
78
79
        throw new \Exception('Repository source expects field or method parameter');
80
    }
81
82
    /**
83
     * @deprecated Specifying repository as an object is deprecated and will not be supported since 1.0.0. Specify it by it's name instead.
84
     *
85
     * @param EntityRepository $repository
86
     *
87
     * @return EntityRepository
88
     */
89
    private function getSpecifiedRepository(EntityRepository $repository)
90
    {
91
        trigger_error('Specifying repository as an object is deprecated and will not be supported since 1.0.0. Specify it by it\'s name instead.', E_USER_DEPRECATED);
92
93
        return $repository;
94
    }
95
96
    /**
97
     * Get all values available for this data field for consumption by
98
     * the front-end in order to enable advanced UX functionality.
99
     *
100
     * @param EntityRepository $repository
101
     * @param string           $property
102
     * @param null|string      $sortOrder
103
     *
104
     * @return array
105
     */
106
    private function getChoicesFromRepositoryForField(EntityRepository $repository, $property, $sortOrder = null)
107
    {
108
        $queryBuilder = $repository->createQueryBuilder('entity')
109
            ->select('entity.' . $property);
110
111
        if (!is_null($sortOrder)) {
112
            $queryBuilder->orderBy('entity.' . $property, $sortOrder);
113
        }
114
115
        $results = $queryBuilder
116
            ->getQuery()
117
            ->getArrayResult();
118
        $choices = [];
119
        foreach ($results as $value) {
120
            $choices[$value[$property]] = $value[$property];
121
        }
122
123
        return $choices;
124
    }
125
126
    /**
127
     * @param EntityRepository $repository
128
     * @param string           $method
129
     *
130
     * @return array
131
     *
132
     * @throws \Exception
133
     */
134
    private function getChoicesFromRepositoryWithMethod(EntityRepository $repository, $method)
135
    {
136
        if (!method_exists($repository, $method)) {
137
            throw new \Exception("Specified repository does not have '$method' method");
138
        }
139
140
        $choices = $repository->$method();
141
        if (!is_array($choices)) {
142
            throw new \Exception('Choices repository method defined in table configurations must return array');
143
        }
144
145
        return $choices;
146
    }
147
148
    /**
149
     * @param callable $callable
150
     *
151
     * @return array
152
     *
153
     * @throws \Exception
154
     */
155
    private function getChoicesFromCallable(callable $callable)
156
    {
157
        $choices = $callable();
158
        if (!is_array($choices)) {
159
            throw new \Exception('Choices callback defined in table configurations must return array');
160
        }
161
162
        return $choices;
163
    }
164
}
165