Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * This file contains the class XML_Query2XML_Driver_DB.
4
 *
5
 * PHP version 5
6
 *
7
 * @category  XML
8
 * @package   XML_Query2XML
9
 * @author    Lukas Feiler <lukas.feiler@lukasfeiler.com>
10
 * @copyright 2006 Lukas Feiler
11
 * @license   http://www.gnu.org/copyleft/lesser.html  LGPL Version 2.1
12
 * @version   CVS: $Id: DB.php 276639 2009-03-01 13:17:08Z lukasfeiler $
13
 * @link      http://pear.php.net/package/XML_Query2XML
14
 */
15
 
16
/**
17
 * XML_Query2XML_Driver_DB extends XML_Query2XML_Driver.
18
 */
19
require_once 'XML/Query2XML.php';
20
 
21
/**
22
 * As the method PEAR::isError() is used within XML_Query2XML_Driver_DB
23
 * we require PEAR.php.
24
 */
25
require_once 'PEAR.php';
26
 
27
/**
28
 * Driver for the database abstraction layer PEAR DB.
29
 *
30
 * usage:
31
 * <code>
32
 * $driver = XML_Query2XML_Driver::factory(DB::connect(...));
33
 * </code>
34
 *
35
 * @category  XML
36
 * @package   XML_Query2XML
37
 * @author    Lukas Feiler <lukas.feiler@lukasfeiler.com>
38
 * @copyright 2006 Lukas Feiler
39
 * @license   http://www.gnu.org/copyleft/lesser.html  LGPL Version 2.1
40
 * @version   Release: 1.7.2
41
 * @link      http://pear.php.net/package/XML_Query2XML
42
 * @since     Release 1.5.0RC1
43
 */
44
class XML_Query2XML_Driver_DB extends XML_Query2XML_Driver
45
{
46
    /**
47
     * In instance of a class that extends DB_common.
48
     * @var DB_common
49
     */
50
    private $_db = null;
51
 
52
    /**
53
     * Constructor
54
     *
55
     * @param DB_Common $db An instance of a class that extends DB_Common.
56
     *
57
     * @throws XML_Query2XML_DBException If the fetch mode cannot be set to
58
     *                               DB_FETCHMODE_ASSOC.
59
     */
60
    public function __construct(DB_common $db)
61
    {
62
        $fetchModeError = $db->setFetchMode(DB_FETCHMODE_ASSOC);
63
        if (PEAR::isError($fetchModeError)) {
64
            // no unit tests for this one
65
            throw new XML_Query2XML_DBException(
66
                'Could not set fetch mode to DB_FETCHMODE_ASSOC: '
67
                . $fetchModeError->toString()
68
            );
69
        }
70
        $this->_db = $db;
71
    }
72
 
73
    /**
74
     * Pre-processes a query specification and returns a string representation
75
     * of the query.
76
     * This method will call parent::preprocessQuery(). Additionally it will
77
     * verify $query['limit'] and $query['offset'].
78
     *
79
     * @param mixed  &$query     A string or an array containing the element 'query'.
80
     * @param string $configPath The config path; used for exception messages.
81
     *
82
     * @return string The query statement as a string.
83
     * @throws XML_Query2XML_ConfigException If $query['limit'] or $query['offset']
84
     *                                       is set but not numeric. This exception
85
     *                                       might also bubble up from
86
     *                                       parent::preprocessQuery().
87
     */
88
    public function preprocessQuery(&$query, $configPath)
89
    {
90
        /*
91
         * This will make $query an array if it is not already.
92
         * We'll ignore preprocessQuery()'s return value here.
93
         */
94
        parent::preprocessQuery($query, $configPath);
95
 
96
        foreach (array('limit', 'offset') as $sqlOption) {
97
            if (isset($query[$sqlOption])) {
98
                if (!is_numeric($query[$sqlOption])) {
99
                    /*
100
                     * unit test: getXML/
101
                     *  offsetlimit_throwConfigException_limit_not_numeric.phpt
102
                     *  offsetlimit_throwConfigException_offset_not_numeric.phpt
103
                     */
104
                    throw new XML_Query2XML_ConfigException(
105
                        $configPath . '[' . $sqlOption
106
                        . ']: integer expected, '
107
                        . gettype($query[$sqlOption]) . ' given.'
108
                    );
109
                }
110
            }
111
        }
112
        $queryString = $query['query'];
113
        if (isset($query['limit'])) {
114
            if ($query['limit'] == 0) {
115
                // setting limit to 0 is like not setting it at all
116
                unset($query['limit']);
117
            } else {
118
                if (!isset($query['offset'])) {
119
                    // offset defaults to 0
120
                    $query['offset'] = 0;
121
                }
122
                $queryString .= '; LIMIT:' . $query['limit'];
123
                $queryString .= '; OFFSET:' . $query['offset'];
124
 
125
                $query['query'] = $this->_db->modifyLimitQuery(
126
                    $query['query'],
127
                    $query['offset'],
128
                    $query['limit']
129
                );
130
            }
131
        }
132
        return $queryString;
133
    }
134
 
135
    /**
136
     * Execute a SQL SELECT stement and fetch all records from the result set.
137
     *
138
     * @param mixed  $sql        The SQL query as an array containing the
139
     *                           element 'query'.
140
     * @param string $configPath The config path; used for exception messages.
141
     *
142
     * @return array An array of records.
143
     * @throws XML_Query2XML_DBException If a database related error occures.
144
     * @see XML_Query2XML_Driver::getAllRecords()
145
     */
146
    public function getAllRecords($sql, $configPath)
147
    {
148
        if (isset($sql['limit']) && $sql['limit'] < 0) {
149
            return array();
150
        }
151
        $result  =& $this->_prepareAndExecute($sql, $configPath);
152
        $records = array();
153
        while ($record = $result->fetchRow()) {
154
            if (PEAR::isError($record)) {
155
                // no unit test for this exception as it cannot be produced easily
156
                throw new XML_Query2XML_DBException(
157
                    $configPath . ': Could not fetch rows for the following '
158
                    . 'SQL query: ' . $sql['query'] . '; '
159
                    . $record->toString()
160
                );
161
            }
162
            $records[] = $record;
163
        }
164
        $result->free();
165
        return $records;
166
    }
167
 
168
    /**
169
     * Private method that will use DB_Common::prepare() & DB_Common::execute()
170
     * to run an SQL query.
171
     *
172
     * @param mixed  $sql        An associative array with a 'query' element.
173
     * @param string $configPath The config path used for exception messages.
174
     *
175
     * @return DB_result
176
     * @throws XML_Query2XML_DBException If a database related error occures.
177
     */
178
    private function _prepareAndExecute($sql, $configPath)
179
    {
180
        $query = $sql['query'];
181
 
182
        if (isset($this->_preparedQueries[$query])) {
183
            $queryHandle = $this->_preparedQueries[$query];
184
        } else {
185
            // PREPARE
186
            $queryHandle = $this->_db->prepare($query);
187
 
188
            if (PEAR::isError($queryHandle)) {
189
                /*
190
                 * No unit test for this exception as DB's mysql and pgsql
191
                 * drivers never return a PEAR error from prepare().
192
                 */
193
                throw new XML_Query2XML_DBException(
194
                    $configPath . ': Could not prepare the following SQL query: '
195
                    . $query . '; ' . $queryHandle->toString()
196
                );
197
            }
198
 
199
            $this->_preparedQueries[$query] =& $queryHandle;
200
        }
201
 
202
        // EXECUTE
203
        if (isset($sql['data'])) {
204
            $result = $this->_db->execute($queryHandle, $sql['data']);
205
        } else {
206
            $result = $this->_db->execute($queryHandle);
207
        }
208
 
209
        if (PEAR::isError($result)) {
210
            /*
211
             * unit test: DB/_prepareAndExecute/
212
             *  throwDBException_complexQuery.phpt
213
             */
214
            throw new XML_Query2XML_DBException(
215
                $configPath . ': Could not execute the following SQL query: '
216
                . $query . '; ' . $result->toString()
217
            );
218
        }
219
        if (!($result instanceof DB_result)) {
220
            /*
221
             * unit tests: DB/getXML/
222
             *  throwDBException_nullResultSet_complexQuery_multipleRecords.phpt
223
             *  throwDBException_nullResultSet_complexQuery_singleRecord.phpt
224
             */
225
            throw new XML_Query2XML_DBException(
226
                $configPath . ': the following SQL query returned no '
227
                . 'result set: ' . $query
228
            );
229
        }
230
        return $result;
231
    }
232
}
233
?>