Completed
Pull Request — master (#4)
by
unknown
02:24
created

ChoicesBuilder::build()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 17
rs 8.8571
cc 5
eloc 10
nc 4
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 (
32
            is_array($choicesConfiguration) &&
33
            isset($choicesConfiguration['repository'])
34
        ) {
35
            return $this->getChoicesFromRepository($choicesConfiguration);
36
        }
37
        if (is_callable($choicesConfiguration)) {
38
            return $this->getChoicesFromCallable($choicesConfiguration);
39
        }
40
        if (is_array($choicesConfiguration)) {
41
            return $choicesConfiguration;
42
        }
43
44
        throw new \Exception('No usable configuration was found');
45
    }
46
47
    /**
48
     * @param array $choicesConfiguration
49
     *
50
     * @return array
51
     *
52
     * @throws \Exception
53
     */
54
    private function getChoicesFromRepository(array $choicesConfiguration)
55
    {
56
        if ($choicesConfiguration['repository'] instanceof EntityRepository) {
57
            $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...
58
        } else {
59
            $repository = $this->entityManager->getRepository($choicesConfiguration['repository']);
60
        }
61
62
        if (isset($choicesConfiguration['field'])) {
63
            return $this->getChoicesFromRepositoryForField(
64
                $repository,
65
                $choicesConfiguration['field'],
66
                isset($choicesConfiguration['sort']) ? $choicesConfiguration['sort'] : null
67
            );
68
        }
69
        if (isset($choicesConfiguration['method'])) {
70
            return $this->getChoicesFromRepositoryWithMethod(
71
                $repository,
72
                $choicesConfiguration['method']
73
            );
74
        }
75
76
        throw new \Exception('Repository source expects field or method parameter');
77
    }
78
79
    /**
80
     * @deprecated Specifying repository as an object is deprecated and will not be supported since 1.0.0. Specify it by it's name instead.
81
     *
82
     * @param EntityRepository $repository
83
     *
84
     * @return EntityRepository
85
     */
86
    private function getSpecifiedRepository(EntityRepository $repository)
87
    {
88
        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);
89
90
        return $repository;
91
    }
92
93
    /**
94
     * Get all values available for this data field for consumption by
95
     * the front-end in order to enable advanced UX functionality.
96
     *
97
     * @param EntityRepository $repository
98
     * @param string           $property
99
     * @param null|string      $sortOrder
100
     *
101
     * @return array
102
     */
103
    private function getChoicesFromRepositoryForField(EntityRepository $repository, $property, $sortOrder = null)
104
    {
105
        $queryBuilder = $repository->createQueryBuilder('entity')
106
            ->select('entity.' . $property);
107
108
        if (!is_null($sortOrder)) {
109
            $queryBuilder->orderBy('entity.' . $property, $sortOrder);
110
        }
111
112
        $results = $queryBuilder
113
            ->getQuery()
114
            ->getArrayResult();
115
        $choices = [];
116
        foreach ($results as $value) {
117
            $choices[$value[$property]] = $value[$property];
118
        }
119
120
        return $choices;
121
    }
122
123
    /**
124
     * @param EntityRepository $repository
125
     * @param string           $method
126
     *
127
     * @return array
128
     *
129
     * @throws \Exception
130
     */
131
    private function getChoicesFromRepositoryWithMethod(EntityRepository $repository, $method)
132
    {
133
        if (!method_exists($repository, $method)) {
134
            throw new \Exception("Specified repository does not have '$method' method");
135
        }
136
137
        $choices = $repository->$method();
138
        if (!is_array($choices)) {
139
            throw new \Exception('Choices repository method defined in table configurations must return array');
140
        }
141
142
        return $choices;
143
    }
144
145
    /**
146
     * @param callable $callable
147
     *
148
     * @return array
149
     *
150
     * @throws \Exception
151
     */
152
    private function getChoicesFromCallable(callable $callable)
153
    {
154
        $choices = $callable();
155
        if (!is_array($choices)) {
156
            throw new \Exception('Choices callback defined in table configurations must return array');
157
        }
158
159
        return $choices;
160
    }
161
}
162