9 * This source file is subject to the new BSD license that is bundled
10 * with this package in the file LICENSE.
11 * It is also available through the world-wide-web at this URL:
12 * http://phergie.org/license
15 * @package Phergie_Plugin_Php
16 * @author Phergie Development Team <team@phergie.org>
17 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
18 * @license http://phergie.org/license New BSD License
19 * @link http://pear.phergie.org/package/Phergie_Plugin_Php
23 * Data source for {@see Phergie_Plugin_Php}. This source reads function
24 * descriptions from a file and stores them in a SQLite database. When a
25 * function description is requested, the function is retrieved from the
29 * @package Phergie_Plugin_Php
30 * @author Phergie Development Team <team@phergie.org>
31 * @license http://phergie.org/license New BSD License
32 * @link http://pear.phergie.org/package/Phergie_Plugin_Php
34 * @uses extension pdo_sqlite
35 * @uses Phergie_Plugin_Command pear.phergie.org
37 class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
40 * Local database for storage
47 * Source of the PHP function summary
51 protected $url = 'http://cvs.php.net/viewvc.cgi/phpdoc/funcsummary.txt?revision=HEAD';
54 * Constructor to initialize the data source.
58 public function __construct()
60 $path = dirname(__FILE__);
63 $this->database = new PDO('sqlite:' . $path . '/functions.db');
64 $this->buildDatabase();
65 // @todo Modify this to be rethrown as an appropriate
66 // Phergie_Plugin_Exception and handled in Phergie_Plugin_Php
67 } catch (PDOException $e) {
72 * Searches for a description of the function.
74 * @param string $function Search pattern to match against the function
75 * name, wildcards supported using %
77 * @return array|null Associative array containing the function name and
78 * description or NULL if no results are found
80 public function findFunction($function)
82 // Remove possible parentheses
83 $split = preg_split('{\(|\)}', $function);
84 $function = (count($split)) ? array_shift($split) : $function;
86 // Prepare the database statement
87 $stmt = $this->database->prepare('SELECT `name`, `description` FROM `functions` WHERE `name` LIKE :function');
88 $stmt->execute(array(':function' => $function));
91 if (count($stmt) > 0) {
92 $result = $stmt->fetch(PDO::FETCH_ASSOC);
94 * @todo add class and function URLS
95 * class methods: http://php.net/manual/en/classname.methodname.php
96 * functions: http://php.net/manual/en/function.functionname.php
97 * where '_' is replaced with '-'
102 // No results found, return
107 * Build the database and parses the function summary file into it.
109 * @param bool $rebuild TRUE to force a rebuild of the table used to
110 * house function information, FALSE otherwise, defaults to FALSE
114 protected function buildDatabase($rebuild = false)
116 // Check to see if the functions table exists
117 $table = $this->database->exec("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'");
119 // If the table doesn't exist, create it
121 $this->database->exec('CREATE TABLE `functions` (`name` VARCHAR(255), `description` TEXT)');
122 $this->database->exec('CREATE UNIQUE INDEX `functions_name` ON `functions` (`name`)');
125 // If we created a new table, fill it with data
126 if (!$table || $rebuild) {
127 // Get the contents of the source file
128 // @todo Handle possible error cases better here; the @ operator
129 // shouldn't be needed
130 $contents = @file($this->url, FILE_IGNORE_NEW_LINES + FILE_SKIP_EMPTY_LINES);
136 // Parse the contents
140 foreach ($contents as $line) {
141 // Clean the current line
144 // Skip comment lines
145 if (0 === strpos($line, '#')) {
146 // reset the line if the current line is odd
147 if (($lineNumber % 2) !== 0) {
154 * If the current line is even, it's the first part of the
155 * complete function description ...
157 if (($lineNumber % 2) === 0) {
160 // ... it's the last part of the complete function description
161 $completeLine = $firstPart . ' ' . $line;
163 if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.\-_]*)$}', $completeLine, $matches)) {
167 // Up the line number before going to the next line
170 // free up some memory
173 // Process the valid matches
174 if (count($valid) > 0) {
175 // Clear the database
176 $this->database->exec('DELETE * FROM `functions`');
178 // Prepare the sql statement
179 $stmt = $this->database->prepare('INSERT INTO `functions` (`name`, `description`) VALUES (:name, :description)');
180 $this->database->beginTransaction();
183 foreach ($valid as $function) {
184 // Extract function values
185 list( , $retval, $name, $params, $desc) = $function;
190 // Reconstruct the complete function line
191 $line = trim($retval . ' ' . $name . '(' . $params . ') - ' . $desc);
192 // Execute the statement
193 $stmt->execute(array(':name' => $name, ':description' => $line));
196 // Commit the changes to the database
197 $this->database->commit();
199 // free up some more memory