Passed
Push — master ( 8edad9...f8fafa )
by Fabrice
05:07
created

DbExtractorAbstract::setExtractQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
/*
4
 * This file is part of YaEtl.
5
 *     (c) Fabrice de Stefanis / https://github.com/fab2s/YaEtl
6
 * This source file is licensed under the MIT license which you will
7
 * find in the LICENSE file or at https://opensource.org/licenses/MIT
8
 */
9
10
namespace fab2s\YaEtl\Extractors;
11
12
/**
13
 * abstract Class DbExtractorAbstract
14
 */
15
abstract class DbExtractorAbstract extends ExtractorBatchLimitAbstract
16
{
17
    /**
18
     * @var \SplDoublyLinkedList|array
19
     */
20
    protected $extracted;
21
22
    /**
23
     * query
24
     *
25
     * @var mixed
26
     */
27
    protected $extractQuery;
28
29
    /**
30
     * @param mixed $extractQuery
31
     */
32
    public function __construct($extractQuery = null)
33
    {
34
        if ($extractQuery !== null) {
35
            $this->setExtractQuery($extractQuery);
36
        }
37
    }
38
39
    /**
40
     * @param mixed $param
41
     *
42
     * @return bool
43
     */
44
    public function extract($param = null)
45
    {
46
        if ($this->isLimitReached()) {
47
            return false;
48
        }
49
50
        $this->enforceBatchSize();
51
        if ($this->fetchRecords()) {
52
            $this->incrementOffset();
53
54
            return true;
55
        }
56
57
        return false;
58
    }
59
60
    /**
61
     * @param mixed $extractQuery
62
     *
63
     * @return $this
64
     */
65
    public function setExtractQuery($extractQuery)
66
    {
67
        $this->extractQuery = $extractQuery;
68
69
        return $this;
70
    }
71
72
    /**
73
     * @param mixed $param
74
     *
75
     * @return \Generator
76
     */
77
    public function getTraversable($param = null)
78
    {
79
        /*
80
         * unfortunately, we can't do something a simple as
81
         * while ($this->extracted->valid()) {
82
         *     yield $this->extracted->shift();
83
         * }
84
         *
85
         * @SEE https://php.net/spldoublylinkedlist.shift#120715
86
         *
87
         * Now since using shift() will result in an empty
88
         * SplDoublyLinkedList at the end of the extraction cycle,
89
         * the ETL will end up using less RAM when using multiple froms.
90
         * Otherwise, each extractor would keep its entire last
91
         * extracted collection in RAM until the end of the whole ETL.
92
         *
93
         * Besides, while the bellow code may "look" slower than :
94
         * foreach ($this->extracted as $record) {
95
         *     yield $record;
96
         * }
97
         *
98
         * we can't really say it is.
99
         * I quickly measured the time cost of this do/while vs foreach :
100
         * => 1M records from two extractors (500K each, 50K records per extract)
101
         * ==> php 7.1.2
102
         *      - foreach : 2sec 125ms - Memory: 74.00MiB
103
         *      - do / while : 1sec 922ms - Memory: 42.00MiB
104
         * ==> php 5.6.30
105
         *      - foreach : 2sec 686ms - Memory: 147.75MiB
106
         *      - do / while : 2sec 988ms - Memory: 80.00MiB
107
         *
108
         * still win-win ^^
109
         *
110
         */
111
        while ($this->extract($param)) {
112
            ++$this->numExtract;
113
            do {
114
                $record = $this->extracted->shift();
115
                $this->extracted->rewind();
116
                ++$this->numRecords;
117
                yield $record;
118
            } while ($this->extracted->valid());
119
        }
120
    }
121
122
    /**
123
     * @return string
124
     */
125
    protected function getLimitOffsetBit()
126
    {
127
        return ' ' . \implode('', [
128
            ' LIMIT ' . (int) $this->batchSize,
129
            $this->offset ? ' OFFSET ' . (int) $this->offset : '',
130
        ]);
131
    }
132
133
    /**
134
     * execute query and store results in $this->extracted
135
     *
136
     * @return bool true if there are records fetched
137
     */
138
    abstract protected function fetchRecords();
139
}
140