Overview

Packages

  • Luxor
  • None

Classes

  • Luxor
  • Luxor_Driver
  • Luxor_Driver_sql
  • Luxor_Files
  • Luxor_Files_plain
  • Luxor_Lang
  • Luxor_Lang_Generic
  • Luxor_SimpleParse
  • Luxor_Tagger
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Luxor storage implementation for PHP's PEAR database abstraction layer.
  4:  *
  5:  * The table structure can be created by the scripts/drivers/luxor.sql
  6:  * script.
  7:  *
  8:  * $Horde: luxor/lib/Driver/sql.php,v 1.29 2007/09/23 13:32:35 jan Exp $
  9:  *
 10:  * @author  Jan Schneider <jan@horde.org>
 11:  * @since   Luxor 0.1
 12:  * @package Luxor
 13:  */
 14: class Luxor_Driver_sql extends Luxor_Driver {
 15: 
 16:     /**
 17:      * Hash containing connection parameters.
 18:      *
 19:      * @var array
 20:      */
 21:     var $_params = array();
 22: 
 23:     /**
 24:      * Handle for the current database connection.
 25:      *
 26:      * @var DB
 27:      */
 28:     var $_db;
 29: 
 30:     /**
 31:      * The id of the source that we are dealing with.
 32:      *
 33:      * @var string
 34:      */
 35:     var $_source;
 36: 
 37:     /**
 38:      * Boolean indicating whether or not we're connected to the SQL server.
 39:      *
 40:      * @var boolean
 41:      */
 42:     var $_connected = false;
 43: 
 44:     /**
 45:      * Symbol cache.
 46:      *
 47:      * @var array
 48:      */
 49:     var $_symcache = array();
 50: 
 51:     /**
 52:      * Description ID cache.
 53:      *
 54:      * @var array
 55:      */
 56:     var $_decIdcache = array();
 57: 
 58:     /**
 59:      * Constructs a new SQL storage object.
 60:      *
 61:      * @param string $source  The name of the source.
 62:      * @param array  $params  A hash containing connection parameters.
 63:      */
 64:     function Luxor_Driver_sql($source, $params = array())
 65:     {
 66:         $this->_source = $source;
 67:         $this->_params = $params;
 68:     }
 69: 
 70:     /**
 71:      * Adds a symbol definition to the sybmol index.
 72:      *
 73:      * @param string $symname  The symbol's name.
 74:      * @param integer $fileId  The unique ID of the file where this symbol was
 75:      *                         defined.
 76:      * @param integer $line    The linenumber where this symbol was defined.
 77:      * @param integer $langid  The unique ID of the language the file was
 78:      *                         written in.
 79:      * @param integer $type    The symbol type.
 80:      *
 81:      * @return mixed           PEAR_Error on error, true on success.
 82:      */
 83:     function index($symname, $fileId, $line, $langid, $type)
 84:     {
 85:         $this->_connect();
 86: 
 87:         $symid = $this->symid($symname);
 88:         if (is_a($symid, 'PEAR_Error')) {
 89:             return $symid;
 90:         }
 91: 
 92:         /* I have no idea what this is about yet
 93:         if ($relsym) {
 94:             $relsym = $this->symid($relsym);
 95:             if (is_a($relsym, 'PEAR_Error')) {
 96:                 return $relsym;
 97:             }
 98:             $relsym = $this->_db->quote($relsym);
 99:         } else {
100:             $relsym = 'NULL';
101:         }
102:         */
103: 
104:         $query = 'INSERT INTO luxor_indexes (symid, fileid, line, declid)' .
105:                  ' VALUES (?, ?, ?, ?)';
106:         $values = array($symid, $fileId, $line, $this->getDecId($langid, $type));
107:         return $this->_db->query($query, $values);
108:     }
109: 
110:     /**
111:      * Add a symbol reference to the reference index.
112:      *
113:      * @param string $symname  The name of the used symbol.
114:      * @param integer $fileId  The unique ID of the file in which the symbol
115:      *                         was used.
116:      * @param integer $line    The number of line in which the symbol was used.
117:      *
118:      * @return mixed           PEAR_Error on error, true on success.
119:      */
120:     function reference($symname, $fileId, $line)
121:     {
122:         $this->_connect();
123: 
124:         $result = $this->_db->query('INSERT INTO luxor_usage (fileid, line, symid) VALUES (?, ?, ?)',
125:                                     array($fileId, $line, $this->symid($symname)));
126:         return $result;
127:     }
128: 
129:     /**
130:      * Returns a unique ID for a given filename.
131:      *
132:      * @param string $filename  The name of the file.
133:      * @param string $tag       The tag of the file.
134:      *
135:      * @return integer  A unique ID for this file or PEAR_Error on error.
136:      */
137:     function fileId($filename, $tag = '')
138:     {
139:         static $files = array();
140: 
141:         /* Have we already been asked for this file? */
142:         if (isset($files[$filename])) {
143:             return $files[$filename];
144:         }
145: 
146:         $this->_connect();
147: 
148:         /* Has an ID already been created for this file? */
149:         $query = 'SELECT fileid FROM luxor_files' .
150:                  ' WHERE tag = ? AND source = ? AND filename = ?';
151:         $values = array($tag, $this->_source, $filename);
152: 
153:         $fileId = $this->_db->getOne($query, $values);
154:         if (empty($fileId) || is_a($fileId, 'PEAR_Error')) {
155:             return false;
156:         }
157:         $files[$filename] = $fileId;
158: 
159:         return $fileId;
160:     }
161: 
162:     /**
163:      * Created a unique ID for a given filename.
164:      *
165:      * @param string $filename      The name of the file.
166:      * @param string $tag           The tag of the file.
167:      * @param integer $lastmodified The timestamp the file was last modified.
168:      *
169:      * @return integer              A unique ID for this file or PEAR_Error on error.
170:      */
171:     function createFileId($filename, $tag = '', $lastmodified)
172:     {
173:         $this->_connect();
174: 
175:         $fileId = $this->_db->nextId('luxor_files');
176:         if (is_a($fileId, 'PEAR_Error')) {
177:             return $fileId;
178:         }
179: 
180:         /* Create an ID for this file. */
181:         $query = 'INSERT INTO luxor_files (fileid, filename, source, tag, lastmodified) VALUES (?, ?, ?, ?, ?)';
182:         $values = array((int)$fileId,
183:                         $filename,
184:                         $this->_source,
185:                         $tag,
186:                         $lastmodified);
187: 
188:         $result = $this->_db->query($query, $values);
189:         if (is_a($result, 'PEAR_Error')) {
190:             return $result;
191:         }
192: 
193:         return $fileId;
194:     }
195: 
196:     /**
197:      * Returns a unique ID for a given symbol.
198:      *
199:      * @param string $symname  The name of the symbol.
200:      *
201:      * @return int             A unique ID for this symbol or PEAR_Error on error.
202:      */
203:     function symid($symname)
204:     {
205:         /* Do we have this symbol in the symbol cache yet? */
206:         if (!isset($this->_symcache[$symname])) {
207:             $this->_connect();
208:             /* Has an ID already been created for this symbol? */
209:             $query = 'SELECT symid FROM luxor_symbols' .
210:                      ' WHERE source = ? AND symname = ?';
211:             $values = array($this->_source, $symname);
212:             $symid = $this->_db->getOne($query, $values);
213:             if (is_null($symid) || is_a($symid, 'PEAR_Error')) {
214:                 /* Create an ID for this symbol. */
215:                 $symid = $this->_db->nextId('luxor_symbols');
216:                 if (is_a($symid, 'PEAR_Error')) {
217:                     return $symid;
218:                 }
219:                 $result = $this->_db->query('INSERT INTO luxor_symbols (symid, symname, source) VALUES (?, ?, ?)',
220:                                             array((int)$symid, $symname, $this->_source));
221:                 if (is_a($result, 'PEAR_Error')) {
222:                     return $result;
223:                 }
224:             }
225:             $this->_symcache[$symname] = $symid;
226:         }
227: 
228:         return $this->_symcache[$symname];
229:     }
230: 
231:     /**
232:      * Returns the name of a symbol from its unique ID.
233:      *
234:      * @param integer $symid  The ID of the symbol
235:      *
236:      * @return string  The name of the symbol or PEAR_Error on error
237:      */
238:     function symname($symid)
239:     {
240:         /* Don't we have this symbol in the symbol cache yet? */
241:         $this->_connect();
242: 
243:         if (in_array($symid, $this->_symcache)) {
244:             return array_key($symid, $this->_symcache);
245:         }
246: 
247:         $query = 'SELECT symname FROM luxor_symbols WHERE symid = ?';
248:         $values = array($symid);
249:         $symname = $this->_db->getOne($query, $values);
250:         $this->_symcache[$symname] = $symid;
251: 
252:         return $symname;
253:     }
254: 
255:     /**
256:      * Checks if the given name is a known symbol.
257:      *
258:      * @param string $symname  The potential symbol name.
259:      *
260:      * @return integer  The symbol's id or null if it wasn't a symbol.
261:      */
262:     function isSymbol($symname, $altsources = array())
263:     {
264:         if (!isset($this->_symcache[$symname])) {
265:             $this->_connect();
266: 
267:             $altsql = '';
268:             $altvalues = array();
269:             if (!is_array($altsources)) {
270:                 $altsources = array($altsources);
271:             }
272:             foreach ($altsources as $source) {
273:                 $altsql .= ' OR source = ?';
274:                 $altvalues[] = $source;
275:             }
276: 
277:             array_unshift($altvalues, $this->_source);
278:             $values = $altvalues;
279:             $values[] = $symname;
280: 
281:             $symid = $this->_db->getOne('SELECT symid FROM luxor_symbols' .
282:                                         ' WHERE (source = ?' . $altsql . ')' .
283:                                         ' AND symname = ?',
284:                                         $values);
285:             $this->_symcache[$symname] = $symid;
286:         }
287: 
288:         return $this->_symcache[$symname];
289:     }
290: 
291:     /**
292:      * If this file has not been indexed earlier, mark it as being
293:      * indexed now.
294:      *
295:      * @param integer $fileId  The file's unique ID.
296:      *
297:      * @return boolean  True if the file has been marked as being indexed,
298:      *                  false if it was already indexed.
299:      */
300:     function toIndex($fileId)
301:     {
302:         $this->_connect();
303: 
304:         $status = $this->_db->getOne('SELECT status FROM luxor_status' .
305:                                      ' WHERE fileid = ?',
306:                                      array($fileId));
307:         if (empty($status)) {
308:             $this->_db->query('INSERT INTO luxor_status (fileid, status)' .
309:                               ' VALUES (?, 0)',
310:                               array($fileId + 0));
311:         }
312:         $query = 'UPDATE luxor_status SET status = 1' .
313:                  ' WHERE fileid = ? AND status <= 0';
314:         $values = array($fileId);
315:         return $this->_db->query($query, $values);
316:     }
317: 
318:     /**
319:      * If this file has not been referenced earlier, mark it as being
320:      * referenced now.
321:      *
322:      * @param integer $fileId  The file's unique ID.
323:      *
324:      * @return boolean  True if the file has been marked as being referenced,
325:      *                  false if it was already referenced.
326:      */
327:     function toReference($fileId)
328:     {
329:         $this->_connect();
330: 
331:         $query = 'UPDATE luxor_status SET status = 2' .
332:                  ' WHERE fileid = ? AND status <= 1';
333:         $values = array($fileId);
334:         return $this->_db->query($query, $values);
335:     }
336: 
337:     /**
338:      * Return the last time the entry for a file was modified.
339:      *
340:      * @param string $filename  The filename to check.
341:      *
342:      * @return integer  The last modified time, or 0 if there is an error.
343:      */
344:     function getLastModified($filename)
345:     {
346:         static $lastModified;
347: 
348:         if (isset($lastModified[$filename])) {
349:             return $lastModified[$filename];
350:         }
351: 
352:         $this->_connect();
353:         $query = 'SELECT lastmodified FROM luxor_files' .
354:                  ' WHERE source = ? AND filename = ?';
355:         $values = array($this->_source, $filename);
356:         $res = $this->_db->getOne($query, $values);
357:         $lastModified[$filename] = is_a($res, 'PEAR_Error') ? 0 : $res;
358: 
359:         return $lastModified[$filename];
360:     }
361: 
362:     /**
363:      * Empties the current symbol cache.
364:      *
365:      * This function should be called before parsing each new file.
366:      * If this is not done too much memory will be used and things
367:      * will become very slow.
368:      */
369:     function clearCache()
370:     {
371:         $this->_symcache = array();
372:     }
373: 
374:     /**
375:      * Cleans the database for a fresh import of data.
376:      *
377:      * This function should be called before parsing the source tree
378:      * again, to avoid duplicate entries in the database.
379:      */
380:     function clearIndex()
381:     {
382:         $this->_connect();
383: 
384:         $this->_db->query('DELETE FROM luxor_declarations');
385:         $this->_db->query('DELETE FROM luxor_files');
386:         $this->_db->query('DELETE FROM luxor_indexes');
387:         $this->_db->query('DELETE FROM luxor_status');
388:         $this->_db->query('DELETE FROM luxor_symbols');
389:         $this->_db->query('DELETE FROM luxor_usage');
390:     }
391: 
392:     /**
393:      * Returns an unique ID for a description of a symbol type.
394:      *
395:      * @param integer $lang   The language's unique ID.
396:      * @param string $string  The symbol type description.
397:      *
398:      * return mixed  A unique ID for this description or PEAR_Error on error.
399:      */
400:     function getDecId($lang, $string)
401:     {
402:         $this->_connect();
403: 
404:         if (!isset($this->_decIdcache[$lang])) {
405:             $this->_decIdcache[$lang] = array();
406:         }
407: 
408:         if (!isset($this->_decIdcache[$lang][$string])) {
409:             $query = 'SELECT declid FROM luxor_declarations' .
410:                      ' WHERE langid = ? AND declaration = ?';
411:             $values = array($lang, $string);
412:             $decId = $this->_db->getOne($query, $values);
413:             if (is_null($decId) || is_a($decId, 'PEAR_Error')) {
414:                 /* Create an ID for this declaration. */
415:                 $decId = $this->_db->nextId('luxor_declarations');
416:                 if (is_a($decId, 'PEAR_Error')) {
417:                     return $decId;
418:                 }
419:                 $this->_db->query('INSERT INTO luxor_declarations (declid, langid, declaration)' .
420:                                   ' VALUES (?, ?, ?)',
421:                                   array((int)$decId, $lang, $string));
422:             }
423:             $this->_decIdcache[$lang][$string] = $decId;
424:         }
425: 
426:         return $this->_decIdcache[$lang][$string];
427:     }
428: 
429:     /**
430:      * Locate the definitions of a symbol.
431:      *
432:      * @param integer $symid  The symbol id.
433:      * @param string $tag     The tag of the file.
434:      *
435:      * @return array  Nested hash with elements 'filename', 'line', and
436:      *                'declaration'.
437:      */
438:     function getIndex($symid, $tag = '')
439:     {
440:         $this->_connect();
441:         $query = 'SELECT filename, line, declaration FROM ' .
442:                  'luxor_files, luxor_indexes, luxor_declarations WHERE ' .
443:                  'luxor_files.fileid = luxor_indexes.fileid AND ' . // join files to indexes
444:                  'luxor_indexes.declid = luxor_declarations.declid AND ' . // join indexes to declarations
445:                  'luxor_indexes.symid = ? AND ' .
446:                  'luxor_files.tag = ? AND ' .
447:                  'luxor_files.source = ?';
448:         $values = array((int)$symid, $tag, $this->_source);
449: 
450:         return $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC);
451:     }
452: 
453:     /**
454:      * Locate the usage of a symbol.
455:      *
456:      * @param integer $symid  The symbol id.
457:      * @param string $tag     The tag of the file.
458:      *
459:      * @return array  Nested hash with elements 'filename', and 'line'.
460:      */
461:     function getReference($symid, $tag = '')
462:     {
463:         $this->_connect();
464:         $query = 'SELECT filename, line FROM ' .
465:                  'luxor_usage, luxor_files WHERE ' .
466:                  'luxor_usage.fileid = luxor_files.fileid AND ' .
467:                  'luxor_usage.symid = ? AND ' .
468:                  'luxor_files.tag = ? AND ' .
469:                  'luxor_files.source = ?';
470:         $values = array((int)$symid, $tag, $this->_source);
471: 
472:         return $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC);
473:     }
474: 
475:     /**
476:      * Search for symbols matching $symbol.
477:      *
478:      * @param string $symbol  The symbol name to search for.
479:      *
480:      * @return array  Any symids matching $symbol.
481:      */
482:     function searchSymbols($symbol)
483:     {
484:         $this->_connect();
485:         $query = 'SELECT symid, symid FROM luxor_symbols WHERE symname LIKE ?';
486:         $values = array($symbol . '%');
487: 
488:         return $this->_db->getAssoc($query, false, $values);
489:     }
490: 
491:     /**
492:      * Get source that a symbol is from.
493:      *
494:      * @param $symid  The symbol id.
495:      *
496:      * @return string  The source id.
497:      */
498:     function getSourceBySymbol($symid)
499:     {
500:         $this->_connect();
501: 
502:         return $this->_db->getOne('SELECT source FROM luxor_symbols' .
503:                                   ' WHERE symid = ?',
504:                                   array($symid));
505:     }
506: 
507:     /**
508:      * Attempts to open a persistent connection to the SQL server.
509:      *
510:      * @return boolean  True on success.
511:      */
512:     function _connect()
513:     {
514:         if (!$this->_connected) {
515:             $this->_db = $GLOBALS['injector']->getInstance('Horde_Core_Factory_DbPear')->create('rw', 'luxor', 'storage');
516:             $this->_connected = true;
517:         }
518: 
519:         return true;
520:     }
521: 
522: }
523: 
API documentation generated by ApiGen