TransactionalCrudRepository   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 71.23%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 2
dl 0
loc 197
ccs 52
cts 73
cp 0.7123
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 2
A find() 0 8 1
A findAll() 0 8 1
A findBy() 0 8 1
A findOneBy() 0 8 1
A persist() 0 11 1
A merge() 0 9 1
A remove() 0 9 1
A removeById() 0 11 2
A count() 0 8 1
A matching() 0 8 1
A removeAll() 0 9 1
A findPaginatedBy() 0 12 1
A countAll() 0 8 1
A getTransactionManager() 0 4 1
A setTransactionManager() 0 4 1
1
<?php
2
3
namespace Dontdrinkandroot\Repository;
4
5
use Doctrine\Common\Collections\Criteria;
6
use Doctrine\ORM\EntityManagerInterface;
7
use Doctrine\ORM\Mapping;
8
use Doctrine\ORM\Tools\Pagination\Paginator;
9
10
/**
11
 * @author Philip Washington Sorst <[email protected]>
12
 */
13
class TransactionalCrudRepository extends CrudRepository
0 ignored issues
show
Bug introduced by
There is one abstract method getClassName in this class; you could implement it, or declare this class as abstract.
Loading history...
14
{
15
    /** @var TransactionManager */
16
    private $transactionManager;
17
18 16
    public function __construct(
19
        EntityManagerInterface $em,
20
        Mapping\ClassMetadata $class,
21
        ?TransactionManager $transactionManager = null
22
    ) {
23 16
        parent::__construct($em, $class);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Dontdrinkandroot\Repository\CrudRepository as the method __construct() does only exist in the following sub-classes of Dontdrinkandroot\Repository\CrudRepository: Dontdrinkandroot\Reposit...sactionalCrudRepository, Dontdrinkandroot\Reposit...ionalUuidCrudRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
24 16
        if (null === $transactionManager) {
25 16
            $this->transactionManager = new TransactionManager($this->getEntityManager());
0 ignored issues
show
Bug introduced by
The method getEntityManager() does not seem to exist on object<Dontdrinkandroot\...actionalCrudRepository>.

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...
26
        } else {
27
            $this->transactionManager = $transactionManager;
28
        }
29 16
    }
30
31
    /**
32
     * {@inheritdoc}
33
     */
34 2
    public function find($id, $lockMode = null, $lockVersion = null)
35
    {
36 2
        return $this->transactionManager->transactional(
37
            function () use ($id, $lockMode, $lockVersion) {
38 2
                return parent::find($id, $lockMode = null, $lockVersion = null);
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $lockMode, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
Bug introduced by
Consider using a different name than the imported variable $lockVersion, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
Unused Code introduced by
The call to CrudRepository::find() has too many arguments starting with $lockMode = null.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
39 2
            }
40
        );
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46 2
    public function findAll()
47
    {
48 2
        return $this->transactionManager->transactional(
49
            function () {
50 2
                return parent::findAll();
51 2
            }
52
        );
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58 2
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null)
59
    {
60 2
        return $this->transactionManager->transactional(
61
            function () use ($criteria, $orderBy, $limit, $offset) {
62 2
                return parent::findBy($criteria, $orderBy, $limit, $offset);
63 2
            }
64
        );
65
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function findOneBy(array $criteria, array $orderBy = null)
71
    {
72
        return $this->transactionManager->transactional(
73
            function () use ($criteria, $orderBy) {
74
                return parent::findOneBy($criteria, $orderBy);
0 ignored issues
show
Unused Code introduced by
The call to CrudRepository::findOneBy() has too many arguments starting with $orderBy.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
75
            }
76
        );
77
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82 2
    public function persist(object $entity, bool $flush = true): object
83
    {
84 2
        return $this->transactionManager->transactional(
85
            function () use ($entity) {
86 2
                $this->getEntityManager()->persist($entity);
0 ignored issues
show
Bug introduced by
The method getEntityManager() does not seem to exist on object<Dontdrinkandroot\...actionalCrudRepository>.

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...
87
88 2
                return $entity;
89 2
            },
90 2
            $flush
91
        );
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function merge(object $entity, $flush = false): object
98
    {
99
        return $this->transactionManager->transactional(
100
            function () use ($entity) {
101
                $this->getEntityManager()->merge($entity);
0 ignored issues
show
Bug introduced by
The method getEntityManager() does not seem to exist on object<Dontdrinkandroot\...actionalCrudRepository>.

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...
102
            },
103
            $flush
104
        );
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 6
    public function remove(object $entity, bool $flush = false): void
111
    {
112 6
        $this->transactionManager->transactional(
113
            function () use ($entity): void {
114 6
                $this->getEntityManager()->remove($entity);
0 ignored issues
show
Bug introduced by
The method getEntityManager() does not seem to exist on object<Dontdrinkandroot\...actionalCrudRepository>.

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...
115 6
            },
116 6
            $flush
117
        );
118 6
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 2
    public function removeById($id, bool $flush = false): void
124
    {
125 2
        $this->transactionManager->transactional(
126
            function () use ($id, $flush): void {
127 2
                $entity = $this->find($id);
128 2
                if (null !== $entity) {
129 2
                    $this->remove($entity, $flush);
130
                }
131 2
            }
132
        );
133 2
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function count(array $criteria)
139
    {
140
        return $this->transactionManager->transactional(
141
            function () use ($criteria) {
142
                return parent::count($criteria);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Dontdrinkandroot\Repository\CrudRepository as the method count() does only exist in the following sub-classes of Dontdrinkandroot\Repository\CrudRepository: Dontdrinkandroot\Reposit...sactionalCrudRepository, Dontdrinkandroot\Reposit...ionalUuidCrudRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
143
            }
144
        );
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150
    public function matching(Criteria $criteria)
151
    {
152
        return $this->transactionManager->transactional(
153
            function () use ($criteria) {
154
                return parent::matching($criteria);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Dontdrinkandroot\Repository\CrudRepository as the method matching() does only exist in the following sub-classes of Dontdrinkandroot\Repository\CrudRepository: Dontdrinkandroot\Reposit...sactionalCrudRepository, Dontdrinkandroot\Reposit...ionalUuidCrudRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
155
            }
156
        );
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 4
    public function removeAll(bool $flush = false, bool $iterate = true): void
163
    {
164 4
        $this->transactionManager->transactional(
165
            function () use ($iterate): void {
166 4
                parent::removeAll(false, $iterate);
167 4
            },
168 4
            $flush
169
        );
170 4
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 2
    public function findPaginatedBy(
176
        int $page = 1,
177
        int $perPage = 10,
178
        array $criteria = [],
179
        array $orderBy = null
180
    ): Paginator {
181 2
        return $this->transactionManager->transactional(
182
            function () use ($page, $perPage, $criteria, $orderBy): Paginator {
183 2
                return parent::findPaginatedBy($page, $perPage, $criteria, $orderBy);
184 2
            }
185
        );
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191 6
    public function countAll(): int
192
    {
193 6
        return $this->transactionManager->transactional(
194
            function (): int {
195 6
                return parent::countAll();
196 6
            }
197
        );
198
    }
199
200 6
    public function getTransactionManager(): TransactionManager
201
    {
202 6
        return $this->transactionManager;
203
    }
204
205
    public function setTransactionManager(TransactionManager $transactionManager): void
206
    {
207
        $this->transactionManager = $transactionManager;
208
    }
209
}
210