Passed
Push — master ( 429b06...f0c7c5 )
by Rafael
08:46
created

DeferredBuffer::loadBuffer()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 3
eloc 10
nc 3
nop 0
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Resolver;
12
13
use Doctrine\Bundle\DoctrineBundle\Registry;
14
use Doctrine\Common\Util\ClassUtils;
15
use Doctrine\ORM\EntityRepository;
16
use Ynlo\GraphQLBundle\Model\NodeInterface;
17
18
/**
19
 * This buffer is used to solve the N+1 Problem
20
 *
21
 * @see https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/
22
 *
23
 * Create a array of pending relations to load and create a only one
24
 * IN(...) query for all entities of the same type
25
 */
26
class DeferredBuffer
27
{
28
    /**
29
     * @var Registry
30
     */
31
    protected $registry;
32
33
    /**
34
     * @var array[]
35
     */
36
    private static $deferred = [];
37
38
    /**
39
     * @var bool
40
     */
41
    private static $loaded = false;
42
43
    /**
44
     * DeferredBuffer constructor.
45
     *
46
     * @param Registry $registry
47
     */
48
    public function __construct(Registry $registry)
49
    {
50
        $this->registry = $registry;
51
    }
52
53
    /**
54
     * @param NodeInterface $entity
55
     */
56
    public function add(NodeInterface $entity)
57
    {
58
        $class = ClassUtils::getClass($entity);
59
        self::$deferred[$class][$entity->getId()] = $entity->getId();
60
    }
61
62
    /**
63
     * Return the loaded entity for given not initialized entity
64
     *
65
     * @param NodeInterface $entity
66
     *
67
     * @return NodeInterface
68
     */
69
    public function getLoadedEntity(NodeInterface $entity): NodeInterface
70
    {
71
        $class = ClassUtils::getClass($entity);
72
        if (isset(self::$deferred[$class][$entity->getId()]) && self::$deferred[$class][$entity->getId()] instanceof NodeInterface) {
73
            return self::$deferred[$class][$entity->getId()];
74
        }
75
76
        //fallback
77
        return $entity;
78
    }
79
80
    /**
81
     * Load buffer of entities
82
     */
83
    public function loadBuffer()
84
    {
85
        if (self::$loaded) {
86
            return;
87
        }
88
        self::$loaded = true;
89
90
        foreach (self::$deferred as $class => $ids) {
91
            /** @var EntityRepository $repo */
92
            $repo = $this->registry->getRepository($class);
93
            $qb = $repo->createQueryBuilder('o', 'o.id');
94
            $entities = $qb->where($qb->expr()->in('o.id', $ids))
95
                           ->getQuery()
96
                           ->getResult();
97
            self::$deferred[$class] = $entities;
98
        }
99
    }
100
}
101