GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( bd6a42...4aeb5a )
by Christian
04:12
created

src/EventListener/ORM/SortableListener.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * (c) Christian Gripp <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Core23\DoctrineExtensions\EventListener\ORM;
13
14
use Core23\DoctrineExtensions\Model\PositionAwareInterface;
15
use Core23\DoctrineExtensions\Model\Traits\SortableTrait;
16
use Doctrine\ORM\EntityManager;
17
use Doctrine\ORM\Event\LifecycleEventArgs;
18
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
19
use Doctrine\ORM\Event\PreUpdateEventArgs;
20
use Doctrine\ORM\Events;
21
use Doctrine\ORM\Mapping\ClassMetadata;
22
use Doctrine\ORM\Mapping\MappingException;
23
use Doctrine\ORM\NonUniqueResultException;
24
use Symfony\Component\PropertyAccess\PropertyAccess;
25
26
final class SortableListener extends AbstractListener
27
{
28
    /**
29
     * {@inheritdoc}
30
     */
31
    public function getSubscribedEvents()
32
    {
33
        return [
34
            Events::prePersist,
35
            Events::preUpdate,
36
            Events::preRemove,
37
            Events::loadClassMetadata,
38
        ];
39
    }
40
41
    /**
42
     * @param LifecycleEventArgs $args
43
     */
44
    public function prePersist(LifecycleEventArgs $args): void
45
    {
46
        if ($args->getEntity() instanceof PositionAwareInterface) {
47
            $this->uniquePosition($args);
48
        }
49
    }
50
51
    /**
52
     * @param PreUpdateEventArgs $args
53
     */
54
    public function preUpdate(PreUpdateEventArgs $args): void
55
    {
56
        if ($args->getEntity() instanceof PositionAwareInterface) {
57
            $position = $args->getEntity()->getPosition();
58
59
            if ($args->hasChangedField('position')) {
60
                $position = $args->getOldValue('position');
61
            }
62
63
            $this->uniquePosition($args, $position);
64
        }
65
    }
66
67
    /**
68
     * @param LifecycleEventArgs $args
69
     */
70
    public function preRemove(LifecycleEventArgs $args): void
71
    {
72
        $entity = $args->getEntity();
73
74
        if ($entity instanceof PositionAwareInterface) {
75
            $this->movePosition($args->getEntityManager(), $entity, -1);
76
        }
77
    }
78
79
    /**
80
     * @param LoadClassMetadataEventArgs $eventArgs
81
     *
82
     * @throws MappingException
83
     */
84
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void
85
    {
86
        $meta = $eventArgs->getClassMetadata();
87
88
        if (!$meta instanceof ClassMetadata) {
89
            throw new \LogicException(sprintf('Class metadata was no ORM but %s', get_class($meta)));
90
        }
91
92
        if (!$this->containsTrait($meta->getReflectionClass(), SortableTrait::class)) {
93
            return;
94
        }
95
96
        if (!$meta->hasField('position')) {
97
            $meta->mapField([
98
                'type'      => 'integer',
99
                'fieldName' => 'position',
100
            ]);
101
        }
102
    }
103
104
    /**
105
     * @param LifecycleEventArgs $args
106
     * @param int|null           $oldPosition
107
     */
108
    private function uniquePosition(LifecycleEventArgs $args, ?int $oldPosition = null): void
109
    {
110
        $entity = $args->getEntity();
111
112
        if ($entity instanceof PositionAwareInterface) {
113
            if (null === $entity->getPosition()) {
114
                $position = $this->getNextPosition($args->getEntityManager(), $entity);
115
                $entity->setPosition($position);
116
            } elseif ($oldPosition && $oldPosition !== $entity->getPosition()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $oldPosition of type null|integer is loosely compared to true; this is ambiguous if the integer can be 0. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
117
                $this->movePosition($args->getEntityManager(), $entity);
118
            }
119
        }
120
    }
121
122
    /**
123
     * @param EntityManager          $em
124
     * @param PositionAwareInterface $entity
125
     * @param int                    $direction
126
     */
127
    private function movePosition(EntityManager $em, PositionAwareInterface $entity, int $direction = 1): void
128
    {
129
        $uow  = $em->getUnitOfWork();
130
        $meta = $em->getClassMetadata(get_class($entity));
131
132
        $qb = $em->createQueryBuilder()
133
            ->update($meta->getName(), 'e')
134
            ->set('e.position', 'e.position + '.$direction);
135
136
        if ($direction > 0) {
137
            $qb->andWhere('e.position <= :position')->setParameter('position', $entity->getPosition());
138
        } elseif ($direction < 0) {
139
            $qb->andWhere('e.position >= :position')->setParameter('position', $entity->getPosition());
140
        } else {
141
            return;
142
        }
143
144
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
145
146
        foreach ($entity->getPositionGroup() as $field) {
147
            $value = $propertyAccessor->getValue($entity, $field);
148
149
            if (is_object($value) && null === $uow->getSingleIdentifierValue($value)) {
150
                continue;
151
            }
152
153
            $qb->andWhere('e.'.$field.' = :'.$field)->setParameter($field, $value);
154
        }
155
156
        $qb->getQuery()->execute();
157
    }
158
159
    /**
160
     * @param EntityManager          $em
161
     * @param PositionAwareInterface $entity
162
     *
163
     * @return int
164
     */
165
    private function getNextPosition(EntityManager $em, PositionAwareInterface $entity): int
166
    {
167
        $meta = $em->getClassMetadata(get_class($entity));
168
169
        $qb = $em->createQueryBuilder()
170
            ->select('e')
171
            ->from($meta->getName(), 'e')
172
            ->addOrderBy('e.position', 'DESC')
173
            ->setMaxResults(1);
174
175
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
176
177
        foreach ($entity->getPositionGroup() as $field) {
178
            $value = $propertyAccessor->getValue($entity, $field);
179
            $qb->andWhere('e.'.$field.' = :'.$field)->setParameter($field, $value);
180
        }
181
182
        /* @var PositionAwareInterface $result */
183
        try {
184
            $result = $qb->getQuery()->getOneOrNullResult();
185
186
            return ($result ? $result->getPosition() : 0) + 1;
187
        } catch (NonUniqueResultException $ignored) {
188
            return 0;
189
        }
190
    }
191
}
192