source: branches/1.2/workflow/inc/log/Log/mdb2.php @ 1349

Revision 1349, 10.6 KB checked in by niltonneto, 15 years ago (diff)

Ticket #561 - Inclusão do módulo Workflow faltante nessa versão.

  • Property svn:executable set to *
Line 
1<?php
2/**
3 * $Header: /repository/pear/Log/Log/mdb2.php,v 1.5 2006/01/08 03:35:44 jon Exp $
4 *
5 * @version $Revision: 1.5 $
6 * @package Log
7 */
8
9/** PEAR's MDB2 package */
10require_once 'MDB2.php';
11MDB2::loadFile('Date');
12
13/**
14 * The Log_mdb2 class is a concrete implementation of the Log:: abstract class
15 * which sends messages to an SQL server.  Each entry occupies a separate row
16 * in the database.
17 *
18 * This implementation uses PEAR's MDB2 database abstraction layer.
19 *
20 * CREATE TABLE log_table (
21 *  id          INT NOT NULL,
22 *  logtime     TIMESTAMP NOT NULL,
23 *  ident       CHAR(16) NOT NULL,
24 *  priority    INT NOT NULL,
25 *  message     VARCHAR(200),
26 *  PRIMARY KEY (id)
27 * );
28 *
29 * @author  Lukas Smith <smith@backendmedia.com>
30 * @author  Jon Parise <jon@php.net>
31 * @since   Log 1.9.0
32 * @package Log
33 */
34class Log_mdb2 extends Log
35{
36    /**
37     * Variable containing the DSN information.
38     * @var mixed
39     * @access private
40     */
41    var $_dsn = '';
42
43    /**
44     * Array containing our set of DB configuration options.
45     * @var array
46     * @access private
47     */
48    var $_options = array('persistent' => true);
49
50    /**
51     * Object holding the database handle.
52     * @var object
53     * @access private
54     */
55    var $_db = null;
56
57    /**
58     * Resource holding the prepared statement handle.
59     * @var resource
60     * @access private
61     */
62    var $_statement = null;
63
64    /**
65     * Flag indicating that we're using an existing database connection.
66     * @var boolean
67     * @access private
68     */
69    var $_existingConnection = false;
70
71    /**
72     * String holding the database table to use.
73     * @var string
74     * @access private
75     */
76    var $_table = 'log_table';
77
78    /**
79     * String holding the name of the ID sequence.
80     * @var string
81     * @access private
82     */
83    var $_sequence = 'log_id';
84
85    /**
86     * Maximum length of the $ident string.  This corresponds to the size of
87     * the 'ident' column in the SQL table.
88     * @var integer
89     * @access private
90     */
91    var $_identLimit = 16;
92
93    /**
94     * Set of field types used in the database table.
95     * @var array
96     * @access private
97     */
98    var $_types = array(
99        'id'        => 'integer',
100        'logtime'   => 'timestamp',
101        'ident'     => 'text',
102        'priority'  => 'text',
103        'message'   => 'clob'
104    );
105
106    /**
107     * Constructs a new sql logging object.
108     *
109     * @param string $name         The target SQL table.
110     * @param string $ident        The identification field.
111     * @param array $conf          The connection configuration array.
112     * @param int $level           Log messages up to and including this level.
113     * @access public
114     */
115    function Log_mdb2($name, $ident = '', $conf = array(),
116                     $level = PEAR_LOG_DEBUG)
117    {
118        $this->_id = md5(microtime());
119        $this->_table = $name;
120        $this->_mask = Log::UPTO($level);
121
122        /* If an options array was provided, use it. */
123        if (isset($conf['options']) && is_array($conf['options'])) {
124            $this->_options = $conf['options'];
125        }
126
127        /* If a specific sequence name was provided, use it. */
128        if (!empty($conf['sequence'])) {
129            $this->_sequence = $conf['sequence'];
130        }
131
132        /* If a specific sequence name was provided, use it. */
133        if (isset($conf['identLimit'])) {
134            $this->_identLimit = $conf['identLimit'];
135        }
136
137        /* Now that the ident limit is confirmed, set the ident string. */
138        $this->setIdent($ident);
139
140        /* If an existing database connection was provided, use it. */
141        if (isset($conf['db'])) {
142            $this->_db = &$conf['db'];
143            $this->_existingConnection = true;
144            $this->_opened = true;
145        } elseif (isset($conf['singleton'])) {
146            $this->_db = &MDB2::singleton($conf['singleton'], $this->_options);
147            $this->_existingConnection = true;
148            $this->_opened = true;
149        } else {
150            $this->_dsn = $conf['dsn'];
151        }
152    }
153
154    /**
155     * Opens a connection to the database, if it has not already
156     * been opened. This is implicitly called by log(), if necessary.
157     *
158     * @return boolean   True on success, false on failure.
159     * @access public
160     */
161    function open()
162    {
163        if (!$this->_opened) {
164            /* Use the DSN and options to create a database connection. */
165            $this->_db = &MDB2::connect($this->_dsn, $this->_options);
166            if (PEAR::isError($this->_db)) {
167                return false;
168            }
169
170            /* Create a prepared statement for repeated use in log(). */
171            if (!$this->_prepareStatement()) {
172                return false;
173            }
174
175            /* We now consider out connection open. */
176            $this->_opened = true;
177        }
178
179        return $this->_opened;
180    }
181
182    /**
183     * Closes the connection to the database if it is still open and we were
184     * the ones that opened it.  It is the caller's responsible to close an
185     * existing connection that was passed to us via $conf['db'].
186     *
187     * @return boolean   True on success, false on failure.
188     * @access public
189     */
190    function close()
191    {
192        /* If we have a statement object, free it. */
193        if (is_object($this->_statement)) {
194            $this->_statement->free();
195            $this->_statement = null;
196        }
197
198        /* If we opened the database connection, disconnect it. */
199        if ($this->_opened && !$this->_existingConnection) {
200            $this->_opened = false;
201            return $this->_db->disconnect();
202        }
203
204        return ($this->_opened === false);
205    }
206
207    /**
208     * Sets this Log instance's identification string.  Note that this
209     * SQL-specific implementation will limit the length of the $ident string
210     * to sixteen (16) characters.
211     *
212     * @param string    $ident      The new identification string.
213     *
214     * @access  public
215     * @since   Log 1.8.5
216     */
217    function setIdent($ident)
218    {
219        $this->_ident = substr($ident, 0, $this->_identLimit);
220    }
221
222    /**
223     * Inserts $message to the currently open database.  Calls open(),
224     * if necessary.  Also passes the message along to any Log_observer
225     * instances that are observing this Log.
226     *
227     * @param mixed  $message  String or object containing the message to log.
228     * @param string $priority The priority of the message.  Valid
229     *                  values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
230     *                  PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
231     *                  PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
232     * @return boolean  True on success or false on failure.
233     * @access public
234     */
235    function log($message, $priority = null)
236    {
237        /* If a priority hasn't been specified, use the default value. */
238        if ($priority === null) {
239            $priority = $this->_priority;
240        }
241
242        /* Abort early if the priority is above the maximum logging level. */
243        if (!$this->_isMasked($priority)) {
244            return false;
245        }
246
247        /* If the connection isn't open and can't be opened, return failure. */
248        if (!$this->_opened && !$this->open()) {
249            return false;
250        }
251
252        /* If we don't already have a statement object, create one. */
253        if (!is_object($this->_statement) && !$this->_prepareStatement()) {
254            return false;
255        }
256
257        /* Extract the string representation of the message. */
258        $message = $this->_extractMessage($message);
259
260        /* Build our set of values for this log entry. */
261        $values = array(
262            'id'       => $this->_db->nextId($this->_sequence),
263            'logtime'  => MDB2_Date::mdbNow(),
264            'ident'    => $this->_ident,
265            'priority' => $priority,
266            'message'  => $message
267        );
268
269        /* Execute the SQL query for this log entry insertion. */
270        $this->_db->expectError(MDB2_ERROR_NOSUCHTABLE);
271        $result = &$this->_statement->execute($values);
272        $this->_db->popExpect();
273
274        /* Attempt to handle any errors. */
275        if (PEAR::isError($result)) {
276            /* We can only handle MDB2_ERROR_NOSUCHTABLE errors. */
277            if ($result->getCode() != MDB2_ERROR_NOSUCHTABLE) {
278                return false;
279            }
280
281            /* Attempt to create the target table. */
282            if (!$this->_createTable()) {
283                return false;
284            }
285
286            /* Recreate our prepared statement resource. */
287            $this->_statement->free();
288            if (!$this->_prepareStatement()) {
289                return false;
290            }
291
292            /* Attempt to re-execute the insertion query. */
293            $result = $this->_statement->execute($values);
294            if (PEAR::isError($result)) {
295                return false;
296            }
297        }
298
299        $this->_announce(array('priority' => $priority, 'message' => $message));
300
301        return true;
302    }
303
304    /**
305     * Create the log table in the database.
306     *
307     * @return boolean  True on success or false on failure.
308     * @access private
309     */
310    function _createTable()
311    {
312        $this->_db->loadModule('Manager', null, true);
313        $result = $this->_db->manager->createTable(
314            $this->_table,
315            array(
316                'id'        => array('type' => $this->_types['id']),
317                'logtime'   => array('type' => $this->_types['logtime']),
318                'ident'     => array('type' => $this->_types['ident']),
319                'priority'  => array('type' => $this->_types['priority']),
320                'message'   => array('type' => $this->_types['message'])
321            )
322        );
323        if (PEAR::isError($result)) {
324            return false;
325        }
326
327        $result = $this->_db->manager->createIndex(
328            $this->_table,
329            'unique_id',
330            array('fields' => array('id' => true), 'unique' => true)
331        );
332        if (PEAR::isError($result)) {
333            return false;
334        }
335
336        return true;
337    }
338
339    /**
340     * Prepare the SQL insertion statement.
341     *
342     * @return boolean  True if the statement was successfully created.
343     *
344     * @access  private
345     * @since   Log 1.9.0
346     */
347    function _prepareStatement()
348    {
349        $this->_statement = &$this->_db->prepare(
350                'INSERT INTO ' . $this->_table .
351                ' (id, logtime, ident, priority, message)' .
352                ' VALUES(:id, :logtime, :ident, :priority, :message)',
353                $this->_types, MDB2_PREPARE_MANIP);
354
355        /* Return success if we didn't generate an error. */
356        return (PEAR::isError($this->_statement) === false);
357    }
358}
Note: See TracBrowser for help on using the repository browser.