Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.75% covered (success)
93.75%
15 / 16
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
sql_insert_buffer
93.75% covered (success)
93.75%
15 / 16
75.00% covered (warning)
75.00%
3 / 4
8.02
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 insert
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
 insert_all
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 flush
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb\db;
15
16/**
17* Collects rows for insert into a database until the buffer size is reached.
18* Then flushes the buffer to the database and starts over again.
19*
20* Benefits over collecting a (possibly huge) insert array and then using
21* $db->sql_multi_insert() include:
22*
23*  - Going over max packet size of the database connection is usually prevented
24*    because the data is submitted in batches.
25*
26*  - Reaching database connection timeout is usually prevented because
27*    submission of batches talks to the database every now and then.
28*
29*  - Usage of less PHP memory because data no longer needed is discarded on
30*    buffer flush.
31*
32* Attention:
33* Please note that users of this class have to call flush() to flush the
34* remaining rows to the database after their batch insert operation is
35* finished.
36*
37* Usage:
38* <code>
39*    $buffer = new \phpbb\db\sql_insert_buffer($db, 'test_table', 1234);
40*
41*    while (do_stuff())
42*    {
43*        $buffer->insert(array(
44*            'column1' => 'value1',
45*            'column2' => 'value2',
46*        ));
47*    }
48*
49*    $buffer->flush();
50* </code>
51*/
52class sql_insert_buffer
53{
54    /** @var \phpbb\db\driver\driver_interface */
55    protected $db;
56
57    /** @var string */
58    protected $table_name;
59
60    /** @var int */
61    protected $max_buffered_rows;
62
63    /** @var array */
64    protected $buffer = array();
65
66    /**
67    * @param \phpbb\db\driver\driver_interface $db
68    * @param string          $table_name
69    * @param int             $max_buffered_rows
70    */
71    public function __construct(\phpbb\db\driver\driver_interface $db, $table_name, $max_buffered_rows = 500)
72    {
73        $this->db = $db;
74        $this->table_name = $table_name;
75        $this->max_buffered_rows = $max_buffered_rows;
76    }
77
78    /**
79    * Inserts a single row into the buffer if multi insert is supported by the
80    * database (otherwise an insert query is sent immediately). Then flushes
81    * the buffer if the number of rows in the buffer is now greater than or
82    * equal to $max_buffered_rows.
83    *
84    * @param array $row
85    *
86    * @return bool        True when some data was flushed to the database.
87    *                    False otherwise.
88    */
89    public function insert(array $row)
90    {
91        $this->buffer[] = $row;
92
93        // Flush buffer if it is full or when DB does not support multi inserts.
94        // In the later case, the buffer will always only contain one row.
95        if (!$this->db->get_multi_insert() || count($this->buffer) >= $this->max_buffered_rows)
96        {
97            return $this->flush();
98        }
99
100        return false;
101    }
102
103    /**
104    * Inserts a row set, i.e. an array of rows, by calling insert().
105    *
106    * Please note that it is in most cases better to use insert() instead of
107    * first building a huge rowset. Or at least count($rows) should be kept
108    * small.
109    *
110    * @param array $rows
111    *
112    * @return bool        True when some data was flushed to the database.
113    *                    False otherwise.
114    */
115    public function insert_all(array $rows)
116    {
117        // Using bitwise |= because PHP does not have logical ||=
118        $result = 0;
119
120        foreach ($rows as $row)
121        {
122            $result |= (int) $this->insert($row);
123        }
124
125        return (bool) $result;
126    }
127
128    /**
129    * Flushes the buffer content to the DB and clears the buffer.
130    *
131    * @return bool        True when some data was flushed to the database.
132    *                    False otherwise.
133    */
134    public function flush()
135    {
136        if (!empty($this->buffer))
137        {
138            $this->db->sql_multi_insert($this->table_name, $this->buffer);
139            $this->buffer = array();
140
141            return true;
142        }
143
144        return false;
145    }
146}