/trunk/bibliotheque/pear/DB/NestedSet/Output.php |
---|
New file |
0,0 → 1,211 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_Output | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Daniel Khan <dk@webcluster.at> | |
// | Jason Rust <jason@rustyparts.com> | |
// +----------------------------------------------------------------------+ |
// $Id: Output.php,v 1.11 2003/10/07 00:11:27 datenpunk Exp $ |
// |
require_once 'PEAR.php'; |
// {{{ constants |
define('NESEO_ERROR_NO_METHOD', 'E1000'); |
define('NESEO_DRIVER_NOT_FOUND', 'E1100'); |
define('NESEO_ERROR_NO_OPTIONS', 'E2100'); |
// }}} |
// {{{ DB_NestedSet_Output:: class |
/** |
* DB_NestedSet_Output is a unified API for other output drivers |
* Status is beta |
* |
* At the moment PEAR::HTML_TreeMenu written by Jason Rust is supported |
* A driver for treemenu.org will follow soon. |
* |
* Usage example: |
* |
* require_once('DB_NestedSet/NestedSet/Output.php'); |
* $icon = 'folder.gif'; |
* $expandedIcon = 'folder-expanded.gif'; |
* // get data (important to fetch it as an array, using the true flag) |
* $data = $NeSe->getAllNodes(true); |
* // change the events for one of the elements |
* $data[35]['events'] = array('onexpand' => 'alert("we expanded!");'); |
* // add links to each item |
* foreach ($data as $a_data) { |
* $a_data['link'] = 'http://foo.com/foo.php?' . $a_data['id']; |
* } |
* $params = array( |
* 'structure' => $data, |
* 'options' => array( |
* 'icon' => $icon, |
* 'expandedIcon' => $expandedIcon, |
* ), |
* 'textField' => 'name', |
* 'linkField' => 'link', |
* ); |
* $menu =& DB_NestedSet_Output::factory('TreeMenu', $params); |
* $menu->printListbox(); |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.11 $ |
* @access public |
* |
*/ |
// }}} |
class DB_NestedSet_Output { |
// {{{ properties |
/** |
* @var object The tree menu structure |
* @access private |
*/ |
var $_structTreeMenu = false; |
/** |
* @var array Array of options to be passed to the ouput methods |
* @access public |
*/ |
var $options = array(); |
// }}} |
// {{{ factory() |
/** |
* Returns a output driver object |
* |
* @param array $params A DB_NestedSet nodeset |
* @param string $driver (optional) The driver, such as TreeMenu (default) |
* |
* @access public |
* @return object The DB_NestedSet_Ouput object |
*/ |
function &factory ($params, $driver = 'TreeMenu') { |
$path = dirname(__FILE__).'/'.$driver.'.php'; |
if(is_dir($path) || !file_exists($path)) { |
PEAR::raiseError("The output driver '$driver' wasn't found", NESEO_DRIVER_NOT_FOUND, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
require_once($path); |
$driverClass = 'DB_NestedSet_'.$driver; |
return new $driverClass($params); |
} |
// }}} |
// {{{ setOptions() |
/** |
* Set's options for a specific output group (printTree, printListbox) |
* This enables you to set specific options for each output method |
* |
* @param string $group Output group ATM 'printTree' or 'printListbox' |
* @param array $options Hash with options |
* |
* @access public |
* @return bool |
*/ |
function setOptions($group, $options) { |
$this->options[$group] = $options; |
return true; |
} |
// }}} |
// {{{ _getOptions() |
/** |
* Get's all option for a specific output group (printTree, printListbox) |
* |
* @param string $group Output group ATM 'printTree' or 'printListbox' |
* |
* @access private |
* @return array Options |
*/ |
function _getOptions($group) { |
if (!isset($this->options[$group])) { |
return array(); |
} |
return $this->options[$group]; |
} |
// }}} |
// {{{ printTree() |
/** |
* Print's the current tree using the output driver |
* Overriden by the driver class |
* |
* @access public |
*/ |
function printTree() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
// {{{ printListbox() |
/** |
* Print's a listbox representing the current tree |
* Overriden by the driver class |
* |
* @access public |
*/ |
function printListbox() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
// {{{ toHTML() |
/** |
* Returns the HTML for the DHTML-menu. This method can be |
* used instead of printMenu() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the menu |
* @author Emanuel Zueger |
*/ |
function tree_toHTML() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
// {{{ listbox_toHTML() |
/** |
* Returns the HTML for the listbox. This method can be |
* used instead of printListbox() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the listbox |
* @author Emanuel Zueger |
*/ |
function listbox_toHTML() { |
PEAR::raiseError("Method not available for this driver", NESEO_ERROR_NO_METHOD, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/NestedSet/Event.php |
---|
New file |
0,0 → 1,79 |
<?php |
/** |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_DB | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: Event.php,v 1.3 2003/10/07 00:11:27 datenpunk Exp $ |
// |
// |
*/ |
/** |
* Poor mans event handler for DB_NestedSet |
* |
* Mostly for demo purposes or for extending it if |
* someone has ideas... |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.3 $ |
* @access public |
*/ |
Class DB_NestedSetEvent extends PEAR { |
/** |
* Constructor |
* |
* @return void |
*/ |
function DB_NestedSetEvent() { |
$this->PEAR(); |
} |
/** |
* Destructor |
* |
* @return void |
*/ |
function _DB_NestedSetEvent() { |
$this->_PEAR(); |
} |
/** |
* Calls the event handler |
* |
* You may want to do a switch() here and call you methods |
* depending on the event |
* |
* @param string $event The Event that occured |
* @param object node $node A Reference to the node object which was subject to changes |
* @param array $eparams A associative array of params which may be needed by the handler |
* @return void |
* @access private |
*/ |
function callEvent($event, &$node, $eparams = array()) { |
echo "<br>Override callEvent() if you want to have custom event handlers<br>\n"; |
echo "Event $event was called with the following params:<br><br>\n"; |
echo "<PRE>"; |
print_r($eparams); |
echo "</PRE><br>\n"; |
} |
} |
?> |
/trunk/bibliotheque/pear/DB/NestedSet/MDB.php |
---|
New file |
0,0 → 1,136 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_MDB | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// Thanks to Hans Lellelid for suggesting support for PEAR::MDB |
// and for his help in implementing this. |
// |
// $Id: MDB.php,v 1.7 2003/10/07 00:11:27 datenpunk Exp $ |
// |
require_once 'MDB.php'; |
// {{{ DB_NestedSet_MDB:: class |
/** |
* Wrapper class for PEAR::MDB |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.7 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_MDB extends DB_NestedSet { |
// {{{ properties |
/** |
* @var object The MDB object |
*/ |
var $db; |
// }}} |
// {{{ constructor |
/** |
* Constructor |
* |
* @param mixed $dsn DSN as PEAR dsn URI or dsn Array |
* @param array $params Database column fields which should be returned |
* |
*/ |
function DB_NestedSet_MDB($dsn, $params = array()) |
{ |
$this->_debugMessage('DB_NestedSet_MDB($dsn, $params = array())'); |
$this->DB_NestedSet($params); |
$this->db =& $this->_db_Connect($dsn); |
$this->db->setFetchMode(MDB_FETCHMODE_ASSOC); |
} |
// }}} |
// {{{ destructor |
/** |
* Destructor |
*/ |
function _DB_NestedSet_MDB() |
{ |
$this->_debugMessage('_DB_NestedSet_MDB()'); |
$this->_DB_NestedSet(); |
$this->_db_Disconnect(); |
} |
// }}} |
// {{{ _db_Connect() |
/** |
* Connects to the db |
* |
* @return object DB The database object |
* @access private |
*/ |
function &_db_Connect($dsn) |
{ |
$this->_debugMessage('_db_Connect($dsn)'); |
if (is_object($this->db)) { |
return $this->db; |
} |
$db =& MDB::connect($dsn); |
$this->_testFatalAbort($db, __FILE__, __LINE__); |
return $db; |
} |
// }}} |
function _isDBError($err) { |
if(!MDB::isError($err)) { |
return false; |
} |
return true; |
} |
function _numRows($res) { |
return $this->db->numRows($res); |
} |
function _quote($str) { |
return $this->db->getTextValue($str); |
} |
// {{{ _db_Disconnect() |
/** |
* Disconnects from db |
* |
* @return void |
* @access private |
*/ |
function _db_Disconnect() |
{ |
$this->_debugMessage('_db_Disconnect()'); |
if (is_object($this->db)) { |
@$this->db->disconnect(); |
} |
return true; |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/NestedSet/TreeMenu.php |
---|
New file |
0,0 → 1,205 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_TreeMenu | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Jason Rust <jrust@rustyparts.com> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: TreeMenu.php,v 1.13 2003/10/07 00:11:27 datenpunk Exp $ |
// |
require_once 'HTML/TreeMenu.php'; |
// {{{ DB_NestedSet_TreeMenu:: class |
/** |
* A helper class to translate the data from a nested set table into a HTML_TreeMenu object |
* so that it can be used to create a dynamic tree menu using the PEAR HTML_TreeMenu class. |
* |
* @see docs/TreeMenu_example.php |
* @author Jason Rust <jrust@rustyparts.com> |
* @package DB_NestedSet |
* @version $Revision: 1.13 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_TreeMenu extends DB_NestedSet_Output { |
// {{{ properties |
/** |
* @var array The current menu structure |
* @access private |
*/ |
var $_structTreeMenu = false; |
// }}} |
// {{{ DB_NestedSet_TreeMenu |
function &DB_NestedSet_TreeMenu($params) { |
$this->_structTreeMenu =& $this->_createFromStructure($params); |
} |
// }}} |
// {{{ _createFromStructure() |
/** |
* <pre>Creates a HTML_TreeMenu structure based off of the results from getAllNodes() method |
* of the DB_NestedSet class. The needed parameters are: |
* o 'structure' => the result from $nestedSet->getAllNodes(true) |
* o 'textField' => the field in the table that has the text for node |
* o 'linkField' => the field in the table that has the link for the node |
* o 'options' => (optional) an array of any additional options to pass to the node when |
* Additionally these parameters may be added to the individual nodes to control their |
* behavior: |
* o 'ensureVisible' => (optional) whether or not the field should be forced as visible |
* creating it such as 'icon' or 'expandedIcon' |
* o 'events' => (optional) an array of any events to pass to the node when creating it |
* such as 'onclick' or 'onexpand'</pre> |
* </pre> |
* @access public |
* @return object A HTML_TreeMenu object |
*/ |
function &_createFromStructure($params) |
{ |
// Basically we go through the array of nodes checking to see |
// if each node has children and if so recursing. The reason this |
// works is because the data from getAllNodes() is ordered by level |
// so a root node will always be first, and sub children will always |
// be after them. |
if (!isset($params['treeMenu'])) { |
$treeMenu =& new HTML_TreeMenu(); |
} else { |
$treeMenu =& $params['treeMenu']; |
} |
// always start at level 1 |
if (!isset($params['currentLevel'])) { |
$params['currentLevel'] = 1; |
} |
// have to use a while loop here because foreach works on a copy of the array and |
// the child nodes are passed by reference during the recursion so that the parent |
// will know when they have been hit. |
reset($params['structure']); |
while(list($key, $node) = each($params['structure'])) { |
// see if we've already been here before |
if (isset($node['hit'])) { |
continue; |
} |
// mark that we've hit this node |
$params['structure'][$key]['hit'] = $node['hit'] = true; |
$tag = array( |
'text' => $node[$params['textField']], |
'link' => $node[$params['linkField']], |
'ensureVisible' => isset($node['ensureVisible']) ? $node['ensureVisible'] : false, |
); |
$options = isset($params['options']) ? array_merge($params['options'], $tag) : $tag; |
$events = isset($node['events']) ? $node['events'] : array(); |
$parentNode =& $treeMenu->addItem(new HTML_TreeNode($options, $events)); |
// see if it has children |
if (($node['r'] - 1) != $node['l']) { |
$children = array(); |
// harvest all the children |
$tempStructure = $params['structure']; |
foreach ($tempStructure as $childKey => $childNode) { |
if (!isset($childNode['hit']) && |
$childNode['l'] > $node['l'] && |
$childNode['r'] < $node['r'] && |
$childNode['rootid'] == $node['rootid']) { |
// important that we assign it by reference here, so that when the child |
// marks itself 'hit' the parent loops will know |
$children[] =& $params['structure'][$childKey]; |
} |
} |
$recurseParams = $params; |
$recurseParams['structure'] = $children; |
$recurseParams['treeMenu'] =& $parentNode; |
$recurseParams['currentLevel']++; |
$this->_createFromStructure($recurseParams); |
} |
} |
return $treeMenu; |
} |
// }}} |
// {{{ printTree() |
/** |
* Print's the current tree using the output driver |
* |
* @access public |
*/ |
function printTree() { |
$options = $this->_getOptions('printTree'); |
$tree =& new HTML_TreeMenu_DHTML($this->_structTreeMenu, $options); |
$tree->printMenu(); |
} |
// }}} |
// {{{ printListbox() |
/** |
* Print's a listbox representing the current tree |
* |
* @access public |
*/ |
function printListbox() { |
$options = $this->_getOptions('printListbox'); |
$listBox =& new HTML_TreeMenu_Listbox($this->_structTreeMenu, $options); |
$listBox->printMenu(); |
} |
// }}} |
// }}} |
// {{{ tree_toHTML() |
/** |
* Returns the HTML for the DHTML-menu. This method can be |
* used instead of printMenu() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the menu |
* @Author Emanuel Zueger |
*/ |
function tree_toHTML() { |
$options = $this->_getOptions('toHTML'); |
$tree =& new HTML_TreeMenu_DHTML($this->_structTreeMenu, $options); |
return $tree->toHTML(); |
} |
// }}} |
// {{{ listbox_toHTML() |
/** |
* Returns the HTML for the listbox. This method can be |
* used instead of printListbox() to use the menu system |
* with a template system. |
* |
* @access public |
* @return string The HTML for the listbox |
* @author Emanuel Zueger |
*/ |
function listbox_toHTML() { |
$options = $this->_getOptions('toHTML'); |
$listBox =& new HTML_TreeMenu_Listbox($this->_structTreeMenu, $options); |
return $listBox->toHTML(); |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/NestedSet/DB.php |
---|
New file |
0,0 → 1,135 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_DB | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: DB.php,v 1.7 2003/10/07 00:11:27 datenpunk Exp $ |
// |
require_once 'DB.php'; |
// {{{ DB_NestedSet_DB:: class |
/** |
* Wrapper class for PEAR::DB |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.7 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_DB extends DB_NestedSet { |
// {{{ properties |
/** |
* @var object Db object |
*/ |
var $db; |
// }}} |
// {{{ constructor |
/** |
* Constructor |
* |
* @param mixed $dsn DSN as PEAR dsn URI or dsn Array |
* @param array $params Database column fields which should be returned |
* |
*/ |
function DB_NestedSet_DB($dsn, $params = array()) |
{ |
$this->_debugMessage('DB_NestedSet_DB($dsn, $params = array())'); |
$this->DB_NestedSet($params); |
$this->db =& $this->_db_Connect($dsn); |
$this->db->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
// }}} |
// {{{ destructor |
/** |
* Destructor |
*/ |
function _DB_NestedSet_DB() |
{ |
$this->_debugMessage('_DB_NestedSet_DB()'); |
$this->_DB_NestedSet(); |
$this->_db_Disconnect(); |
} |
// }}} |
// {{{ _db_Connect() |
/** |
* Connects to the db |
* |
* @return object DB The database object |
* @access private |
*/ |
function &_db_Connect($dsn) |
{ |
$this->_debugMessage('_db_Connect($dsn)'); |
if (is_object($this->db)) { |
return $this->db; |
} |
$db =& DB::connect($dsn); |
$this->_testFatalAbort($db, __FILE__, __LINE__); |
return $db; |
} |
// }}} |
function _numRows($res) { |
return $res->numRows(); |
} |
function _isDBError($err) { |
if(!DB::isError($err)) { |
return false; |
} |
return true; |
} |
function _quote($str) { |
return $this->db->quote($str); |
} |
// {{{ _db_Disconnect() |
/** |
* Disconnects from db |
* |
* @return void |
* @access private |
*/ |
function _db_Disconnect() |
{ |
$this->_debugMessage('_db_Disconnect()'); |
if (is_object($this->db)) { |
@$this->db->disconnect(); |
} |
return true; |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/NestedSet/TigraMenu.php |
---|
New file |
0,0 → 1,402 |
<?php |
// |
// +----------------------------------------------------------------------+ |
// | PEAR :: DB_NestedSet_TigraMenu | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Daniel Khan <dk@webcluster.at> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: TigraMenu.php,v 1.8 2003/10/07 00:11:27 datenpunk Exp $ |
// |
// {{{ DB_NestedSet_TigraMenu:: class |
/** |
* This class can be used to generate the data to build javascript popup menu |
* from a DB_NestedSet node array. |
* The Javascript part is done using the free available TigraMenu |
* available at http://www.softcomplex.com/products/tigra_menu/. |
* Currently version 1.0 is supported. |
* Parts of this class where taken ftom the TreemMenu driver by Jason Rust |
* |
* @author Daniel Khan <dk@webcluster.at> |
* @package DB_NestedSet |
* @version $Revision: 1.8 $ |
* @access public |
*/ |
// }}} |
class DB_NestedSet_TigraMenu extends DB_NestedSet_Output { |
// {{{{ properties |
/** |
* @var integer The depth of the current menu. |
* @access private |
*/ |
var $_levels = 1; |
/** |
* @var integer The level we started at |
* @access private |
*/ |
var $_levelOffset = false; |
/** |
* @var array The current menu structure |
* @access private |
*/ |
var $_structTigraMenu = false; |
/** |
* @var array The longest text for each level |
* @access private |
*/ |
var $_strlenByLevel = array(); |
// }}} |
// {{{ DB_NestedSet_TigraMenu |
/** |
* Constructor |
* |
* @param array $params A hash with parameters needed by the class |
* @see _createFromStructure() |
* @return bool |
**/ |
function &DB_NestedSet_TigraMenu($params) { |
$this->_menu_id = $params['menu_id']; |
$this->_structTigraMenu = $this->_createFromStructure($params); |
return true; |
} |
// }}} |
// {{{ _createFromStructure() |
/** |
* Creates the JavaScript array for TigraMenu |
* Initially this method was introduced for the TreeMenu driver by Jason Rust |
* |
* o 'structure' => the result from $nestedSet->getAllNodes(true) |
* o 'textField' => the field in the table that has the text for node |
* o 'linkField' => the field in the table that has the link for the node |
* |
* @access private |
* @return string The TigraMenu JavaScript array |
*/ |
function &_createFromStructure($params) |
{ |
// Basically we go through the array of nodes checking to see |
// if each node has children and if so recursing. The reason this |
// works is because the data from getAllNodes() is ordered by level |
// so a root node will always be first, and sub children will always |
// be after them. |
static $rootlevel; |
// always start at level 1 |
if (!isset($params['currentLevel'])) { |
$params['currentLevel'] = 1; |
} |
if (!isset($rootlevel)) { |
$rootlevel = $params['currentLevel']; |
} |
if (isset($params['tigraMenu'])) { |
$tigraMenu = $tigraMenu.$params['tigraMenu']; |
} |
if(!$this->_levelOffset) { |
$this->_levelOffset = $params['currentLevel']; |
} |
if($this->_levels < ($params['currentLevel']- $this->_levelOffset)) { |
$this->_levels = $params['currentLevel'] - $this->_levelOffset; |
} |
// have to use a while loop here because foreach works on a copy of the array and |
// the child nodes are passed by reference during the recursion so that the parent |
// will know when they have been hit. |
reset($params['structure']); |
while(list($key, $node) = each($params['structure'])) { |
// see if we've already been here before |
if (isset($node['hit']) || $node['level'] < $params['currentLevel']) { |
continue; |
} |
// mark that we've hit this node |
$params['structure'][$key]['hit'] = $node['hit'] = true; |
$tag = array( |
isset($node[$params['textField']]) ? "'".$node[$params['textField']]."'" : 'null', |
isset($node[$params['linkField']]) ? "'".$node[$params['linkField']]."'" : 'null' |
); |
if (!$this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset] || |
strlen($node[$params['textField']]) > $this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset]) { |
$this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset] = strlen($node[$params['textField']]); |
}; |
$tigraMenu = $tigraMenu.$this->_openSubMenu($tag); |
// see if it has children |
if (($node['r'] - 1) != $node['l']) { |
$children = array(); |
// harvest all the children |
$tempStructure = $params['structure']; |
foreach ($tempStructure as $childKey => $childNode) { |
if (!isset($childNode['hit']) && |
$node['rootid'] == $childNode['rootid'] && |
$node['l'] < $childNode['l'] && |
$node['r'] > $childNode['r'] && |
$childNode['level'] > $params['currentLevel']) { |
// important that we assign it by reference here, so that when the child |
// marks itself 'hit' the parent loops will know |
$children[] =& $params['structure'][$childKey]; |
} |
} |
$recurseParams = $params; |
$recurseParams['structure'] = $children; |
$recurseParams['currentLevel']++; |
$tigraMenu = $tigraMenu.$this->_createFromStructure($recurseParams); |
} |
$tigraMenu = $tigraMenu.$this->_closeSubMenu(); |
} |
return $tigraMenu; |
} |
// }}} |
// {{{ _openMenu() |
/** |
* Returns the string which opens the JavaScript menu |
* |
* @access private |
* @param int $menu_id ID of the menu needed to use more than one menu on a page |
* @return string The JavaScript piece |
*/ |
function _openMenu($menu_id=1) |
{ |
$str = false; |
$str = $str."var MENU_ITEMS".$menu_id." = new Array();\n"; |
$str = $str."MENU_ITEMS".$menu_id." = [\n"; |
return $str; |
} |
// }}} |
// {{{ _openSubMenu() |
/** |
* Returns the string which opens a submenu within the JavaScript menu |
* |
* @access private |
* @param array $tag Contains the content of the current item (name, link) |
* @return string The JavaScript piece |
*/ |
function _openSubMenu($tag) |
{ |
$rtag = implode(', ', $tag); |
return "\n[".$rtag.','; |
} |
// }}} |
// {{{ _closeMenu() |
/** |
* Closes the JavaScript array |
* |
* @access private |
* @return string The JavaScript piece |
*/ |
function _closeMenu() |
{ |
return '];'; |
} |
// }}} |
// {{{ _closeSubMenu() |
/** |
* Closes the JavaScript array of a submenu |
* |
* @access private |
* @return string The JavaScript piece |
*/ |
function _closeSubMenu() |
{ |
return "\n],"; |
} |
// }}} |
// {{{ _addStyles() |
/** |
* Creates the JavaScript code which sets the styles for each level |
* |
* @access private |
* @param int $menu_id ID of the menu needed to use more than one menu on a page |
* @param array $rootStyles Array of style attributes for the top items |
* @param array $childStyles Array of style attributes for the sub items |
* @return string The JavaScript piece |
*/ |
function _addStyles($menu_id, $rootStyles, $childStyles = false) |
{ |
if (!$childStyles) { |
$childStyles = $rootStyles; |
} |
$styles = array(); |
foreach ($rootStyles as $key => $val) { |
foreach ($val as $skey => $sval) { |
$styles["'$key'"][$skey][] = "'$sval'"; |
} |
} |
foreach ($childStyles as $key => $val) { |
foreach ($val as $skey => $sval) { |
for ($i = 1; $i <= $this->_levels; $i++) { |
$styles["'$key'"][$skey][] = "'$sval'"; |
} |
} |
} |
$menustyles = false; |
$menustyles = $menustyles . 'var MENU_STYLES'.$menu_id." = new Array();\n"; |
foreach ($styles as $key => $val) { |
$menustyles = $menustyles.'MENU_STYLES'.$menu_id."[$key] = [\n"; |
foreach ($val as $skey => $sval) { |
$menustyles = $menustyles . "'$skey', [".implode(', ', $sval)."],\n"; |
} |
$menustyles = $menustyles."];\n"; |
} |
return $menustyles; |
} |
// }}} |
// {{{ _addGeometry() |
/** |
* Creates the JavaScript code which sets the position and geometry of the menu |
* |
* @access private |
* @param int $menu_id ID of the menu needed to use more than one menu on a page |
* @param array $rootGeometry Array of geometry attributes for the top items |
* @param array $childGeometry Array of geometry attributes for the sub items |
* @return string The JavaScript piece |
*/ |
function _addGeometry($menu_id, $rootGeometry, $childGeometry = false) |
{ |
if (!$childGeometry) { |
$childGeometry = $rootGeometry; |
} |
$params = array(); |
$geometry = array(); |
foreach ($rootGeometry as $key => $val) { |
$geometry["'$key'"][] = $val; |
$incr = false; |
if (strpos($val, ',') !== false) { |
list($start, $interval) = explode(',',$val); |
$incr = true; |
} |
$ratio = false; |
if ($key == 'width' && strpos($val, '*') !== false) { |
$ratio = trim(str_replace('*','', $val)); |
} |
if ($incr) { |
$val = trim($interval); |
if ($key == 'left' && preg_match('/[+-]/', $interval)) { |
$val = $params[0]['width'] + trim($val); |
} |
} elseif ($incr) { |
$val = trim($start); |
} elseif ($ratio) { |
$val = $ratio * $this->_strlenByLevel[0]; |
} |
$geometry["'$key'"][0] = $val; |
$params[0][$key] = $val; |
} |
foreach($childGeometry as $key => $val) { |
$incr = false; |
if (strpos($val, ',') !== false) { |
list($start, $interval) = explode(',', $val); |
$incr = true; |
} |
$ratio = false; |
if ($key == 'width' && strpos($val, '*') !== false) { |
$ratio = trim(str_replace('*', '', $val)); |
} |
for ($i = 1; $i <= $this->_levels; $i++) { |
if ($incr && isset($lastval[$key])) { |
$val = trim($interval); |
if($key == 'block_left' && preg_match('/[+-]/', $interval)) { |
$val = $params[$i - 1]['width'] + trim($val); |
} |
} elseif($incr) { |
$val = trim($start); |
} elseif ($ratio) { |
$val = $ratio * $this->_strlenByLevel[$i]; |
if($val < $params[0]['width']) { |
$val = $params[0]['width']; |
} |
} |
$lastval[$key] = $val; |
$geometry["'$key'"][] = $val; |
$params[$i][$key] = $val; |
} |
} |
$pos = false; |
$pos = $pos . 'var MENU_POS'.$menu_id." = new Array();\n"; |
foreach ($geometry as $key => $val) { |
$pos = $pos . 'MENU_POS' . $menu_id . "[$key] = [" . implode(', ', $val) . "];\n"; |
} |
return $pos; |
} |
// }}} |
// {{{ printTree() |
/** |
* Print's the current tree using the output driver |
* |
* @access public |
*/ |
function printTree() |
{ |
if (!$options = $this->_getOptions('printTree')) { |
return PEAR::raiseError("TigraMenu::printTree() needs options. See TigraMenu::setOptions()", NESEO_ERROR_NO_OPTIONS, PEAR_ERROR_TRIGGER, E_USER_ERROR); |
} |
echo $this->_openMenu($options['menu_id']) . $this->_structTigraMenu .$this->_closeMenu(); |
echo "\n\n"; |
echo $this->_addStyles($options['menu_id'], $options['rootStyles'], $options['childStyles']); |
echo "\n\n"; |
echo $this->_addGeometry($options['menu_id'], $options['rootGeometry'], $options['childGeometry']); |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/DataObject/Generator.php |
---|
New file |
0,0 → 1,929 |
<?php |
/** |
* Generation tools for DB_DataObject |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Generator.php,v 1.96 2005/06/16 02:03:45 alan_k Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
/** |
* |
* Config _$ptions |
* [DB_DataObject_Generator] |
* ; optional default = DB/DataObject.php |
* extends_location = |
* ; optional default = DB_DataObject |
* extends = |
* ; alter the extends field when updating a class (defaults to only replacing DB_DataObject) |
* generator_class_rewrite = ANY|specific_name // default is DB_DataObject |
* |
*/ |
/** |
* Needed classes |
*/ |
require_once 'DB/DataObject.php'; |
//require_once('Config.php'); |
/** |
* Generator class |
* |
* @package DB_DataObject |
*/ |
class DB_DataObject_Generator extends DB_DataObject |
{ |
/* =========================================================== */ |
/* Utility functions - for building db config files */ |
/* =========================================================== */ |
/** |
* Array of table names |
* |
* @var array |
* @access private |
*/ |
var $tables; |
/** |
* associative array table -> array of table row objects |
* |
* @var array |
* @access private |
*/ |
var $_definitions; |
/** |
* active table being output |
* |
* @var string |
* @access private |
*/ |
var $table; // active tablename |
/** |
* The 'starter' = call this to start the process |
* |
* @access public |
* @return none |
*/ |
function start() |
{ |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$databases = array(); |
foreach($options as $k=>$v) { |
if (substr($k,0,9) == 'database_') { |
$databases[substr($k,9)] = $v; |
} |
} |
if (@$options['database']) { |
require_once 'DB.php'; |
$dsn = DB::parseDSN($options['database']); |
if (!isset($database[$dsn['database']])) { |
$databases[$dsn['database']] = $options['database']; |
} |
} |
foreach($databases as $databasename => $database) { |
if (!$database) { |
continue; |
} |
$this->debug("CREATING FOR $databasename\n"); |
$class = get_class($this); |
$t = new $class; |
$t->_database_dsn = $database; |
$t->_database = $databasename; |
$dsn = DB::parseDSN($database); |
if (($dsn['phptype'] == 'sqlite') && is_file($databasename)) { |
$t->_database = basename($t->_database); |
} |
$t->_createTableList(); |
foreach(get_class_methods($class) as $method) { |
if (substr($method,0,8 ) != 'generate') { |
continue; |
} |
$this->debug("calling $method"); |
$t->$method(); |
} |
} |
$this->debug("DONE\n\n"); |
} |
/** |
* Output File was config object, now just string |
* Used to generate the Tables |
* |
* @var string outputbuffer for table definitions |
* @access private |
*/ |
var $_newConfig; |
/** |
* Build a list of tables; |
* Currently this is very Mysql Specific - ideas for more generic stiff welcome |
* |
* @access private |
* @return none |
*/ |
function _createTableList() |
{ |
$this->_connect(); |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5]; |
// try getting a list of schema tables first. (postgres) |
$__DB->expectError(DB_ERROR_UNSUPPORTED); |
$this->tables = $__DB->getListOf('schema.tables'); |
$__DB->popExpect(); |
if (empty($this->tables) || is_a($this->tables , 'PEAR_Error')) { |
//if that fails fall back to clasic tables list. |
$this->tables = $__DB->getListOf('tables'); |
} |
if (is_a($this->tables , 'PEAR_Error')) { |
return PEAR::raiseError($this->tables->toString(), null, PEAR_ERROR_DIE); |
} |
// build views as well if asked to. |
if (!empty($options['build_views'])) { |
$views = $__DB->getListOf('views'); |
if (is_a($views,'PEAR_Error')) { |
return PEAR::raiseError( |
'Error getting Views (check the PEAR bug database for the fix to DB), ' . |
$views->toString(), |
null, |
PEAR_ERROR_DIE |
); |
} |
$this->tables = array_merge ($this->tables, $views); |
} |
// declare a temporary table to be filled with matching tables names |
$tmp_table = array(); |
foreach($this->tables as $table) { |
if (isset($options['generator_include_regex']) && |
!preg_match($options['generator_include_regex'],$table)) { |
continue; |
} else if (isset($options['generator_exclude_regex']) && |
preg_match($options['generator_exclude_regex'],$table)) { |
continue; |
} |
// postgres strip the schema bit from the |
if (!empty($options['generator_strip_schema'])) { |
$bits = explode('.', $table,2); |
$table = $bits[0]; |
if (count($bits) > 1) { |
$table = $bits[1]; |
} |
} |
$defs = $__DB->tableInfo($table); |
if (is_a($defs,'PEAR_Error')) { |
echo $defs->toString(); |
exit; |
} |
// cast all definitions to objects - as we deal with that better. |
foreach($defs as $def) { |
if (!is_array($def)) { |
continue; |
} |
$this->_definitions[$table][] = (object) $def; |
} |
// we find a matching table, just store it into a temporary array |
$tmp_table[] = $table; |
} |
// the temporary table array is now the right one (tables names matching |
// with regex expressions have been removed) |
$this->tables = $tmp_table; |
//print_r($this->_definitions); |
} |
/** |
* Auto generation of table data. |
* |
* it will output to db_oo_{database} the table definitions |
* |
* @access private |
* @return none |
*/ |
function generateDefinitions() |
{ |
$this->debug("Generating Definitions file: "); |
if (!$this->tables) { |
$this->debug("-- NO TABLES -- \n"); |
return; |
} |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
//$this->_newConfig = new Config('IniFile'); |
$this->_newConfig = ''; |
foreach($this->tables as $this->table) { |
$this->_generateDefinitionsTable(); |
} |
$this->_connect(); |
// dont generate a schema if location is not set |
// it's created on the fly! |
if (!@$options['schema_location'] && @!$options["ini_{$this->_database}"] ) { |
return; |
} |
$base = @$options['schema_location']; |
if (isset($options["ini_{$this->_database}"])) { |
$file = $options["ini_{$this->_database}"]; |
} else { |
$file = "{$base}/{$this->_database}.ini"; |
} |
if (!file_exists(dirname($file))) { |
require_once 'System.php'; |
System::mkdir(array('-p','-m',0755,dirname($file))); |
} |
$this->debug("Writing ini as {$file}\n"); |
touch($file); |
//print_r($this->_newConfig); |
$fh = fopen($file,'w'); |
fwrite($fh,$this->_newConfig); |
fclose($fh); |
//$ret = $this->_newConfig->writeInput($file,false); |
//if (PEAR::isError($ret) ) { |
// return PEAR::raiseError($ret->message,null,PEAR_ERROR_DIE); |
// } |
} |
/** |
* The table geneation part |
* |
* @access private |
* @return tabledef and keys array. |
*/ |
function _generateDefinitionsTable() |
{ |
global $_DB_DATAOBJECT; |
$defs = $this->_definitions[$this->table]; |
$this->_newConfig .= "\n[{$this->table}]\n"; |
$keys_out = "\n[{$this->table}__keys]\n"; |
$keys_out_primary = ''; |
$keys_out_secondary = ''; |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) { |
echo "TABLE STRUCTURE FOR {$this->table}\n"; |
print_r($defs); |
} |
$DB = $this->getDatabaseConnection(); |
$dbtype = $DB->phptype; |
$ret = array( |
'table' => array(), |
'keys' => array(), |
); |
$ret_keys_primary = array(); |
$ret_keys_secondary = array(); |
foreach($defs as $t) { |
$n=0; |
switch (strtoupper($t->type)) { |
case 'INT': |
case 'INT2': // postgres |
case 'INT4': // postgres |
case 'INT8': // postgres |
case 'SERIAL4': // postgres |
case 'SERIAL8': // postgres |
case 'INTEGER': |
case 'TINYINT': |
case 'SMALLINT': |
case 'MEDIUMINT': |
case 'BIGINT': |
$type = DB_DATAOBJECT_INT; |
if ($t->len == 1) { |
$type += DB_DATAOBJECT_BOOL; |
} |
break; |
case 'REAL': |
case 'DOUBLE': |
case 'FLOAT': |
case 'FLOAT8': // double precision (postgres) |
case 'DECIMAL': |
case 'NUMERIC': |
case 'NUMBER': // oci8 |
$type = DB_DATAOBJECT_INT; // should really by FLOAT!!! / MONEY... |
break; |
case 'YEAR': |
$type = DB_DATAOBJECT_INT; |
break; |
case 'BIT': |
case 'BOOL': |
case 'BOOLEAN': |
$type = DB_DATAOBJECT_BOOL; |
// postgres needs to quote '0' |
if ($dbtype == 'pgsql') { |
$type += DB_DATAOBJECT_STR; |
} |
break; |
case 'STRING': |
case 'CHAR': |
case 'VARCHAR': |
case 'VARCHAR2': |
case 'TINYTEXT': |
case 'ENUM': |
case 'SET': // not really but oh well |
case 'TIMESTAMPTZ': // postgres |
case 'BPCHAR': // postgres |
case 'INTERVAL': // postgres (eg. '12 days') |
case 'CIDR': // postgres IP net spec |
case 'INET': // postgres IP |
case 'MACADDR': // postgress network Mac address. |
$type = DB_DATAOBJECT_STR; |
break; |
case 'TEXT': |
case 'MEDIUMTEXT': |
case 'LONGTEXT': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT; |
break; |
case 'DATE': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE; |
break; |
case 'TIME': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TIME; |
break; |
case 'DATETIME': |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME; |
break; |
case 'TIMESTAMP': // do other databases use this??? |
$type = ($dbtype == 'mysql') ? |
DB_DATAOBJECT_MYSQLTIMESTAMP : |
DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME; |
break; |
case 'TINYBLOB': |
case 'BLOB': /// these should really be ignored!!!??? |
case 'MEDIUMBLOB': |
case 'LONGBLOB': |
case 'BYTEA': // postgres blob support.. |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_BLOB; |
break; |
} |
if (!strlen(trim($t->name))) { |
continue; |
} |
if (preg_match('/not_null/i',$t->flags)) { |
$type += DB_DATAOBJECT_NOTNULL; |
} |
$write_ini = true; |
if (in_array($t->name,array('null','yes','no','true','false'))) { |
echo "*****************************************************************\n". |
"** WARNING **\n". |
"** Found column '{$t->name}', which is invalid in an .ini file **\n". |
"** This line will not be writen to the file - you will have **\n". |
"** define the keys()/method manually. **\n". |
"*****************************************************************\n"; |
$write_ini = false; |
} else { |
$this->_newConfig .= "{$t->name} = $type\n"; |
} |
$ret['table'][$t->name] = $type; |
// i've no idea if this will work well on other databases? |
// only use primary key or nextval(), cause the setFrom blocks you setting all key items... |
// if no keys exist fall back to using unique |
//echo "\n{$t->name} => {$t->flags}\n"; |
if (preg_match("/(auto_increment|nextval\()/i",rawurldecode($t->flags))) { |
// native sequences = 2 |
if ($write_ini) { |
$keys_out_primary .= "{$t->name} = N\n"; |
} |
$ret_keys_primary[$t->name] = 'N'; |
} else if (preg_match("/(primary|unique)/i",$t->flags)) { |
// keys.. = 1 |
if ($write_ini) { |
$keys_out_secondary .= "{$t->name} = K\n"; |
} |
$ret_keys_secondary[$t->name] = 'K'; |
} |
} |
$this->_newConfig .= $keys_out . (empty($keys_out_primary) ? $keys_out_secondary : $keys_out_primary); |
$ret['keys'] = empty($keys_out_primary) ? $ret_keys_secondary : $ret_keys_primary; |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) { |
print_r(array("dump for {$this->table}", $ret)); |
} |
return $ret; |
} |
/* |
* building the class files |
* for each of the tables output a file! |
*/ |
function generateClasses() |
{ |
//echo "Generating Class files: \n"; |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$base = $options['class_location']; |
if (strpos($base,'%s') !== false) { |
$base = dirname($base); |
} |
if (!file_exists($base)) { |
require_once 'System.php'; |
System::mkdir(array('-p',$base)); |
} |
$class_prefix = $options['class_prefix']; |
if ($extends = @$options['extends']) { |
$this->_extends = $extends; |
$this->_extendsFile = $options['extends_location']; |
} |
foreach($this->tables as $this->table) { |
$this->table = trim($this->table); |
$this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)); |
$i = ''; |
if (strpos($options['class_location'],'%s') !== false) { |
$outfilename = sprintf($options['class_location'], preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table))); |
} else { |
$outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)).".php"; |
} |
$oldcontents = ''; |
if (file_exists($outfilename)) { |
// file_get_contents??? |
$oldcontents = implode('',file($outfilename)); |
} |
$out = $this->_generateClassTable($oldcontents); |
$this->debug( "writing $this->classname\n"); |
$fh = fopen($outfilename, "w"); |
fputs($fh,$out); |
fclose($fh); |
} |
//echo $out; |
} |
/** |
* class being extended (can be overridden by [DB_DataObject_Generator] extends=xxxx |
* |
* @var string |
* @access private |
*/ |
var $_extends = 'DB_DataObject'; |
/** |
* line to use for require('DB/DataObject.php'); |
* |
* @var string |
* @access private |
*/ |
var $_extendsFile = "DB/DataObject.php"; |
/** |
* class being generated |
* |
* @var string |
* @access private |
*/ |
var $_className; |
/** |
* The table class geneation part - single file. |
* |
* @access private |
* @return none |
*/ |
function _generateClassTable($input = '') |
{ |
// title = expand me! |
$foot = ""; |
$head = "<?php\n/**\n * Table Definition for {$this->table}\n */\n"; |
// requires |
$head .= "require_once '{$this->_extendsFile}';\n\n"; |
// add dummy class header in... |
// class |
$head .= "class {$this->classname} extends {$this->_extends} \n{"; |
$body = "\n ###START_AUTOCODE\n"; |
$body .= " /* the code below is auto generated do not remove the above tag */\n\n"; |
// table |
$padding = (30 - strlen($this->table)); |
if ($padding < 2) $padding =2; |
$p = str_repeat(' ',$padding) ; |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var'; |
$body .= " {$var} \$__table = '{$this->table}'; {$p}// table name\n"; |
// if we are using the option database_{databasename} = dsn |
// then we should add var $_database = here |
// as database names may not always match.. |
if (isset($options["database_{$this->_database}"])) { |
$body .= " {$var} \$_database = '{$this->_database}'; {$p}// database name (used with database_{*} config)\n"; |
} |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var'; |
if (!empty($options['generator_novars'])) { |
$var = '//'.$var; |
} |
$defs = $this->_definitions[$this->table]; |
// show nice information! |
$connections = array(); |
$sets = array(); |
foreach($defs as $t) { |
if (!strlen(trim($t->name))) { |
continue; |
} |
$padding = (30 - strlen($t->name)); |
if ($padding < 2) $padding =2; |
$p = str_repeat(' ',$padding) ; |
$body .=" {$var} \${$t->name}; {$p}// {$t->type}({$t->len}) {$t->flags}\n"; |
// can not do set as PEAR::DB table info doesnt support it. |
//if (substr($t->Type,0,3) == "set") |
// $sets[$t->Field] = "array".substr($t->Type,3); |
$body .= $this->derivedHookVar($t,$padding); |
} |
// THIS IS TOTALLY BORKED old FC creation |
// IT WILL BE REMOVED!!!!! in DataObjects 1.6 |
// grep -r __clone * to find all it's uses |
// and replace them with $x = clone($y); |
// due to the change in the PHP5 clone design. |
if ( substr(phpversion(),0,1) < 5) { |
$body .= "\n"; |
$body .= " /* ZE2 compatibility trick*/\n"; |
$body .= " function __clone() { return \$this;}\n"; |
} |
// simple creation tools ! (static stuff!) |
$body .= "\n"; |
$body .= " /* Static get */\n"; |
$body .= " function staticGet(\$k,\$v=NULL) { return DB_DataObject::staticGet('{$this->classname}',\$k,\$v); }\n"; |
// generate getter and setter methods |
$body .= $this->_generateGetters($input); |
$body .= $this->_generateSetters($input); |
/* |
theoretically there is scope here to introduce 'list' methods |
based up 'xxxx_up' column!!! for heiracitcal trees.. |
*/ |
// set methods |
//foreach ($sets as $k=>$v) { |
// $kk = strtoupper($k); |
// $body .=" function getSets{$k}() { return {$v}; }\n"; |
//} |
$body .= $this->derivedHookFunctions(); |
$body .= "\n /* the code above is auto generated do not remove the tag below */"; |
$body .= "\n ###END_AUTOCODE\n"; |
// stubs.. |
if (!empty($options['generator_add_validate_stubs'])) { |
foreach($defs as $t) { |
if (!strlen(trim($t->name))) { |
continue; |
} |
$validate_fname = 'validate' . ucfirst(strtolower($t->name)); |
// dont re-add it.. |
if (preg_match('/\s+function\s+' . $validate_fname . '\s*\(/i', $input)) { |
continue; |
} |
$body .= "\n function {$validate_fname}()\n {\n return false;\n }\n"; |
} |
} |
$foot .= "}\n"; |
$full = $head . $body . $foot; |
if (!$input) { |
return $full; |
} |
if (!preg_match('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n)/s',$input)) { |
return $full; |
} |
if (!preg_match('/(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',$input)) { |
return $full; |
} |
/* this will only replace extends DB_DataObject by default, |
unless use set generator_class_rewrite to ANY or a name*/ |
$class_rewrite = 'DB_DataObject'; |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
if (!($class_rewrite = @$options['generator_class_rewrite'])) { |
$class_rewrite = 'DB_DataObject'; |
} |
if ($class_rewrite == 'ANY') { |
$class_rewrite = '[a-z_]+'; |
} |
$input = preg_replace( |
'/(\n|\r\n)class\s*[a-z0-9_]+\s*extends\s*' .$class_rewrite . '\s*\{(\n|\r\n)/si', |
"\nclass {$this->classname} extends {$this->_extends} \n{\n", |
$input); |
return preg_replace( |
'/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', |
$body,$input); |
} |
/** |
* hook to add extra methods to all classes |
* |
* called once for each class, use with $this->table and |
* $this->_definitions[$this->table], to get data out of the current table, |
* use it to add extra methods to the default classes. |
* |
* @access public |
* @return string added to class eg. functions. |
*/ |
function derivedHookFunctions() |
{ |
// This is so derived generator classes can generate functions |
// It MUST NOT be changed here!!! |
return ""; |
} |
/** |
* hook for var lines |
* called each time a var line is generated, override to add extra var |
* lines |
* |
* @param object t containing type,len,flags etc. from tableInfo call |
* @param int padding number of spaces |
* @access public |
* @return string added to class eg. functions. |
*/ |
function derivedHookVar(&$t,$padding) |
{ |
// This is so derived generator classes can generate variabels |
// It MUST NOT be changed here!!! |
return ""; |
} |
/** |
* getProxyFull - create a class definition on the fly and instantate it.. |
* |
* similar to generated files - but also evals the class definitoin code. |
* |
* |
* @param string database name |
* @param string table name of table to create proxy for. |
* |
* |
* @return object Instance of class. or PEAR Error |
* @access public |
*/ |
function getProxyFull($database,$table) { |
if ($err = $this->fillTableSchema($database,$table)) { |
return $err; |
} |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$class_prefix = $options['class_prefix']; |
if ($extends = @$options['extends']) { |
$this->_extends = $extends; |
$this->_extendsFile = $options['extends_location']; |
} |
$classname = $this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst(trim($this->table))); |
$out = $this->_generateClassTable(); |
//echo $out; |
eval('?>'.$out); |
return new $classname; |
} |
/** |
* fillTableSchema - set the database schema on the fly |
* |
* |
* |
* @param string database name |
* @param string table name of table to create schema info for |
* |
* @return none | PEAR::error() |
* @access public |
*/ |
function fillTableSchema($database,$table) { |
global $_DB_DATAOBJECT; |
$this->_database = $database; |
$this->_connect(); |
$table = trim($table); |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5]; |
$defs = $__DB->tableInfo($table); |
if (PEAR::isError($defs)) { |
return $defs; |
} |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) { |
$this->debug("getting def for $database/$table",'fillTable'); |
$this->debug(print_r($defs,true),'defs'); |
} |
// cast all definitions to objects - as we deal with that better. |
foreach($defs as $def) { |
if (is_array($def)) { |
$this->_definitions[$table][] = (object) $def; |
} |
} |
$this->table = trim($table); |
$ret = $this->_generateDefinitionsTable(); |
$_DB_DATAOBJECT['INI'][$database][$table] = $ret['table']; |
$_DB_DATAOBJECT['INI'][$database][$table.'__keys'] = $ret['keys']; |
return false; |
} |
/** |
* Generate getter methods for class definition |
* |
* @param string $input Existing class contents |
* @return string |
* @access public |
*/ |
function _generateGetters($input) { |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$getters = ''; |
// only generate if option is set to true |
if (empty($options['generate_getters'])) { |
return ''; |
} |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input); |
$getters .= "\n\n"; |
$defs = $this->_definitions[$this->table]; |
// loop through properties and create getter methods |
foreach ($defs = $defs as $t) { |
// build mehtod name |
$methodName = 'get' . ucfirst($t->name); |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) { |
continue; |
} |
$getters .= " /**\n"; |
$getters .= " * Getter for \${$t->name}\n"; |
$getters .= " *\n"; |
$getters .= (stristr($t->flags, 'multiple_key')) ? " * @return object\n" |
: " * @return {$t->type}\n"; |
$getters .= " * @access public\n"; |
$getters .= " */\n"; |
$getters .= (substr(phpversion(),0,1) > 4) ? ' public ' |
: ' '; |
$getters .= "function $methodName() {\n"; |
$getters .= " return \$this->{$t->name};\n"; |
$getters .= " }\n\n"; |
} |
return $getters; |
} |
/** |
* Generate setter methods for class definition |
* |
* @param string Existing class contents |
* @return string |
* @access public |
*/ |
function _generateSetters($input) { |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
$setters = ''; |
// only generate if option is set to true |
if (empty($options['generate_setters'])) { |
return ''; |
} |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input); |
$setters .= "\n"; |
$defs = $this->_definitions[$this->table]; |
// loop through properties and create setter methods |
foreach ($defs = $defs as $t) { |
// build mehtod name |
$methodName = 'set' . ucfirst($t->name); |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) { |
continue; |
} |
$setters .= " /**\n"; |
$setters .= " * Setter for \${$t->name}\n"; |
$setters .= " *\n"; |
$setters .= " * @param mixed input value\n"; |
$setters .= " * @access public\n"; |
$setters .= " */\n"; |
$setters .= (substr(phpversion(),0,1) > 4) ? ' public ' |
: ' '; |
$setters .= "function $methodName(\$value) {\n"; |
$setters .= " \$this->{$t->name} = \$value;\n"; |
$setters .= " }\n\n"; |
} |
return $setters; |
} |
} |
/trunk/bibliotheque/pear/DB/DataObject/Error.php |
---|
New file |
0,0 → 1,53 |
<?php |
/** |
* DataObjects error handler, loaded on demand... |
* |
* DB_DataObject_Error is a quick wrapper around pear error, so you can distinguish the |
* error code source. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Error.php,v 1.3 2005/03/23 02:35:35 alan_k Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
class DB_DataObject_Error extends PEAR_Error |
{ |
/** |
* DB_DataObject_Error constructor. |
* |
* @param mixed $code DB error code, or string with error message. |
* @param integer $mode what "error mode" to operate in |
* @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER |
* @param mixed $debuginfo additional debug info, such as the last query |
* |
* @access public |
* |
* @see PEAR_Error |
*/ |
function DB_DataObject_Error($message = '', $code = DB_ERROR, $mode = PEAR_ERROR_RETURN, |
$level = E_USER_NOTICE) |
{ |
$this->PEAR_Error('DB_DataObject Error: ' . $message, $code, $mode, $level); |
} |
// todo : - support code -> message handling, and translated error messages... |
} |
/trunk/bibliotheque/pear/DB/DataObject/Cast.php |
---|
New file |
0,0 → 1,546 |
<?php |
/** |
* Prototype Castable Object.. for DataObject queries |
* |
* Storage for Data that may be cast into a variety of formats. |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_DataObject |
* @author Alan Knowles <alan@akbkhome.com> |
* @copyright 1997-2005 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Cast.php,v 1.15 2005/07/07 05:30:53 alan_k Exp $ |
* @link http://pear.php.net/package/DB_DataObject |
*/ |
/** |
* |
* Common usages: |
* // blobs |
* $data = DB_DataObject_Cast::blob($somefile); |
* $data = DB_DataObject_Cast::string($somefile); |
* $dataObject->someblobfield = $data |
* |
* // dates? |
* $d1 = new DB_DataObject_Cast::date('12/12/2000'); |
* $d2 = new DB_DataObject_Cast::date(2000,12,30); |
* $d3 = new DB_DataObject_Cast::date($d1->year, $d1->month+30, $d1->day+30); |
* |
* // time, datetime.. ????????? |
* |
* // raw sql???? |
* $data = DB_DataObject_Cast::sql('cast("123123",datetime)'); |
* $data = DB_DataObject_Cast::sql('NULL'); |
* |
* // int's/string etc. are proably pretty pointless..!!!! |
* |
* |
* inside DB_DataObject, |
* if (is_a($v,'db_dataobject_class')) { |
* $value .= $v->toString(DB_DATAOBJECT_INT,'mysql'); |
* } |
* |
* |
* |
* |
*/ |
class DB_DataObject_Cast { |
/** |
* Type of data Stored in the object.. |
* |
* @var string (date|blob|.....?) |
* @access public |
*/ |
var $type; |
/** |
* Data For date representation |
* |
* @var int day/month/year |
* @access public |
*/ |
var $day; |
var $month; |
var $year; |
/** |
* Generic Data.. |
* |
* @var string |
* @access public |
*/ |
var $value; |
/** |
* Blob consructor |
* |
* create a Cast object from some raw data.. (binary) |
* |
* |
* @param string (with binary data!) |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function blob($value) { |
$r = new DB_DataObject_Cast; |
$r->type = 'blob'; |
$r->value = $value; |
return $r; |
} |
/** |
* String consructor (actually use if for ints and everything else!!! |
* |
* create a Cast object from some string (not binary) |
* |
* |
* @param string (with binary data!) |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function string($value) { |
$r = new DB_DataObject_Cast; |
$r->type = 'string'; |
$r->value = $value; |
return $r; |
} |
/** |
* SQL constructor (for raw SQL insert) |
* |
* create a Cast object from some sql |
* |
* @param string (with binary data!) |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function sql($value) |
{ |
$r = new DB_DataObject_Cast; |
$r->type = 'sql'; |
$r->value = $value; |
return $r; |
} |
/** |
* Date Constructor |
* |
* create a Cast object from some string (not binary) |
* NO VALIDATION DONE, although some crappy re-calcing done! |
* |
* @param vargs... accepts |
* dd/mm |
* dd/mm/yyyy |
* yyyy-mm |
* yyyy-mm-dd |
* array(yyyy,dd) |
* array(yyyy,dd,mm) |
* |
* |
* |
* @return object DB_DataObject_Cast |
* @access public |
*/ |
function date() |
{ |
$args = func_get_args(); |
switch(count($args)) { |
case 0: // no args = today! |
$bits = explode('-',date('Y-m-d')); |
break; |
case 1: // one arg = a string |
if (strpos($args[0],'/') !== false) { |
$bits = array_reverse(explode('/',$args[0])); |
} else { |
$bits = explode('-',$args[0]); |
} |
break; |
default: // 2 or more.. |
$bits = $args; |
} |
if (count($bits) == 1) { // if YYYY set day = 1st.. |
$bits[] = 1; |
} |
if (count($bits) == 2) { // if YYYY-DD set day = 1st.. |
$bits[] = 1; |
} |
// if year < 1970 we cant use system tools to check it... |
// so we make a few best gueses.... |
// basically do date calculations for the year 2000!!! |
// fix me if anyone has more time... |
if (($bits[0] < 1975) || ($bits[0] > 2030)) { |
$oldyear = $bits[0]; |
$bits = explode('-',date('Y-m-d',mktime(1,1,1,$bits[1],$bits[2],2000))); |
$bits[0] = ($bits[0] - 2000) + $oldyear; |
} else { |
// now mktime |
$bits = explode('-',date('Y-m-d',mktime(1,1,1,$bits[1],$bits[2],$bits[0]))); |
} |
$r = new DB_DataObject_Cast; |
$r->type = 'date'; |
list($r->year,$r->month,$r->day) = $bits; |
return $r; |
} |
/** |
* Data For time representation ** does not handle timezones!! |
* |
* @var int hour/minute/second |
* @access public |
*/ |
var $hour; |
var $minute; |
var $second; |
/** |
* DateTime Constructor |
* |
* create a Cast object from a Date/Time |
* Maybe should accept a Date object.! |
* NO VALIDATION DONE, although some crappy re-calcing done! |
* |
* @param vargs... accepts |
* noargs (now) |
* yyyy-mm-dd HH:MM:SS (Iso) |
* array(yyyy,mm,dd,HH,MM,SS) |
* |
* |
* @return object DB_DataObject_Cast |
* @access public |
* @author therion 5 at hotmail |
*/ |
function dateTime() |
{ |
$args = func_get_args(); |
switch(count($args)) { |
case 0: // no args = now! |
$datetime = date('Y-m-d G:i:s', mktime()); |
case 1: |
// continue on from 0 args. |
if (!isset($datetime)) { |
$datetime = $args[0]; |
} |
$parts = explode(' ', $datetime); |
$bits = explode('-', $parts[0]); |
$bits = array_merge($bits, explode(':', $parts[1])); |
break; |
default: // 2 or more.. |
$bits = $args; |
} |
if (count($bits) != 6) { |
// PEAR ERROR? |
return false; |
} |
$r = DB_DataObject_Cast::date($bits[0], $bits[1], $bits[2]); |
if (!$r) { |
return $r; // pass thru error (False) - doesnt happen at present! |
} |
// change the type! |
$r->type = 'datetime'; |
// should we mathematically sort this out.. |
// (or just assume that no-one's dumb enough to enter 26:90:90 as a time! |
$r->hour = $bits[3]; |
$r->minute = $bits[4]; |
$r->second = $bits[5]; |
return $r; |
} |
/** |
* time Constructor |
* |
* create a Cast object from a Date/Time |
* Maybe should accept a Date object.! |
* NO VALIDATION DONE, and no-recalcing done! |
* |
* @param vargs... accepts |
* noargs (now) |
* HH:MM:SS (Iso) |
* array(HH,MM,SS) |
* |
* |
* @return object DB_DataObject_Cast |
* @access public |
* @author therion 5 at hotmail |
*/ |
function time() |
{ |
$args = func_get_args(); |
switch (count($args)) { |
case 0: // no args = now! |
$time = date('G:i:s', mktime()); |
case 1: |
// continue on from 0 args. |
if (!isset($time)) { |
$time = $args[0]; |
} |
$bits = explode(':', $time); |
break; |
default: // 2 or more.. |
$bits = $args; |
} |
if (count($bits) != 3) { |
return false; |
} |
// now take data from bits into object fields |
$r = new DB_DataObject_Cast; |
$r->type = 'time'; |
$r->hour = $bits[0]; |
$r->minute = $bits[1]; |
$r->second = $bits[2]; |
return $r; |
} |
/** |
* get the string to use in the SQL statement for this... |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toString($to=false,$db) |
{ |
// if $this->type is not set, we are in serious trouble!!!! |
// values for to: |
$method = 'toStringFrom'.$this->type; |
return $this->$method($to,$db); |
} |
/** |
* get the string to use in the SQL statement from a blob of binary data |
* ** Suppots only blob->postgres::bytea |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromBlob($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
if (!($to & DB_DATAOBJECT_BLOB)) { |
return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::blob to something other than a blob!'); |
} |
switch ($db->dsn["phptype"]) { |
case 'pgsql': |
return "'".pg_escape_bytea($this->value)."'::bytea"; |
case 'mysql': |
return "'".mysql_real_escape_string($this->value,$db->connection)."'"; |
case 'mysqli': |
// this is funny - the parameter order is reversed ;) |
return "'".mysqli_real_escape_string($db->connection, $this->value)."'"; |
default: |
return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet"); |
} |
} |
/** |
* get the string to use in the SQL statement for a blob from a string! |
* ** Suppots only string->postgres::bytea |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromString($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
// |
if (!($to & DB_DATAOBJECT_BLOB)) { |
return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a blob!'. |
' (why not just use native features)'); |
} |
switch ($db->dsn['phptype']) { |
case 'pgsql': |
return "'".pg_escape_string($this->value)."'::bytea"; |
case 'mysql': |
return "'".mysql_real_escape_string($this->value,$db->connection)."'"; |
case 'mysqli': |
return "'".mysqli_real_escape_string($db->connection, $this->value)."'"; |
default: |
return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet"); |
} |
} |
/** |
* get the string to use in the SQL statement for a date |
* |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromDate($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
// |
if (($to !== false) && !($to & DB_DATAOBJECT_DATE)) { |
return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a date!'. |
' (why not just use native features)'); |
} |
return "'{$this->year}-{$this->month}-{$this->day}'"; |
} |
/** |
* get the string to use in the SQL statement for a datetime |
* |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
* @author therion 5 at hotmail |
*/ |
function toStringFromDateTime($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
if (($to !== false) && |
!($to & (DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME))) { |
return PEAR::raiseError('Invalid Cast from a ' . |
' DB_DataObject_Cast::dateTime to something other than a datetime!' . |
' (try using native features)'); |
} |
return "'{$this->year}-{$this->month}-{$this->day} {$this->hour}:{$this->minute}:{$this->second}'"; |
} |
/** |
* get the string to use in the SQL statement for a time |
* |
* |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
* @author therion 5 at hotmail |
*/ |
function toStringFromTime($to,$db) |
{ |
// first weed out invalid casts.. |
// in blobs can only be cast to blobs.! |
// perhaps we should support TEXT fields??? |
if (($to !== false) && !($to & DB_DATAOBJECT_TIME)) { |
return PEAR::raiseError('Invalid Cast from a' . |
' DB_DataObject_Cast::time to something other than a time!'. |
' (try using native features)'); |
} |
return "'{$this->hour}:{$this->minute}:{$this->second}'"; |
} |
/** |
* get the string to use in the SQL statement for a raw sql statement. |
* |
* @param int $to Type (DB_DATAOBJECT_* |
* @param object $db DB Connection Object |
* |
* |
* @return string |
* @access public |
*/ |
function toStringFromSql($to,$db) |
{ |
return $this->value; |
} |
} |
/trunk/bibliotheque/pear/DB/DataObject/createTables.php |
---|
New file |
0,0 → 1,55 |
#!/usr/bin/php -q |
<?php |
// +----------------------------------------------------------------------+ |
// | PHP Version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2003 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.02 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Author: Alan Knowles <alan@akbkhome.com> |
// +----------------------------------------------------------------------+ |
// |
// $Id: createTables.php,v 1.23 2005/05/04 14:13:57 alan_k Exp $ |
// |
// since this version doesnt use overload, |
// and I assume anyone using custom generators should add this.. |
define('DB_DATAOBJECT_NO_OVERLOAD',1); |
require_once 'DB/DataObject/Generator.php'; |
if (!ini_get('register_argc_argv')) { |
PEAR::raiseError("\nERROR: You must turn register_argc_argv On in you php.ini file for this to work\neg.\n\nregister_argc_argv = On\n\n", null, PEAR_ERROR_DIE); |
exit; |
} |
if (!@$_SERVER['argv'][1]) { |
PEAR::raiseError("\nERROR: createTable.php usage:\n\nC:\php\pear\DB\DataObjects\createTable.php example.ini\n\n", null, PEAR_ERROR_DIE); |
exit; |
} |
$config = parse_ini_file($_SERVER['argv'][1], true); |
foreach($config as $class=>$values) { |
$options = &PEAR::getStaticProperty($class,'options'); |
$options = $values; |
} |
$options = &PEAR::getStaticProperty('DB_DataObject','options'); |
if (empty($options)) { |
PEAR::raiseError("\nERROR: could not read ini file\n\n", null, PEAR_ERROR_DIE); |
exit; |
} |
set_time_limit(0); |
DB_DataObject::debugLevel(1); |
$generator = new DB_DataObject_Generator; |
$generator->start(); |
/trunk/bibliotheque/pear/DB/QueryTool/Query.php |
---|
New file |
0,0 → 1,2395 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_Query class |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Query.php,v 1.57 2005/02/27 19:13:19 quipo Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* require the PEAR and DB classes |
*/ |
require_once 'PEAR.php'; |
require_once 'DB.php'; |
/** |
* DB_QueryTool_Query class |
* |
* This class should be extended |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Query |
{ |
// {{{ class vars |
/** |
* @var string the name of the primary column |
*/ |
var $primaryCol = 'id'; |
/** |
* @var string the current table the class works on |
*/ |
var $table = ''; |
/** |
* @var string the name of the sequence for this table |
*/ |
var $sequenceName = null; |
/** |
* @var object the db-object, a PEAR::DB instance |
*/ |
var $db = null; |
/** |
* @var string the where condition |
* @access private |
*/ |
var $_where = ''; |
/** |
* @var string the order condition |
* @access private |
*/ |
var $_order = ''; |
/** |
* @var string the having definition |
* @access private |
*/ |
var $_having = ''; |
/** |
* @var array contains the join content |
* the key is the join type, for now we have 'default' and 'left' |
* inside each key 'table' contains the table |
* key 'where' contains the where clause for the join |
* @access private |
*/ |
var $_join = array(); |
/** |
* @var string which column to index the result by |
* @access private |
*/ |
var $_index = null; |
/** |
* @var string the group-by clause |
* @access private |
*/ |
var $_group = ''; |
/** |
* @var array the limit |
* @access private |
*/ |
var $_limit = array(); |
/** |
* @var string type of result to return |
* @access private |
*/ |
var $_resultType = 'none'; |
/** |
* @var array the metadata temporary saved |
* @access private |
*/ |
var $_metadata = array(); |
/** |
* @var string |
* @access private |
*/ |
var $_lastQuery = null; |
/** |
* @var string the rows that shall be selected |
* @access private |
*/ |
var $_select = '*'; |
/** |
* @var string the rows that shall not be selected |
* @access private |
*/ |
var $_dontSelect = ''; |
/** |
* @var array this array saves different modes in which this class works |
* i.e. 'raw' means no quoting before saving/updating data |
* @access private |
*/ |
var $options = array( |
'raw' => false, |
'verbose' => true, // set this to false in a productive environment |
// it will produce error-logs if set to true |
'useCache' => false, |
'logFile' => false, |
); |
/** |
* this array contains information about the tables |
* those are |
* - 'name' => the real table name |
* - 'shortName' => the short name used, so that when moving the table i.e. |
* onto a provider's db and u have to rename the tables to |
* longer names this name will be relevant, i.e. when |
* autoJoining, i.e. a table name on your local machine is: |
* 'user' but online it has to be 'applName_user' then the |
* shortName will be used to determine if a column refers to |
* another table, if the colName is 'user_id', it knows the |
* shortName 'user' refers to the table 'applName_user' |
*/ |
var $tableSpec = array(); |
/** |
* this is the regular expression that shall be used to find a table's shortName |
* in a column name, the string found by using this regular expression will be removed |
* from the column name and it will be checked if it is a table name |
* i.e. the default '/_id$/' would find the table name 'user' from the column name 'user_id' |
*/ |
var $_tableNameToShortNamePreg = '/^.*_/'; |
/** |
* @var array this array caches queries that have already been built once |
* to reduce the execution time |
*/ |
var $_queryCache = array(); |
/** |
* The object that contains the log-instance |
*/ |
var $_logObject = null; |
/** |
* Some internal data the logging needs |
*/ |
var $_logData = array(); |
// }}} |
// {{{ __construct() |
/** |
* this is the constructor, as it will be implemented in ZE2 (php5) |
* |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param object db-object |
*/ |
/* |
function __construct($dsn=false, $options=array()) |
{ |
if (!isset($options['autoConnect'])) { |
$autoConnect = true; |
} else { |
$autoConnect = $options['autoConnect']; |
} |
if (isset($options['errorCallback'])) { |
$this->setErrorCallback($options['errorCallback']); |
} |
if (isset($options['errorSetCallback'])) { |
$this->setErrorSetCallback($options['errorSetCallback']); |
} |
if (isset($options['errorLogCallback'])) { |
$this->setErrorLogCallback($options['errorLogCallback']); |
} |
if ($autoConnect && $dsn) { |
$this->connect($dsn, $options); |
} |
//we would need to parse the dsn first ... i dont feel like now :-) |
// oracle has all column names in upper case |
//FIXXXME make the class work only with upper case when we work with oracle |
//if ($this->db->phptype=='oci8' && !$this->primaryCol) { |
// $this->primaryCol = 'ID'; |
//} |
if ($this->sequenceName == null) { |
$this->sequenceName = $this->table; |
} |
} |
*/ |
// }}} |
// {{{ DB_QueryTool_Query() |
/** |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed $dsn DSN string, DSN array or DB object |
* @param array $options |
*/ |
function DB_QueryTool_Query($dsn=false, $options=array()) |
{ |
//$this->__construct($dsn, $options); |
if (!isset($options['autoConnect'])) { |
$autoConnect = true; |
} else { |
$autoConnect = $options['autoConnect']; |
unset($options['autoConnect']); |
} |
if (isset($options['errorCallback'])) { |
$this->setErrorCallback($options['errorCallback']); |
unset($options['errorCallback']); |
} |
if (isset($options['errorSetCallback'])) { |
$this->setErrorSetCallback($options['errorSetCallback']); |
unset($options['errorSetCallback']); |
} |
if (isset($options['errorLogCallback'])) { |
$this->setErrorLogCallback($options['errorLogCallback']); |
unset($options['errorLogCallback']); |
} |
if ($autoConnect && $dsn) { |
$this->connect($dsn, $options); |
} |
if (is_null($this->sequenceName)) { |
$this->sequenceName = $this->table; |
} |
} |
// }}} |
// {{{ connect() |
/** |
* use this method if you want to connect manually |
* @param mixed $dsn DSN string, DSN array or MDB object |
* @param array $options |
*/ |
function connect($dsn, $options=array()) |
{ |
if (is_object($dsn)) { |
$res = $this->db =& $dsn; |
} else { |
$res = $this->db = DB::connect($dsn, $options); |
} |
if (DB::isError($res)) { |
// FIXXME what shall we do here? |
$this->_errorLog($res->getUserInfo()); |
} else { |
$this->db->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
} |
// }}} |
// {{{ getDbInstance() |
/** |
* @return reference to current DB instance |
*/ |
function &getDbInstance() |
{ |
return $this->db; |
} |
// }}} |
// {{{ setDbInstance() |
/** |
* Setup using an existing connection. |
* this also sets the DB_FETCHMODE_ASSOC since this class |
* needs this to be set! |
* |
* @param object a reference to an existing DB-object |
* @return void |
*/ |
function setDbInstance(&$dbh) |
{ |
$this->db =& $dbh; |
$this->db->setFetchMode(DB_FETCHMODE_ASSOC); |
} |
// }}} |
// {{{ get() |
/** |
* get the data of a single entry |
* if the second parameter is only one column the result will be returned |
* directly not as an array! |
* |
* @version 2002/03/05 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param integer the id of the element to retrieve |
* @param string if this is given only one row shall be returned, directly, not an array |
* @return mixed (1) an array of the retrieved data |
* (2) if the second parameter is given and its only one column, |
* only this column's data will be returned |
* (3) false in case of failure |
*/ |
function get($id, $column='') |
{ |
$table = $this->table; |
$getMethod = 'getRow'; |
if ($column && !strpos($column, ',')) { // if only one column shall be selected |
$getMethod = 'getOne'; |
} |
// we dont use 'setSelect' here, since this changes the setup of the class, we |
// build the query directly |
// if $column is '' then _buildSelect selects '*' anyway, so that's the same behaviour as before |
$query['select'] = $this->_buildSelect($column); |
$query['where'] = $this->_buildWhere($this->table.'.'.$this->primaryCol.'='.$id); |
$queryString = $this->_buildSelectQuery($query); |
return $this->returnResult($this->execute($queryString,$getMethod)); |
} |
// }}} |
// {{{ getMultiple() |
/** |
* gets the data of the given ids |
* |
* @version 2002/04/23 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array this is an array of ids to retreive |
* @param string the column to search in for |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getMultiple($ids, $column='') |
{ |
$col = $this->primaryCol; |
if ($column) { |
$col = $column; |
} |
// FIXXME if $ids has no table.col syntax and we are using joins, the table better be put in front!!! |
$ids = $this->_quoteArray($ids); |
$query['where'] = $this->_buildWhere($col.' IN ('.implode(',', $ids).')'); |
$queryString = $this->_buildSelectQuery($query); |
return $this->returnResult($this->execute($queryString)); |
} |
// }}} |
// {{{ getAll() |
/** |
* get all entries from the DB |
* for sorting use setOrder!!!, the last 2 parameters are deprecated |
* |
* @version 2002/03/05 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param int to start from |
* @param int the number of rows to show |
* @param string the DB-method to use, i dont know if we should leave this param here ... |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getAll($from=0,$count=0,$method='getAll') |
{ |
$query = array(); |
if ($count) { |
$query = array('limit' => array($from, $count)); |
} |
return $this->returnResult($this->execute($this->_buildSelectQuery($query), $method)); |
} |
// }}} |
// {{{ getCol() |
/** |
* this method only returns one column, so the result will be a one dimensional array |
* this does also mean that using setSelect() should be set to *one* column, the one you want to |
* have returned a most common use case for this could be: |
* $table->setSelect('id'); |
* $ids = $table->getCol(); |
* OR |
* $ids = $table->getCol('id'); |
* so ids will be an array with all the id's |
* |
* @version 2003/02/25 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the column that shall be retreived |
* @param int to start from |
* @param int the number of rows to show |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getCol($column=null, $from=0, $count=0) |
{ |
$query = array(); |
if (!is_null($column)) { |
// by using _buildSelect() i can be sure that the table name will not be ambigious |
// i.e. in a join, where all the joined tables have a col 'id' |
// _buildSelect() will put the proper table name in front in case there is none |
$query['select'] = $this->_buildSelect($column); |
} |
if ($count) { |
$query['limit'] = array($from,$count); |
} |
return $this->returnResult($this->execute($this->_buildSelectQuery($query), 'getCol')); |
} |
// }}} |
// {{{ getCount() |
/** |
* get the number of entries |
* |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return mixed an array of the retreived data, or false in case of failure |
* when failing an error is set in $this->_error |
*/ |
function getCount() |
{ |
/* the following query works on mysql |
SELECT count(DISTINCT image.id) FROM image2tree |
RIGHT JOIN image ON image.id = image2tree.image_id |
the reason why this is needed - i just wanted to get the number of rows that do exist if the result is grouped by image.id |
the following query is what i tried first, but that returns the number of rows that have been grouped together |
for each image.id |
SELECT count(*) FROM image2tree |
RIGHT JOIN image ON image.id = image2tree.image_id GROUP BY image.id |
so that's why we do the following, i am not sure if that is standard SQL and absolutley correct!!! |
*/ |
//FIXXME see comment above if this is absolutely correct!!! |
if ($group = $this->_buildGroup()) { |
$query['select'] = 'COUNT(DISTINCT '.$group.')'; |
$query['group'] = ''; |
} else { |
$query['select'] = 'COUNT(*)'; |
} |
$query['order'] = ''; // order is not of importance and might freak up the special group-handling up there, since the order-col is not be known |
/*# FIXXME use the following line, but watch out, then it has to be used in every method, or this |
# value will be used always, simply try calling getCount and getAll afterwards, getAll will return the count :-) |
# if getAll doesn't use setSelect!!! |
*/ |
//$this->setSelect('count(*)'); |
$queryString = $this->_buildSelectQuery($query, true); |
return ($res = $this->execute($queryString, 'getOne')) ? $res : 0; |
} |
// }}} |
// {{{ getDefaultValues() |
/** |
* return an empty element where all the array elements do already exist |
* corresponding to the columns in the DB |
* |
* @version 2002/04/05 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return array an empty, or pre-initialized element |
*/ |
function getDefaultValues() |
{ |
$ret = array(); |
// here we read all the columns from the DB and initialize them |
// with '' to prevent PHP-warnings in case we use error_reporting=E_ALL |
foreach ($this->metadata() as $aCol=>$x) { |
$ret[$aCol] = ''; |
} |
return $ret; |
} |
// }}} |
// {{{ getEmptyElement() |
/** |
* this is just for BC |
* @deprecated |
*/ |
function getEmptyElement() |
{ |
$this->getDefaultValues(); |
} |
// }}} |
// {{{ getQueryString() |
/** |
* Render the current query and return it as a string. |
* |
* @return string the current query |
*/ |
function getQueryString() |
{ |
$ret = $this->_buildSelectQuery(); |
if (is_string($ret)) { |
$ret = trim($ret); |
} |
return $ret; |
} |
// }}} |
// {{{ save() |
/** |
* save data, calls either update or add |
* if the primaryCol is given in the data this method knows that the |
* data passed to it are meant to be updated (call 'update'), otherwise it will |
* call the method 'add'. |
* If you dont like this behaviour simply stick with the methods 'add' |
* and 'update' and ignore this one here. |
* This method is very useful when you have validation checks that have to |
* be done for both adding and updating, then you can simply overwrite this |
* method and do the checks in here, and both cases will be validated first. |
* |
* @version 2002/03/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains the new data that shall be saved in the DB |
* @return mixed the data returned by either add or update-method |
*/ |
function save($data) |
{ |
if (!empty($data[$this->primaryCol])) { |
return $this->update($data); |
} |
return $this->add($data); |
} |
// }}} |
// {{{ update() |
/** |
* update the member data of a data set |
* |
* @version 2002/03/06 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains the new data that shall be saved in the DB |
* the id has to be given in the field with the key 'ID' |
* @return mixed true on success, or false otherwise |
*/ |
function update($newData) |
{ |
$query = array(); |
// do only set the 'where' part in $query, if a primary column is given |
// if not the default 'where' clause is used |
if (isset($newData[$this->primaryCol])) { |
$query['where'] = $this->primaryCol.'='.$newData[$this->primaryCol]; |
} |
$newData = $this->_checkColumns($newData, 'update'); |
$values = array(); |
$raw = $this->getOption('raw'); |
foreach ($newData as $key => $aData) { // quote the data |
//$values[] = "{$this->table}.$key=". ($raw ? $aData : $this->db->quote($aData)); |
$values[] = "$key=". ($raw ? $aData : $this->db->quote($aData)); |
} |
$query['set'] = implode(',', $values); |
//FIXXXME _buildUpdateQuery() seems to take joins into account, whcih is bullshit here |
$updateString = $this->_buildUpdateQuery($query); |
#print '$updateString = '.$updateString; |
return $this->execute($updateString, 'query') ? true : false; |
} |
// }}} |
// {{{ add() |
/** |
* add a new member in the DB |
* |
* @version 2002/04/02 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains the new data that shall be saved in the DB |
* @return mixed the inserted id on success, or false otherwise |
*/ |
function add($newData) |
{ |
// if no primary col is given, get next sequence value |
if (empty($newData[$this->primaryCol])) { |
if ($this->primaryCol) { // do only use the sequence if a primary column is given |
// otherwise the data are written as given |
$id = $this->db->nextId($this->sequenceName); |
$newData[$this->primaryCol] = (int)$id; |
} else { |
// if no primary col is given return true on success |
$id = true; |
} |
} else { |
$id = $newData[$this->primaryCol]; |
} |
//unset($newData[$this->primaryCol]); |
$newData = $this->_checkColumns($newData, 'add'); |
$newData = $this->_quoteArray($newData); |
$query = sprintf( 'INSERT INTO %s (%s) VALUES (%s)', |
$this->table, |
implode(', ', array_keys($newData)), |
implode(', ', $newData) |
); |
return $this->execute($query, 'query') ? $id : false; |
} |
// }}} |
// {{{ addMultiple() |
/** |
* adds multiple new members in the DB |
* |
* @version 2002/07/17 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array contains an array of new data that shall be saved in the DB |
* the key-value pairs have to be the same for all the data!!! |
* @return mixed the inserted ids on success, or false otherwise |
*/ |
function addMultiple($data) |
{ |
if (!sizeof($data)) { |
return false; |
} |
// the inserted ids which will be returned or if no primaryCol is given |
// we return true by default |
$retIds = $this->primaryCol ? array() : true; |
$allData = array(); // each row that will be inserted |
foreach ($data as $key => $aData) { |
$aData = $this->_checkColumns($aData, 'add'); |
$aData = $this->_quoteArray($aData); |
if (empty($aData[$this->primaryCol])) { |
if ($this->primaryCol) { // do only use the sequence if a primary column is given |
// otherwise the data are written as given |
$retIds[] = $id = (int)$this->db->nextId($this->sequenceName); |
$aData[$this->primaryCol] = $id; |
} |
} else { |
$retIds[] = $aData[$this->primaryCol]; |
} |
$allData[] = '('.implode(', ', $aData).')'; |
} |
$query = sprintf( 'INSERT INTO %s (%s) VALUES %s', |
$this->table, |
implode(', ', array_keys($aData)), // use the keys of the last element built |
implode(', ', $allData) |
); |
return $this->execute($query, 'query') ? $retIds : false; |
} |
// }}} |
// {{{ remove() |
/** |
* removes a member from the DB |
* |
* @version 2002/04/08 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed integer/string - the value of the column that shall be removed |
* array - multiple columns that shall be matched, the second parameter will be ignored |
* @param string the column to match the data against, only if $data is not an array |
* @return boolean |
*/ |
function remove($data, $whereCol='') |
{ |
$raw = $this->getOption('raw'); |
if (is_array($data)) { |
//FIXXME check $data if it only contains columns that really exist in the table |
$wheres = array(); |
foreach ($data as $key => $val) { |
$wheres[] = $key.'='. ($raw ? $val : $this->db->quote($val)); |
} |
$whereClause = implode(' AND ',$wheres); |
} else { |
if (empty($whereCol)) { |
$whereCol = $this->primaryCol; |
} |
$whereClause = $whereCol.'='. ($raw ? $data : $this->db->quote($data)); |
} |
$query = sprintf( 'DELETE FROM %s WHERE %s', |
$this->table, |
$whereClause |
); |
return $this->execute($query, 'query') ? true : false; |
// i think this method should return the ID's that it removed, this way we could simply use the result |
// for further actions that depend on those id ... or? make stuff easier, see ignaz::imail::remove |
} |
// }}} |
// {{{ removeAll() |
/** |
* empty a table |
* |
* @version 2002/06/17 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return |
*/ |
function removeAll() |
{ |
$query = 'DELETE FROM '.$this->table; |
return $this->execute($query, 'query') ? true : false; |
} |
// }}} |
// {{{ removeMultiple() |
/** |
* remove the datasets with the given ids |
* |
* @version 2002/04/24 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array the ids to remove |
* @return |
*/ |
function removeMultiple($ids, $colName='') |
{ |
if (empty($colName)) { |
$colName = $this->primaryCol; |
} |
$ids = $this->_quoteArray($ids); |
$query = sprintf( 'DELETE FROM %s WHERE %s IN (%s)', |
$this->table, |
$colName, |
implode(',', $ids) |
); |
return $this->execute($query, 'query') ? true : false; |
} |
// }}} |
// {{{ removePrimary() |
/** |
* removes a member from the DB and calls the remove methods of the given objects |
* so all rows in another table that refer to this table are erased too |
* |
* @version 2002/04/08 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param integer the value of the primary key |
* @param string the column name of the tables with the foreign keys |
* @param object just for convinience, so nobody forgets to call this method |
* with at least one object as a parameter |
* @return boolean |
*/ |
function removePrimary($id, $colName, $atLeastOneObject) |
{ |
$argCounter = 2; // we have 2 parameters that need to be given at least |
// func_get_arg returns false and a warning if there are no more parameters, so |
// we suppress the warning and check for false |
while ($object = @func_get_arg($argCounter++)) { |
//FIXXXME let $object also simply be a table name |
if (!$object->remove($id, $colName)) { |
//FIXXXME do this better |
$this->_errorSet("Error removing '$colName=$id' from table {$object->table}."); |
return false; |
} |
} |
return ($this->remove($id) ? true : false); |
} |
// }}} |
// {{{ setLimit() |
/** |
* @param integer $from |
* @param integer $count |
*/ |
function setLimit($from=0, $count=0) |
{ |
if ($from==0 && $count==0) { |
$this->_limit = array(); |
} else { |
$this->_limit = array($from, $count); |
} |
} |
// }}} |
// {{{ getLimit() |
/** |
* @return array |
*/ |
function getLimit() |
{ |
return $this->_limit; |
} |
// }}} |
// {{{ setWhere() |
/** |
* sets the where condition which is used for the current instance |
* |
* @version 2002/04/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where condition, this can be complete like 'X=7 AND Y=8' |
*/ |
function setWhere($whereCondition='') |
{ |
$this->_where = $whereCondition; |
//FIXXME parse the where condition and replace ambigious column names, such as "name='Deutschland'" with "country.name='Deutschland'" |
// then the users dont have to write that explicitly and can use the same name as in the setOrder i.e. setOrder('name,_net_name,_netPrefix_prefix'); |
} |
// }}} |
// {{{ getWhere() |
/** |
* gets the where condition which is used for the current instance |
* |
* @version 2002/04/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the where condition, this can be complete like 'X=7 AND Y=8' |
*/ |
function getWhere() |
{ |
return $this->_where; |
} |
// }}} |
// {{{ addWhere() |
/** |
* only adds a string to the where clause |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where clause to add to the existing one |
* @param string the condition for how to concatenate the new where clause |
* to the existing one |
*/ |
function addWhere($where, $condition='AND') |
{ |
if ($this->getWhere()) { |
$where = $this->getWhere().' '.$condition.' '.$where; |
} |
$this->setWhere($where); |
} |
// }}} |
// {{{ addWhereSearch() |
/** |
* add a where-like clause which works like a search for the given string |
* i.e. calling it like this: |
* $this->addWhereSearch('name', 'otto hans') |
* produces a where clause like this one |
* LOWER(name) LIKE "%otto%hans%" |
* so the search finds the given string |
* |
* @version 2002/08/14 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the column to search in for |
* @param string the string to search for |
*/ |
function addWhereSearch($column, $string, $condition='AND') |
{ |
// if the column doesn't contain a tablename use the current table name |
// in case it is a defined column to prevent ambiguous rows |
if (strpos($column, '.') === false) { |
$meta = $this->metadata(); |
if (isset($meta[$column])) { |
$column = $this->table.".$column"; |
} |
} |
$string = $this->db->quote('%'.str_replace(' ', '%', strtolower($string)).'%'); |
$this->addWhere("LOWER($column) LIKE $string", $condition); |
} |
// }}} |
// {{{ setOrder() |
/** |
* sets the order condition which is used for the current instance |
* |
* @version 2002/05/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where condition, this can be complete like 'X=7 AND Y=8' |
* @param boolean sorting order (TRUE => ASC, FALSE => DESC) |
*/ |
function setOrder($orderCondition='', $desc=false) |
{ |
$this->_order = $orderCondition .($desc ? ' DESC' : ''); |
} |
// }}} |
// {{{ addOrder() |
/** |
* Add a order parameter to the query. |
* |
* @version 2003/05/28 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the where condition, this can be complete like 'X=7 AND Y=8' |
* @param boolean sorting order (TRUE => ASC, FALSE => DESC) |
*/ |
function addOrder($orderCondition='', $desc=false) |
{ |
$order = $orderCondition .($desc ? ' DESC' : ''); |
if ($this->_order) { |
$this->_order = $this->_order.','.$order; |
} else { |
$this->_order = $order; |
} |
} |
// }}} |
// {{{ getOrder() |
/** |
* gets the order condition which is used for the current instance |
* |
* @version 2002/05/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the order condition, this can be complete like 'ID,TIMESTAMP DESC' |
*/ |
function getOrder() |
{ |
return $this->_order; |
} |
// }}} |
// {{{ setHaving() |
/** |
* sets the having definition |
* |
* @version 2003/06/05 |
* @access public |
* @author Johannes Schaefer <johnschaefer@gmx.de> |
* @param string the having definition |
*/ |
function setHaving($having='') |
{ |
$this->_having = $having; |
} |
// }}} |
// {{{ getHaving() |
/** |
* gets the having definition which is used for the current instance |
* |
* @version 2003/06/05 |
* @access public |
* @author Johannes Schaefer <johnschaefer@gmx.de> |
* @return string the having definition |
*/ |
function getHaving() |
{ |
return $this->_having; |
} |
// }}} |
// {{{ addHaving() |
/** |
* Extend the current having clause. This is very useful, when you are building |
* this clause from different places and don't want to overwrite the currently |
* set having clause, but extend it. |
* |
* @param string this is a having clause, i.e. 'column' or 'table.column' or 'MAX(column)' |
* @param string the connection string, which usually stays the default, which is ',' (a comma) |
*/ |
function addHaving($what='*', $connectString=' AND ') |
{ |
if ($this->_having) { |
$this->_having = $this->_having.$connectString.$what; |
} else { |
$this->_having = $what; |
} |
} |
// }}} |
// {{{ setJoin() |
/** |
* sets a join-condition |
* |
* @version 2002/06/10 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed either a string or an array that contains |
* the table(s) to join on the current table |
* @param string the where clause for the join |
*/ |
function setJoin($table=null, $where=null, $joinType='default') |
{ |
//FIXXME make it possible to pass a table name as a string like this too 'user u' |
// where u is the string that can be used to refer to this table in a where/order |
// or whatever condition |
// this way it will be possible to join tables with itself, like setJoin(array('user u','user u1')) |
// this wouldnt work yet, but for doing so we would need to change the _build methods too!!! |
// because they use getJoin('tables') and this simply returns all the tables in use |
// but don't take care of the mentioned syntax |
if (is_null($table) || is_null($where)) { // remove the join if not sufficient parameters are given |
$this->_join[$joinType] = array(); |
return; |
} |
/* this causes problems if we use the order-by, since it doenst know the name to order it by ... :-) |
// replace the table names with the internal name used for the join |
// this way we can also join one table multiple times if it will be implemented one day |
$this->_join[$table] = preg_replace('/'.$table.'/','j1',$where); |
*/ |
$this->_join[$joinType][$table] = $where; |
} |
// }}} |
// {{{ setJoin() |
/** |
* if you do a left join on $this->table you will get all entries |
* from $this->table, also if there are no entries for them in the joined table |
* if both parameters are not given the left-join will be removed |
* NOTE: be sure to only use either a right or a left join |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the table(s) to be left-joined |
* @param string the where clause for the join |
*/ |
function setLeftJoin($table=null, $where=null) |
{ |
$this->setJoin($table, $where, 'left'); |
} |
// }}} |
// {{{ addLeftJoin() |
/** |
* @param string the table to be left-joined |
* @param string the where clause for the join |
* @param string the join type |
*/ |
function addLeftJoin($table, $where, $type='left') |
{ |
// init value, to prevent E_ALL-warning |
if (!isset($this->_join[$type]) || !$this->_join[$type]) { |
$this->_join[$type] = array(); |
} |
$this->_join[$type][$table] = $where; |
} |
// }}} |
// {{{ setRightJoin() |
/** |
* see setLeftJoin for further explaination on what a left/right join is |
* NOTE: be sure to only use either a right or a left join |
//FIXXME check if the above sentence is necessary and if sql doesnt allow the use of both |
* |
* @see setLeftJoin() |
* @version 2002/09/04 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the table(s) to be right-joined |
* @param string the where clause for the join |
*/ |
function setRightJoin($table=null, $where=null) |
{ |
$this->setJoin($table, $where, 'right'); |
} |
// }}} |
// {{{ getJoin() |
/** |
* gets the join-condition |
* |
* @access public |
* @param string [null|''|'table'|'tables'|'right'|'left'] |
* @return array gets the join parameters |
*/ |
function getJoin($what=null) |
{ |
// if the user requests all the join data or if the join is empty, return it |
if (is_null($what) || empty($this->_join)) { |
return $this->_join; |
} |
$ret = array(); |
switch (strtolower($what)) { |
case 'table': |
case 'tables': |
foreach ($this->_join as $aJoin) { |
if (count($aJoin)) { |
$ret = array_merge($ret, array_keys($aJoin)); |
} |
} |
break; |
case 'right': // return right-join data only |
case 'left': // return left join data only |
if (count($this->_join[$what])) { |
$ret = array_merge($ret, $this->_join[$what]); |
} |
break; |
} |
return $ret; |
} |
// }}} |
// {{{ addJoin() |
/** |
* adds a table and a where clause that shall be used for the join |
* instead of calling |
* setJoin(array(table1,table2),'<where clause1> AND <where clause2>') |
* you can also call |
* setJoin(table1,'<where clause1>') |
* addJoin(table2,'<where clause2>') |
* or where it makes more sense is to build a query which is made out of a |
* left join and a standard join |
* setLeftJoin(table1,'<where clause1>') |
* // results in ... FROM $this->table LEFT JOIN table ON <where clause1> |
* addJoin(table2,'<where clause2>') |
* // results in ... FROM $this->table,table2 LEFT JOIN table ON <where clause1> WHERE <where clause2> |
* |
* @access public |
* @param string the table to be joined |
* @param string the where clause for the join |
* @param string the join type |
*/ |
function addJoin($table, $where, $type='default') |
{ |
if ($table == $this->table) { |
return; //skip. Self joins are not supported. |
} |
// init value, to prevent E_ALL-warning |
if (!isset($this->_join[$type]) || !$this->_join[$type]) { |
$this->_join[$type] = array(); |
} |
$this->_join[$type][$table] = $where; |
} |
// }}} |
// {{{ setTable() |
/** |
* sets the table this class is currently working on |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the table name |
*/ |
function setTable($table) |
{ |
$this->table = $table; |
} |
// }}} |
// {{{ getTable() |
/** |
* gets the table this class is currently working on |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the table name |
*/ |
function getTable() |
{ |
return $this->table; |
} |
// }}} |
// {{{ setGroup() |
/** |
* sets the group-by condition |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the group condition |
*/ |
function setGroup($group='') |
{ |
$this->_group = $group; |
//FIXXME parse the condition and replace ambigious column names, such as "name='Deutschland'" with "country.name='Deutschland'" |
// then the users dont have to write that explicitly and can use the same name as in the setOrder i.e. setOrder('name,_net_name,_netPrefix_prefix'); |
} |
// }}} |
// {{{ getGroup() |
/** |
* gets the group condition which is used for the current instance |
* |
* @version 2002/07/22 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return string the group condition |
*/ |
function getGroup() |
{ |
return $this->_group; |
} |
// }}} |
// {{{ setSelect() |
/** |
* limit the result to return only the columns given in $what |
* @param string fields that shall be selected |
*/ |
function setSelect($what='*') |
{ |
$this->_select = $what; |
} |
// }}} |
// {{{ addSelect() |
/** |
* add a string to the select part of the query |
* |
* add a string to the select-part of the query and connects it to an existing |
* string using the $connectString, which by default is a comma. |
* (SELECT xxx FROM - xxx is the select-part of a query) |
* |
* @version 2003/01/08 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the string that shall be added to the select-part |
* @param string the string to connect the new string with the existing one |
* @return void |
*/ |
function addSelect($what='*', $connectString=',') |
{ |
// if the select string is not empty add the string, otherwise simply set it |
if ($this->_select) { |
$this->_select = $this->_select.$connectString.$what; |
} else { |
$this->_select = $what; |
} |
} |
// }}} |
// {{{ getSelect() |
/** |
* @return string |
*/ |
function getSelect() |
{ |
return $this->_select; |
} |
// }}} |
// {{{ setDontSelect() |
/** |
* @param string |
*/ |
function setDontSelect($what='') |
{ |
$this->_dontSelect = $what; |
} |
// }}} |
// {{{ getDontSelect() |
/** |
* @return string |
*/ |
function getDontSelect() |
{ |
return $this->_dontSelect; |
} |
// }}} |
// {{{ reset() |
/** |
* reset all the set* settings; with no parameter given, it resets them all |
* |
* @version 2002/09/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @return void |
*/ |
function reset($what=array()) |
{ |
if (!sizeof($what)) { |
$what = array( |
'select', |
'dontSelect', |
'group', |
'having', |
'limit', |
'where', |
'index', |
'order', |
'join', |
'leftJoin', |
'rightJoin' |
); |
} |
foreach ($what as $aReset) { |
$this->{'set'.ucfirst($aReset)}(); |
} |
} |
// }}} |
// {{{ setOption() |
/** |
* set mode the class shall work in |
* currently we have the modes: |
* 'raw' does not quote the data before building the query |
* |
* @version 2002/09/17 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the mode to be set |
* @param mixed the value of the mode |
* @return void |
*/ |
function setOption($option, $value) |
{ |
$this->options[strtolower($option)] = $value; |
} |
// }}} |
// {{{ getOption() |
/** |
* @return string |
*/ |
function getOption($option) |
{ |
return $this->options[strtolower($option)]; |
} |
// }}} |
// {{{ _quoteArray() |
/** |
* quotes all the data in this array if we are not in raw mode! |
* @param array |
*/ |
function _quoteArray($data) |
{ |
if (!$this->getOption('raw')) { |
foreach ($data as $key => $val) { |
$data[$key] = $this->db->quote($val); |
} |
} |
return $data; |
} |
// }}} |
// {{{ _checkColumns() |
/** |
* checks if the columns which are given as the array's indexes really exist |
* if not it will be unset anyway |
* |
* @version 2002/04/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the actual message, first word should always be the method name, |
* to build the message like this: className::methodname |
* @param integer the line number |
*/ |
function _checkColumns($newData, $method='unknown') |
{ |
if (!$meta = $this->metadata()) { // if no metadata available, return data as given |
return $newData; |
} |
foreach ($newData as $colName => $x) { |
if (!isset($meta[$colName])) { |
$this->_errorLog("$method, column {$this->table}.$colName doesnt exist, value was removed before '$method'",__LINE__); |
unset($newData[$colName]); |
} else { |
// if the current column exists, check the length too, not to write content that is too long |
// prevent DB-errors here |
// do only check the data length if this field is given |
if (isset($meta[$colName]['len']) && ($meta[$colName]['len'] != -1) && |
($oldLength=strlen($newData[$colName])) > $meta[$colName]['len'] |
) { |
$this->_errorLog("_checkColumns, had to trim column '$colName' from $oldLength to ". |
$meta[$colName]['DATA_LENGTH'].' characters.', __LINE__); |
$newData[$colName] = substr($newData[$colName], 0, $meta[$colName]['len']); |
} |
} |
} |
return $newData; |
} |
// }}} |
// {{{ debug() |
/** |
* overwrite this method and i.e. print the query $string |
* to see the final query |
* |
* @param string the query mostly |
*/ |
function debug($string){} |
// |
// |
// ONLY ORACLE SPECIFIC, not very nice since it is DB dependent, but we need it!!! |
// |
// |
// }}} |
// {{{ metadata() |
/** |
* !!!! query COPIED FROM db_oci8.inc - from PHPLIB !!!! |
* |
* @access public |
* @see |
* @version 2001/09 |
* @author PHPLIB |
* @param |
* @return |
*/ |
function metadata($table='') |
{ |
// is there an alias in the table name, then we have something like this: 'user ua' |
// cut of the alias and return the table name |
if (strpos($table, ' ') !== false) { |
$split = explode(' ', trim($table)); |
$table = $split[0]; |
} |
$full = false; |
if (empty($table)) { |
$table = $this->table; |
} |
// to prevent multiple selects for the same metadata |
if (isset($this->_metadata[$table])) { |
return $this->_metadata[$table]; |
} |
// FIXXXME use oci8 implementation of newer PEAR::DB-version |
if ($this->db->phptype == 'oci8') { |
$count = 0; |
$id = 0; |
$res = array(); |
//# This is a RIGHT OUTER JOIN: "(+)", if you want to see, what |
//# this query results try the following: |
//// $table = new Table; $this->db = new my_DB_Sql; // you have to make |
//// // your own class |
//// $table->show_results($this->db->query(see query vvvvvv)) |
//// |
$res = $this->db->getAll("SELECT T.column_name,T.table_name,T.data_type,". |
"T.data_length,T.data_precision,T.data_scale,T.nullable,". |
"T.char_col_decl_length,I.index_name". |
" FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I". |
" WHERE T.column_name=I.column_name (+)". |
" AND T.table_name=I.table_name (+)". |
" AND T.table_name=UPPER('$table') ORDER BY T.column_id"); |
if (DB::isError($res)) { |
//$this->_errorSet($res->getMessage()); |
// i think we only need to log here, since this method is never used |
// directly for the user's functionality, which means if it fails it |
// is most probably an appl error |
$this->_errorLog($res->getUserInfo()); |
return false; |
} |
foreach ($res as $key=>$val) { |
$res[$key]['name'] = $val['COLUMN_NAME']; |
} |
} else { |
if (!is_object($this->db)) { |
return false; |
} |
$res = $this->db->tableinfo($table); |
if (DB::isError($res)) { |
$this->_errorSet($res->getUserInfo()); |
return false; |
} |
} |
$ret = array(); |
foreach ($res as $key => $val) { |
$ret[$val['name']] = $val; |
} |
$this->_metadata[$table] = $ret; |
return $ret; |
} |
// |
// methods for building the query |
// |
// }}} |
// {{{ _buildFrom() |
/** |
* build the from string |
* |
* @access private |
* @return string the string added after FROM |
*/ |
function _buildFrom() |
{ |
$from = $this->table; |
$join = $this->getJoin(); |
if (!$join) { // no join set |
return $from; |
} |
// handle the standard join thingy |
if (isset($join['default']) && count($join['default'])) { |
$from .= ','.implode(',',array_keys($join['default'])); |
} |
// handle left/right joins |
foreach (array('left', 'right') as $joinType) { |
if (isset($join[$joinType]) && count($join[$joinType])) { |
foreach($join[$joinType] as $table => $condition) { |
// replace the _TABLENAME_COLUMNNAME by TABLENAME.COLUMNNAME |
// since oracle doesnt work with the _TABLENAME_COLUMNNAME which i think is strange |
// FIXXME i think this should become deprecated since the setWhere should not be used like this: '_table_column' but 'table.column' |
$regExp = '/_('.$table.')_([^\s]+)/'; |
$where = preg_replace($regExp, '$1.$2', $condition); |
// add the table name before any column that has no table prefix |
// since this might cause "unambiguous column" errors |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol=>$x) { |
// this covers the LIKE,IN stuff: 'name LIKE "%you%"' 'id IN (2,3,4,5)' |
$condition = preg_replace('/\s'.$aCol.'\s/', " {$this->table}.$aCol ", $condition); |
// replace also the column names which are behind a '=' |
// and do this also if the aCol is at the end of the where clause |
// that's what the $ is for |
$condition = preg_replace('/=\s*'.$aCol.'(\s|$)/', "={$this->table}.$aCol ", $condition); |
// replace if colName is first and possibly also if at the beginning of the where-string |
$condition = preg_replace('/(^\s*|\s+)'.$aCol.'\s*=/', "$1{$this->table}.$aCol=", $condition); |
} |
} |
$from .= ' '.strtoupper($joinType).' JOIN '.$table.' ON '.$condition; |
} |
} |
} |
return $from; |
} |
// }}} |
// {{{ getTableShortName() |
/** |
* this method gets the short name for a table |
* |
* get the short name for a table, this is needed to properly build the |
* 'AS' parts in the select query |
* @param string the real table name |
* @return string the table's short name |
*/ |
function getTableShortName($table) |
{ |
$tableSpec = $this->getTableSpec(false); |
if (isset($tableSpec[$table]['shortName']) && $tableSpec[$table]['shortName']) { |
//print "$table ... ".$tableSpec[$table]['shortName'].'<br>'; |
return $tableSpec[$table]['shortName']; |
} |
$possibleTableShortName = preg_replace($this->_tableNameToShortNamePreg, '', $table); |
//print "$table ... $possibleTableShortName<br>"; |
return $possibleTableShortName; |
} |
// }}} |
// {{{ getTableSpec() |
/** |
* gets the tableSpec either indexed by the short name or the name |
* returns the array for the tables given as parameter or if no |
* parameter given for all tables that exist in the tableSpec |
* |
* @param array table names (not the short names!) |
* @param boolean if true the table is returned indexed by the shortName |
* otherwise indexed by the name |
* @return array the tableSpec indexed |
*/ |
function getTableSpec($shortNameIndexed=true, $tables=array()) |
{ |
$newSpec = array(); |
foreach ($this->tableSpec as $aSpec) { |
if (sizeof($tables)==0 || in_array($aSpec['name'],$tables)) { |
if ($shortNameIndexed) { |
$newSpec[$aSpec['shortName']] = $aSpec; |
} else { |
$newSpec[$aSpec['name']] = $aSpec; |
} |
} |
} |
return $newSpec; |
} |
// }}} |
// {{{ _buildSelect() |
/** |
* build the 'SELECT <what> FROM ... 'for a select |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string if given use this string |
* @return string the what-clause |
*/ |
function _buildSelect($what=null) |
{ |
// what has preference, that means if what is set it is used |
// this is only because the methods like 'get' pass an individually built value, which |
// is supposed to be used, but usually it's generically build using the 'getSelect' values |
if (empty($what) && $this->getSelect()) { |
$what = $this->getSelect(); |
} |
// |
// replace all the '*' by the real column names, and take care of the dontSelect-columns! |
// |
$dontSelect = $this->getDontSelect(); |
$dontSelect = $dontSelect ? explode(',', $dontSelect) : array(); // make sure dontSelect is an array |
// here we will replace all the '*' and 'table.*' by all the columns that this table |
// contains. we do this so we can easily apply the 'dontSelect' values. |
// and so we can also handle queries like: 'SELECT *,count() FROM ' and 'SELECT table.*,x FROM ' too |
if (strpos($what, '*') !== false) { |
// subpattern 1 get all the table names, that are written like this: 'table.*' including '*' |
// for '*' the tablename will be '' |
preg_match_all('/([^,]*)(\.)?\*\s*(,|$)/U', $what, $res); |
//print "$what ... ";print_r($res);print "<br>"; |
$selectAllFromTables = array_unique($res[1]); // make the table names unique, so we do it all just once for each table |
$tables = array(); |
if (in_array('', $selectAllFromTables)) { // was there a '*' ? |
// get all the tables that we need to process, depending on if joined or not |
$tables = $this->getJoin() ? |
array_merge($this->getJoin('tables'), array($this->table)) : // get the joined tables and this->table |
array($this->table); // create an array with only this->table |
} else { |
$tables = $selectAllFromTables; |
} |
$cols = array(); |
foreach ($tables as $aTable) { // go thru all the tables and get all columns for each, and handle 'dontSelect' |
if ($meta = $this->metadata($aTable)) { |
foreach ($meta as $colName => $x) { |
// handle the dontSelect's |
if (in_array($colName, $dontSelect) || in_array("$aTable.$colName", $dontSelect)) { |
continue; |
} |
// build the AS clauses |
// put " around them to enable use of reserved words, i.e. SELECT table.option as option FROM... |
// and 'option' actually is a reserved word, at least in mysql |
// put double quotes around them, since pgsql doesnt work with single quotes |
// but don't do this for ibase because it doesn't work! |
if ($aTable == $this->table) { |
if ($this->db->phptype == 'ibase') { |
$cols[$aTable][] = $this->table. '.' .$colName . ' AS '. $colName; |
} else { |
$cols[$aTable][] = $this->table. '.' .$colName . ' AS "'. $colName .'"'; |
} |
} else { |
$cols[$aTable][] = "$aTable.$colName AS \"_".$this->getTableShortName($aTable)."_$colName\""; |
} |
} |
} |
} |
// put the extracted select back in the $what |
// that means replace 'table.*' by the i.e. 'table.id AS _table_id' |
// or if it is the table of this class replace 'table.id AS id' |
if (in_array('', $selectAllFromTables)) { |
$allCols = array(); |
foreach ($cols as $aTable) { |
$allCols[] = implode(',', $aTable); |
} |
$what = preg_replace('/(^|,)\*($|,)/', '$1'.implode(',',$allCols).'$2', $what); |
// remove all the 'table.*' since we have selected all anyway (because there was a '*' in the select) |
$what = preg_replace('/[^,]*(\.)?\*\s*(,|$)/U', '', $what); |
} else { |
foreach ($cols as $tableName => $aTable) { |
if (is_array($aTable) && sizeof($aTable)) { |
// replace all the 'table.*' by their select of each column |
$what = preg_replace('/(^|,)\s*'.$tableName.'\.\*\s*($|,)/', '$1'.implode(',',$aTable).'$2', $what); |
} |
} |
} |
} |
if ($this->getJoin()) { |
// replace all 'column' by '$this->table.column' to prevent ambigious errors |
$metadata = $this->metadata(); |
if (is_array($metadata)) { |
foreach ($metadata as $aCol => $x) { |
// handle ',id as xid,MAX(id),id' etc. |
// FIXXME do this better!!! |
$what = preg_replace( "/(^|,|\()(\s*)$aCol(\)|\s|,|as|$)/i", |
// $2 is actually just to keep the spaces, is not really |
// necessary, but this way the test works independent of this functionality here |
"$1$2{$this->table}.$aCol$3", |
$what); |
} |
} |
// replace all 'joinedTable.columnName' by '_joinedTable_columnName' |
// this actually only has an effect if there was no 'table.*' for 'table' |
// if that was there, then it has already been done before |
foreach ($this->getJoin('tables') as $aTable) { |
if ($meta = $this->metadata($aTable)) { |
foreach ($meta as $aCol=>$x) { |
// dont put the 'AS' behind it if there is already one |
if (preg_match("/$aTable.$aCol\s*as/i",$what)) { |
continue; |
} |
// this covers a ' table.colName ' surrounded by spaces, and replaces it by ' table.colName AS _table_colName' |
$what = preg_replace('/\s'.$aTable.'.'.$aCol.'\s/', " $aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol ", $what); |
// replace also the column names which are behind a ',' |
// and do this also if the aCol is at the end that's what the $ is for |
$what = preg_replace('/,\s*'.$aTable.'.'.$aCol.'(,|\s|$)/', ",$aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol$1", $what); |
// replace if colName is first and possibly also if at the beginning of the where-string |
$what = preg_replace('/(^\s*|\s+)'.$aTable.'.'.$aCol.'\s*,/', "$1$aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol,", $what); |
} |
} |
} |
} |
return $what; |
} |
// }}} |
// {{{ _buildWhere() |
/** |
* Build WHERE clause |
* |
* @param string $where WHERE clause |
* @return string $where WHERE clause after processing |
* @access private |
*/ |
function _buildWhere($where='') |
{ |
$where = trim($where); |
$originalWhere = $this->getWhere(); |
if ($originalWhere) { |
if (!empty($where)) { |
$where = $originalWhere.' AND '.$where; |
} else { |
$where = $originalWhere; |
} |
} |
$where = trim($where); |
if ($join = $this->getJoin()) { // is join set? |
// only those where conditions in the default-join have to be added here |
// left-join conditions are added behind 'ON', the '_buildJoin()' does that |
if (isset($join['default']) && count($join['default'])) { |
// we have to add this join-where clause here |
// since at least in mysql a query like: select * from tableX JOIN tableY ON ... |
// doesnt work, may be that's even SQL-standard... |
if (!empty($where)) { |
$where = implode(' AND ', $join['default']).' AND '.$where; |
} else { |
$where = implode(' AND ', $join['default']); |
} |
} |
// replace the _TABLENAME_COLUMNNAME by TABLENAME.COLUMNNAME |
// since oracle doesnt work with the _TABLENAME_COLUMNNAME which i think is strange |
// FIXXME i think this should become deprecated since the setWhere should not be used like this: '_table_column' but 'table.column' |
$regExp = '/_('.implode('|', $this->getJoin('tables')).')_([^\s]+)/'; |
$where = preg_replace($regExp, '$1.$2', $where); |
// add the table name before any column that has no table prefix |
// since this might cause "unambigious column" errors |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
// this covers the LIKE,IN stuff: 'name LIKE "%you%"' 'id IN (2,3,4,5)' |
$where = preg_replace('/\s'.$aCol.'\s/', " {$this->table}.$aCol ", $where); |
// replace also the column names which are behind a '=' |
// and do this also if the aCol is at the end of the where clause |
// that's what the $ is for |
$where = preg_replace('/([=<>])\s*'.$aCol.'(\s|$)/', "$1{$this->table}.$aCol ", $where); |
// replace if colName is first and possibly also if at the beginning of the where-string |
$where = preg_replace('/(^\s*|\s+)'.$aCol.'\s*([=<>])/', "$1{$this->table}.$aCol$2", $where); |
} |
} |
} |
return $where; |
} |
// }}} |
// {{{ _buildOrder() |
/** |
* |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return |
*/ |
function _buildOrder() |
{ |
$order = $this->getOrder(); |
// replace 'column' by '$this->table.column' if the column is defined for $this->table |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol=>$x) { |
$order = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U', "$1{$this->table}.$aCol$2", $order); |
} |
} |
return $order; |
} |
// }}} |
// {{{ _buildGroup() |
/** |
* Build the group-clause, replace 'column' by 'table.column'. |
* |
* @access public |
* @param void |
* @return string the rendered group clause |
*/ |
function _buildGroup() |
{ |
$group = $this->getGroup(); |
// replace 'column' by '$this->table.column' if the column is defined for $this->table |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
$group = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U', "$1{$this->table}.$aCol$2", $group); |
} |
} |
return $group; |
} |
// }}} |
// {{{ _buildHaving() |
/** |
* |
* @version 2003/06/05 |
* @access public |
* @author Johannes Schaefer <johnschaefer@gmx.de> |
* @param |
* @return string the having clause |
*/ |
function _buildHaving() |
{ |
$having = $this->getHaving(); |
// replace 'column' by '$this->table.column' if the column is defined for $this->table |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
$having = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U',"$1{$this->table}.$aCol$2",$having); |
} |
} |
return $having; |
} |
// }}} |
// {{{ _buildHaving() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param array this array contains the elements of the query, |
* indexed by their key, which are: 'select','from','where', etc. |
* @param boolean whether this method is called via getCount() or not. |
* @return |
*/ |
function _buildSelectQuery($query=array(), $isCalledViaGetCount = false) |
{ |
/*FIXXXME finish this |
$cacheKey = md5(serialize(????)); |
if (isset($this->_queryCache[$cacheKey])) { |
$this->_errorLog('using cached query',__LINE__); |
return $this->_queryCache[$cacheKey]; |
} |
*/ |
$where = isset($query['where']) ? $query['where'] : $this->_buildWhere(); |
if ($where) { |
$where = 'WHERE '.$where; |
} |
$order = isset($query['order']) ? $query['order'] : $this->_buildOrder(); |
if ($order) { |
$order = 'ORDER BY '.$order; |
} |
$group = isset($query['group']) ? $query['group'] : $this->_buildGroup(); |
if ($group) { |
$group = 'GROUP BY '.$group; |
} |
$having = isset($query['having']) ? $query['having'] : $this->_buildHaving(); |
if ($having) { |
$having = 'HAVING '.$having; |
} |
$queryString = sprintf( 'SELECT %s FROM %s %s %s %s %s', |
isset($query['select']) ? $query['select'] : $this->_buildSelect(), |
isset($query['from']) ? $query['from'] : $this->_buildFrom(), |
$where, |
$group, |
$having, |
$order |
); |
// $query['limit'] has preference! |
$limit = isset($query['limit']) ? $query['limit'] : $this->_limit; |
if (!$isCalledViaGetCount && @$limit[1]) { // is there a count set? |
$queryString=$this->db->modifyLimitQuery($queryString,$limit[0],$limit[1]); |
if (DB::isError($queryString)) { |
$this->_errorSet('DB_QueryTool::db::modifyLimitQuery failed '.$queryString->getMessage()); |
$this->_errorLog($queryString->getUserInfo()); |
return false; |
} |
} |
// $this->_queryCache[$cacheKey] = $queryString; |
return $queryString; |
} |
// }}} |
// {{{ _buildUpdateQuery() |
/** |
* this simply builds an update query. |
* |
* @param array the parameter array might contain the following indexes |
* 'where' the where clause to be added, i.e. |
* UPDATE table SET x=1 WHERE y=0 |
* here the 'where' part simply would be 'y=0' |
* 'set' the actual data to be updated |
* in the example above, that would be 'x=1' |
* @return string the resulting query |
*/ |
function _buildUpdateQuery($query=array()) |
{ |
$where = isset($query['where']) ? $query['where'] : $this->_buildWhere(); |
if ($where) { |
$where = 'WHERE '.$where; |
} |
$updateString = sprintf('UPDATE %s SET %s %s', |
$this->table, |
$query['set'], |
$where |
); |
return $updateString; |
} |
// }}} |
// {{{ execute() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @param string query method |
* @return boolean |
*/ |
function execute($query=null, $method='getAll') |
{ |
$this->writeLog(); |
if (is_null($query)) { |
$query = $this->_buildSelectQuery(); |
} |
$this->writeLog('query built: '.$query); |
// FIXXME on ORACLE this doesnt work, since we return joined columns as _TABLE_COLNAME and the _ in front |
// doesnt work on oracle, add a letter before it!!! |
$this->_lastQuery = $query; |
$this->debug($query); |
$this->writeLog('start query'); |
if (DB::isError($res = $this->db->$method($query))) { |
$this->writeLog('end query (failed)'); |
if ($this->getOption('verbose')) { |
$this->_errorSet($res->getMessage()); |
} else { |
$this->_errorLog($res->getMessage()); |
} |
$this->_errorLog($res->getUserInfo(), __LINE__); |
return false; |
} else { |
$this->writeLog('end query'); |
} |
$res = $this->_makeIndexed($res); |
return $res; |
} |
// }}} |
// {{{ writeLog() |
/** |
* Write events to the logfile. |
* |
* It does some additional work, like time measuring etc. to |
* see some additional info |
* |
*/ |
function writeLog($text='START') |
{ |
//its still really a quicky.... 'refactor' (nice word) that |
if (!isset($this->options['logfile'])) { |
return; |
} |
include_once 'Log.php'; |
if (!class_exists('Log')) { |
return; |
} |
if (!$this->_logObject) { |
$this->_logObject =& Log::factory('file', $this->options['logfile']); |
} |
if ($text==='start query' || $text==='end query') { |
$bytesSent = $this->db->getAll("SHOW STATUS like 'Bytes_sent'"); |
$bytesSent = $bytesSent[0]['Value']; |
} |
if ($text==='START') { |
$startTime = split(' ', microtime()); |
$this->_logData['startTime'] = $startTime[1] + $startTime[0]; |
} |
if ($text==='start query') { |
$this->_logData['startBytesSent'] = $bytesSent; |
$startTime = split(' ', microtime()); |
$this->_logData['startQueryTime'] = $startTime[1] + $startTime[0]; |
return; |
} |
if ($text==='end query') { |
$text .= ' result size: '.((int)$bytesSent-(int)$this->_logData['startBytesSent']).' bytes'; |
$endTime = split(' ', microtime()); |
$endTime = $endTime[1] + $endTime[0]; |
$text .= ', took: '.(($endTime - $this->_logData['startQueryTime'])).' seconds'; |
} |
if (strpos($text, 'query built')===0) { |
$endTime = split(' ', microtime()); |
$endTime = $endTime[1] + $endTime[0]; |
$this->writeLog('query building took: '.(($endTime - $this->_logData['startTime'])).' seconds'); |
} |
$this->_logObject->log($text); |
if (strpos($text, 'end query')===0) { |
$endTime = split(' ', microtime()); |
$endTime = $endTime[1] + $endTime[0]; |
$text = 'time over all: '.(($endTime - $this->_logData['startTime'])).' seconds'; |
$this->_logObject->log($text); |
} |
} |
// }}} |
// {{{ returnResult() |
/** |
* Return the chosen result type |
* |
* @version 2004/04/28 |
* @access public |
* @param object reference |
* @return mixed |
*/ |
function returnResult(&$result) |
{ |
if ($this->_resultType == 'none') { |
return $result; |
} |
if ($result === false) { |
return false; |
} |
//what about allowing other (custom) result types? |
switch (strtolower($this->_resultType)) { |
case 'object': return new DB_QueryTool_Result_Object($result); |
case 'array': |
default: return new DB_QueryTool_Result($result); |
} |
} |
// }}} |
// {{{ _makeIndexed() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param mixed |
* @return mixed |
*/ |
function &_makeIndexed(&$data) |
{ |
// we can only return an indexed result if the result has a number of columns |
if (is_array($data) && sizeof($data) && $key = $this->getIndex()) { |
// build the string to evaluate which might be made up out of multiple indexes of a result-row |
$evalString = '$val[\''.implode('\'].\',\'.$val[\'',explode(',',$key)).'\']'; //" |
$indexedData = array(); |
//FIXXME actually we also need to check ONCE if $val is an array, so to say if $data is 2-dimensional |
foreach ($data as $val) { |
eval("\$keyValue = $evalString;"); // get the actual real (string-)key (string if multiple cols are used as index) |
$indexedData[$keyValue] = $val; |
} |
unset($data); |
return $indexedData; |
} |
return $data; |
} |
// }}} |
// {{{ setIndex() |
/** |
* format the result to be indexed by $key |
* NOTE: be careful, when using this you should be aware, that if you |
* use an index which's value appears multiple times you may loose data |
* since a key cant exist multiple times!! |
* the result for a result to be indexed by a key(=columnName) |
* (i.e. 'relationtoMe') which's values are 'brother' and 'sister' |
* or alike normally returns this: |
* $res['brother'] = array('name'=>'xxx') |
* $res['sister'] = array('name'=>'xxx') |
* but if the column 'relationtoMe' contains multiple entries for 'brother' |
* then the returned dataset will only contain one brother, since the |
* value from the column 'relationtoMe' is used |
* and which 'brother' you get depends on a lot of things, like the sortorder, |
* how the db saves the data, and whatever else |
* |
* you can also set indexes which depend on 2 columns, simply pass the parameters like |
* 'table1.id,table2.id' it will be used as a string for indexing the result |
* and the index will be built using the 2 values given, so a possible |
* index might be '1,2' or '2108,29389' this way you can access data which |
* have 2 primary keys. Be sure to remember that the index is a string! |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return |
*/ |
function setIndex($key=null) |
{ |
if ($this->getJoin()) { // is join set? |
// replace TABLENAME.COLUMNNAME by _TABLENAME_COLUMNNAME |
// since this is only the result-keys can be used for indexing :-) |
$regExp = '/('.implode('|', $this->getJoin('tables')).')\.([^\s]+)/'; |
$key = preg_replace($regExp, '_$1_$2', $key); |
// remove the table name if it is in front of '<$this->table>.columnname' |
// since the key doesnt contain it neither |
if ($meta = $this->metadata()) { |
foreach ($meta as $aCol => $x) { |
$key = preg_replace('/'.$this->table.'\.'.$aCol.'/', $aCol, $key); |
} |
} |
} |
$this->_index = $key; |
} |
// }}} |
// {{{ getIndex() |
/** |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param |
* @return |
*/ |
function getIndex() |
{ |
return $this->_index; |
} |
// }}} |
// {{{ useResult() |
/** |
* Choose the type of the returned result |
* |
* @version 2004/04/28 |
* @access public |
* @param string $type ['array' | 'object' | 'none'] |
* For BC reasons, $type=true is equal to 'array', |
* $type=false is equal to 'none' |
*/ |
function useResult($type='array') |
{ |
if ($type === true) { |
$type = 'array'; |
} elseif ($type === false) { |
$type = 'none'; |
} |
switch (strtolower($type)) { |
case 'array': |
$this->_resultType = 'array'; |
require_once 'DB/QueryTool/Result.php'; |
break; |
case 'object': |
$this->_resultType = 'object'; |
require_once 'DB/QueryTool/Result/Object.php'; |
break; |
default: |
$this->_resultType = 'none'; |
} |
} |
// }}} |
// {{{ setErrorCallback() |
/** |
* set both callbacks |
* @param string |
*/ |
function setErrorCallback($param='') |
{ |
$this->setErrorLogCallback($param); |
$this->setErrorSetCallback($param); |
} |
// }}} |
// {{{ setErrorLogCallback() |
/** |
* @param string |
*/ |
function setErrorLogCallback($param='') |
{ |
$errorLogCallback = &PEAR::getStaticProperty('DB_QueryTool','_errorLogCallback'); |
$errorLogCallback = $param; |
} |
// }}} |
// {{{ setErrorSetCallback() |
/** |
* @param string |
*/ |
function setErrorSetCallback($param='') |
{ |
$errorSetCallback = &PEAR::getStaticProperty('DB_QueryTool','_errorSetCallback'); |
$errorSetCallback = $param; |
} |
// }}} |
// {{{ _errorLog() |
/** |
* sets error log and adds additional info |
* |
* @version 2002/04/16 |
* @access public |
* @author Wolfram Kriesing <wk@visionp.de> |
* @param string the actual message, first word should always be the method name, |
* to build the message like this: className::methodname |
* @param integer the line number |
*/ |
function _errorLog($msg, $line='unknown') |
{ |
$this->_errorHandler('log', $msg, $line); |
/* |
if ($this->getOption('verbose') == true) |
{ |
$this->_errorLog(get_class($this)."::$msg ($line)"); |
return; |
} |
if ($this->_errorLogCallback) |
call_user_func($this->_errorLogCallback, $msg); |
*/ |
} |
// }}} |
// {{{ _errorSet() |
/** |
* @param string |
* @param string |
*/ |
function _errorSet($msg, $line='unknown') |
{ |
$this->_errorHandler('set', $msg, $line); |
} |
// }}} |
// {{{ _errorHandler() |
/** |
* @param |
* @param string |
* @param string |
*/ |
function _errorHandler($logOrSet, $msg, $line='unknown') |
{ |
/* what did i do this for? |
if ($this->getOption('verbose') == true) |
{ |
$this->_errorHandler($logOrSet, get_class($this)."::$msg ($line)"); |
return; |
} |
*/ |
$msg = get_class($this)."::$msg ($line)"; |
$logOrSet = ucfirst($logOrSet); |
$callback = &PEAR::getStaticProperty('DB_QueryTool','_error'.$logOrSet.'Callback'); |
//var_dump($callback); |
//if ($callback) |
// call_user_func($callback, $msg); |
// else |
// ????? |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/QueryTool/Result/Object.php |
---|
New file |
0,0 → 1,89 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_Result_Row and DB_QueryTool_Result_Object classes |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_QueryTool |
* @author Roman Dostovalov, Com-tec-so S.A.<roman.dostovalov@ctco.lv> |
* @copyright 2004-2005 Roman Dostovalov |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Object.php,v 1.3 2005/02/25 16:38:28 quipo Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* Include parent class |
*/ |
require_once 'DB/QueryTool/Result.php'; |
/** |
* DB_QueryTool_Result_Row class |
* |
* @category Database |
* @package DB_QueryTool |
* @author Roman Dostovalov, Com-tec-so S.A.<roman.dostovalov@ctco.lv> |
* @copyright 2004-2005 Roman Dostovalov |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Result_Row |
{ |
/** |
* create object properties from the array |
* @param array |
*/ |
function DB_QueryTool_Result_Row($arr) |
{ |
foreach ($arr as $key => $value) { |
$this->$key = $value; |
} |
} |
} |
// ----------------------------------------------------------------------------- |
/** |
* DB_QueryTool_Result_Object class |
* |
* @category Database |
* @package DB_QueryTool |
* @author Roman Dostovalov, Com-tec-so S.A.<roman.dostovalov@ctco.lv> |
* @copyright 2004-2005 Roman Dostovalov |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Result_Object extends DB_QueryTool_Result |
{ |
// {{{ fetchRow |
/** |
* This function emulates PEAR::DB fetchRow() method |
* With this function DB_QueryTool can transparently replace PEAR::DB |
* |
* @todo implement fetchmode support? |
* @access public |
* @return void |
*/ |
function fetchRow() |
{ |
$arr = $this->getNext(); |
if (!PEAR::isError($arr)) { |
$row = new DB_QueryTool_Result_Row($arr); |
return $row; |
} |
return false; |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/DB/QueryTool/Result.php |
---|
New file |
0,0 → 1,261 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_Result class |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Result.php,v 1.8 2005/02/25 16:38:28 quipo Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* DB_QueryTool_Result class |
* |
* This result actually contains the 'data' itself, the number of rows |
* returned and some additional info |
* using ZE2 you can also get retrieve data from the result doing the following: |
* <DB_QueryTool_Common-instance>->getAll()->getCount() |
* or |
* <DB_QueryTool_Common-instance>->getAll()->getData() |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @author Lorenzo Alberton <l dot alberton at quipo dot it> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto, Lorenzo Alberton |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_Result |
{ |
// {{{ class vars |
/** |
* @var array |
*/ |
var $_data = array(); |
/** |
* @var array |
*/ |
var $_dataKeys = array(); |
/** |
* @var integer |
*/ |
var $_count = 0; |
/** |
* the counter for the methods getFirst, getNext |
* @var array |
*/ |
var $_counter = null; |
// }}} |
// {{{ DB_QueryTool_Result() |
/** |
* create a new instance of result with the data returned by the query |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @param array the data returned by the result |
*/ |
function DB_QueryTool_Result($data) |
{ |
if (!count($data)) { |
$this->_count = 0; |
} else { |
list($firstElement) = $data; |
if (is_array($firstElement)) { // is the array a collection of rows? |
$this->_count = sizeof($data); |
} else { |
if (sizeof($data) > 0) { |
$this->_count = 1; |
} else { |
$this->_count = 0; |
} |
} |
} |
$this->_data = $data; |
} |
// }}} |
// {{{ numRows |
/** |
* return the number of rows returned. This is an alias for getCount(). |
* |
* @access public |
* @return integer |
*/ |
function numRows() |
{ |
return $this->_count; |
} |
// }}} |
// {{{ getCount() |
/** |
* return the number of rows returned |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @return integer the number of rows returned |
*/ |
function getCount() |
{ |
return $this->_count; |
} |
// }}} |
// {{{ getData() |
/** |
* get all the data returned |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @param string $key |
* @return mixed array or PEAR_Error |
*/ |
function getData($key=null) |
{ |
if (is_null($key)) { |
return $this->_data; |
} |
if ($this->_data[$key]) { |
return $this->_data[$key]; |
} |
return new PEAR_Error("there is no element with the key '$key'!"); |
} |
// }}} |
// {{{ getFirst() |
/** |
* get the first result set |
* we are not using next, current, and reset, since those ignore keys |
* which are empty or 0 |
* |
* @version 2002/07/11 |
* @access public |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
* @return mixed |
*/ |
function getFirst() |
{ |
if ($this->getCount() > 0) { |
$this->_dataKeys = array_keys($this->_data); |
$this->_counter = 0; |
return $this->_data[$this->_dataKeys[$this->_counter]]; |
} |
return new PEAR_Error('There are no elements!'); |
} |
// }}} |
// {{{ getNext() |
/** |
* Get next result set. If getFirst() has never been called before, |
* it calls that method. |
* @return mixed |
* @access public |
*/ |
function getNext() |
{ |
if (!$this->initDone()) { |
return $this->getFirst(); |
} |
if ($this->hasMore()) { |
$this->_counter++; |
return $this->_data[$this->_dataKeys[$this->_counter]]; |
} |
return new PEAR_Error('there are no more elements!'); |
} |
// }}} |
// {{{ hasMore() |
/** |
* check if there are other rows |
* |
* @return boolean |
* @access public |
*/ |
function hasMore() |
{ |
if ($this->_counter+1 < $this->getCount()) { |
return true; |
} |
return false; |
} |
// }}} |
// {{{ fetchRow |
/** |
* This function emulates PEAR::DB fetchRow() method. |
* With this method, DB_QueryTool can transparently replace PEAR_DB |
* |
* @todo implement fetchmode support? |
* @access public |
* @return void |
*/ |
function fetchRow() |
{ |
if ($this->hasMore()) { |
$arr = $this->getNext(); |
if (!PEAR::isError($arr)) { |
return $arr; |
} |
} |
return false; |
} |
// }}} |
// {{{ initDone |
/** |
* Helper method. Check if $this->_dataKeys has been initialized |
* |
* @return boolean |
* @access private |
*/ |
function initDone() |
{ |
return ( |
isset($this->_dataKeys) && |
is_array($this->_dataKeys) && |
count($this->_dataKeys) |
); |
} |
// }}} |
#TODO |
#function getPrevious() |
#function getLast() |
} |
?> |
/trunk/bibliotheque/pear/DB/QueryTool/EasyJoin.php |
---|
New file |
0,0 → 1,135 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_QueryTool_EasyJoin class |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @author Paolo Panto <wk@visionp.de> |
* @copyright 2003-2005 Wolfram Kriesing, Paolo Panto |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: EasyJoin.php,v 1.9 2005/02/27 17:15:05 quipo Exp $ |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
/** |
* require the DB_QueryTool_Query class |
*/ |
require_once 'DB/QueryTool/Query.php'; |
/** |
* DB_QueryTool_EasyJoin class |
* |
* @category Database |
* @package DB_QueryTool |
* @author Wolfram Kriesing <wk@visionp.de> |
* @copyright 2003-2005 Wolfram Kriesing |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @link http://pear.php.net/package/DB_QueryTool |
*/ |
class DB_QueryTool_EasyJoin extends DB_QueryTool_Query |
{ |
// {{{ class vars |
/** |
* This is the regular expression that shall be used to find a table's shortName |
* in a column name, the string found by using this regular expression will be removed |
* from the column name and it will be checked if it is a table name |
* i.e. the default '/_id$/' would find the table name 'user' from the column name 'user_id' |
* |
* @var string regexp |
*/ |
var $_tableNamePreg = '/_id$/'; |
/** |
* This is to find the column name that is referred by it, so the default find |
* from 'user_id' the column 'id' which will be used to refer to the 'user' table |
* |
* @var string regexp |
*/ |
var $_columnNamePreg = '/^.*_/'; |
// }}} |
// {{{ __construct() |
/** |
* call parent constructor |
* @param mixed $dsn DSN string, DSN array or DB object |
* @param array $options |
*/ |
function __construct($dsn=false, $options=array()) |
{ |
parent::DB_QueryTool_Query($dsn, $options); |
} |
// }}} |
// {{{ autoJoin() |
/** |
* Join the given tables, using the column names, to find out how to join the tables; |
* i.e., if table1 has a column named "table2_id", this method will join |
* "WHERE table1.table2_id=table2.id". |
* All joins made here are only concatenated via AND. |
* @param array $tables |
*/ |
function autoJoin($tables) |
{ |
// FIXXME if $tables is empty autoJoin all available tables that have a relation |
// to $this->table, starting to search in $this->table |
settype($tables, 'array'); |
// add this->table to the tables array, so we go thru the current table first |
$tables = array_merge(array($this->table), $tables); |
$shortNameIndexed = $this->getTableSpec(true, $tables); |
$nameIndexed = $this->getTableSpec(false, $tables); |
//print_r($shortNameIndexed); |
//print_r($tables); print '<br><br>'; |
if (sizeof($shortNameIndexed) != sizeof($tables)) { |
$this->_errorLog("autoJoin-ERROR: not all the tables are in the tableSpec!<br />"); |
} |
$joinTables = array(); |
$joinConditions = array(); |
foreach ($tables as $aTable) { // go through $this->table and all the given tables |
if ($metadata = $this->metadata($aTable)) |
foreach ($metadata as $aCol => $x) { // go through each row to check which might be related to $aTable |
$possibleTableShortName = preg_replace($this->_tableNamePreg, '' , $aCol); |
$possibleColumnName = preg_replace($this->_columnNamePreg, '' , $aCol); |
//print "$aTable.$aCol .... possibleTableShortName=$possibleTableShortName .... possibleColumnName=$possibleColumnName<br />"; |
if (isset($shortNameIndexed[$possibleTableShortName])) { |
// are the tables given in the tableSpec? |
if (!$shortNameIndexed[$possibleTableShortName]['name'] || |
!$nameIndexed[$aTable]['name']) { |
// its an error of the developer, so log the error, dont show it to the end user |
$this->_errorLog("autoJoin-ERROR: '$aTable' is not given in the tableSpec!<br />"); |
} else { |
// do only join different table.col combination, |
// we should not join stuff like 'question.question=question.question' |
// this would be quite stupid, but it used to be :-( |
if ($shortNameIndexed[$possibleTableShortName]['name'] != $aTable || |
$possibleColumnName != $aCol |
) { |
$where = $shortNameIndexed[$possibleTableShortName]['name'].".$possibleColumnName=$aTable.$aCol"; |
$this->addJoin($nameIndexed[$aTable]['name'], $where); |
$this->addJoin($shortNameIndexed[$possibleTableShortName]['name'], $where); |
} |
} |
} |
} |
} |
} |
// }}} |
} |
?> |
/trunk/bibliotheque/pear/PEAR/tests/pear_info.php |
---|
New file |
0,0 → 1,38 |
<?php |
/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */ |
// +----------------------------------------------------------------------+ |
// | PHP version 4 | |
// +----------------------------------------------------------------------+ |
// | Copyright (c) 1997-2002 The PHP Group | |
// +----------------------------------------------------------------------+ |
// | This source file is subject to version 2.0 of the PHP license, | |
// | that is bundled with this package in the file LICENSE, and is | |
// | available at through the world-wide-web at | |
// | http://www.php.net/license/2_02.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +----------------------------------------------------------------------+ |
// | Authors: Davey Shafik <davey@pixelated-dreams.com> | |
// +----------------------------------------------------------------------+ |
// |
// $Id: pear_info.php,v 1.5 2003/05/12 11:40:57 davey Exp $ |
/* May be required on slower (dial-up) connections |
ini_set('default_socket_timeout',600); |
ini_set('max_execution_time',600); |
ini_set('max_input_time',600); */ |
// require the PEAR_Info file |
require_once 'PEAR/Info.php'; |
// If you need to set a http_proxy uncomment the line below |
// PEAR_Info::setProxy('your.proxy.here'); |
// Create PEAR_Info object |
$info = new PEAR_Info(); |
// Display PEAR_Info output |
$info->show(); |
?> |
/trunk/bibliotheque/pear/PEAR/PackageFileManager/File.php |
---|
New file |
0,0 → 1,421 |
<?php |
// |
// +------------------------------------------------------------------------+ |
// | PEAR :: Package File Manager | |
// +------------------------------------------------------------------------+ |
// | Copyright (c) 2003-2004 Gregory Beaver | |
// | Email cellog@phpdoc.org | |
// +------------------------------------------------------------------------+ |
// | This source file is subject to version 3.00 of the PHP License, | |
// | that is available at http://www.php.net/license/3_0.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +------------------------------------------------------------------------+ |
// | Portions of this code based on phpDocumentor | |
// | Web http://www.phpdoc.org | |
// | Mirror http://phpdocu.sourceforge.net/ | |
// +------------------------------------------------------------------------+ |
// $Id: File.php,v 1.21 2005/03/28 06:37:35 cellog Exp $ |
// |
/** |
* Retrieve the files from a directory listing |
* @package PEAR_PackageFileManager |
*/ |
/** |
* Retrieve the files from a directory listing |
* |
* This class is used to retrieve a raw directory |
* listing. Use the {@link PEAR_PackageFileManager_CVS} |
* class to only retrieve the contents of a cvs |
* repository when generating the package.xml |
* @package PEAR_PackageFileManager |
*/ |
class PEAR_PackageFileManager_File { |
/** |
* @var array |
* @access private |
*/ |
var $_options = |
array( |
); |
/** |
* @access private |
* @var PEAR_PackageFileManager |
*/ |
var $_parent; |
/** |
* @access private |
* @var array|false |
*/ |
var $_ignore = false; |
/** |
* Set up the File filelist generator |
* |
* 'ignore' and 'include' are the only options that this class uses. See |
* {@link PEAR_PackageFileManager::setOptions()} for |
* more information and formatting of this option |
* @param PEAR_PackageFileManager |
* @param array |
*/ |
function PEAR_PackageFileManager_File(&$parent, $options) |
{ |
$this->_parent = &$parent; |
$this->_options = array_merge($this->_options, $options); |
} |
/** |
* Generate the <filelist></filelist> section |
* of the package file. |
* |
* This function performs the backend generation of the array |
* containing all files in this package |
* @return array |
*/ |
function getFileList() |
{ |
$package_directory = $this->_options['packagedirectory']; |
$ignore = $this->_options['ignore']; |
// implicitly ignore packagefile |
$ignore[] = $this->_options['packagefile']; |
if ($this->_options['packagefile'] == 'package.xml') { |
// ignore auto-generated package2.xml from PEAR 1.4.0 |
$ignore[] = 'package2.xml'; |
} |
$include = $this->_options['include']; |
$this->ignore = array(false, false); |
$this->_setupIgnore($ignore, 1); |
$this->_setupIgnore($include, 0); |
$allfiles = $this->dirList(substr($package_directory, 0, strlen($package_directory) - 1)); |
if (PEAR::isError($allfiles)) { |
return $allfiles; |
} |
if (!count($allfiles)) { |
return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_NO_FILES, |
substr($package_directory, 0, strlen($package_directory) - 1)); |
} |
$struc = array(); |
foreach($allfiles as $file) { |
$path = substr(dirname($file), strlen(str_replace(DIRECTORY_SEPARATOR, |
'/', |
realpath($package_directory))) + 1); |
if (!$path) { |
$path = '/'; |
} |
$ext = array_pop(explode('.', $file)); |
if (strlen($ext) == strlen($file)) { |
$ext = ''; |
} |
$struc[$path][] = array('file' => basename($file), |
'ext' => $ext, |
'path' => (($path == '/') ? basename($file) : $path . '/' . basename($file)), |
'fullpath' => $file); |
} |
if (!count($struc)) { |
$newig = implode($this->_options['ignore'], ', '); |
return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING, |
substr($package_directory, 0, strlen($package_directory) - 1), $newig); |
} |
uksort($struc,'strnatcasecmp'); |
foreach($struc as $key => $ind) { |
usort($ind, array($this, 'sortfiles')); |
$struc[$key] = $ind; |
} |
$tempstruc = $struc; |
if (!isset($tempstruc['/'])) { |
$tempstruc['/'] = array(); |
} |
$struc = array('/' => $tempstruc['/']); |
$bv = 0; |
foreach($tempstruc as $key => $ind) { |
$save = $key; |
if ($key != '/') |
{ |
$struc['/'] = $this->_setupDirs($struc['/'], explode('/',$key), $tempstruc[$key]); |
} |
} |
uksort($struc['/'], array($this, 'mystrucsort')); |
return $struc; |
} |
/** |
* Retrieve a listing of every file in $directory and |
* all subdirectories. |
* |
* The return format is an array of full paths to files |
* @access protected |
* @return array list of files in a directory |
* @param string $directory full path to the directory you want the list of |
* @throws PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST |
*/ |
function dirList($directory) |
{ |
$ret = false; |
if (@is_dir($directory)) { |
$ret = array(); |
$d = @dir($directory); // thanks to Jason E Sweat (jsweat@users.sourceforge.net) for fix |
while($d && false !== ($entry=$d->read())) { |
if ($this->_testFile($directory, $entry)) { |
if (is_file($directory . '/' . $entry)) { |
// if include option was set, then only pass included files |
if ($this->ignore[0]) { |
if ($this->_checkIgnore($entry, $directory . '/' . $entry, 0)) { |
continue; |
} |
} |
// if ignore option was set, then only pass included files |
if ($this->ignore[1]) { |
if ($this->_checkIgnore($entry, $directory . '/' . $entry, 1)) { |
continue; |
} |
} |
$ret[] = $directory . '/' . $entry; |
} |
if (is_dir($directory . '/' . $entry)) { |
$tmp = $this->dirList($directory . '/' . $entry); |
if (is_array($tmp)) { |
foreach($tmp as $ent) { |
$ret[] = $ent; |
} |
} |
} |
} |
} |
if ($d) { |
$d->close(); |
} |
} else { |
return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST, $directory); |
} |
return $ret; |
} |
/** |
* Test whether an entry should be processed. |
* |
* Normally, it ignores all files and directories that begin with "." addhiddenfiles option |
* instead only ignores "." and ".." entries |
* @access private |
* @param string directory name of entry |
* @param string name |
*/ |
function _testFile($directory, $entry) |
{ |
if ($this->_options['addhiddenfiles']) { |
return is_file($directory . '/' . $entry) || (is_dir($directory . '/' . $entry) && !in_array($entry, array('.', '..'))); |
} else { |
return $entry{0} != '.'; |
} |
} |
/** |
* Tell whether to ignore a file or a directory |
* allows * and ? wildcards |
* |
* @param string $file just the file name of the file or directory, |
* in the case of directories this is the last dir |
* @param string $path the full path |
* @param 1|0 $return value to return if regexp matches. Set this to |
* false to include only matches, true to exclude |
* all matches |
* @return bool true if $path should be ignored, false if it should not |
* @access private |
*/ |
function _checkIgnore($file, $path, $return = 1) |
{ |
if (file_exists($path)) { |
$path = realpath($path); |
} |
if (is_array($this->ignore[$return])) { |
foreach($this->ignore[$return] as $match) { |
// match is an array if the ignore parameter was a /path/to/pattern |
if (is_array($match)) { |
// check to see if the path matches with a path delimiter appended |
preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path) . '/',$find); |
if (!count($find)) { |
// check to see if it matches without an appended path delimiter |
preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path), $find); |
} |
if (count($find)) { |
// check to see if the file matches the file portion of the regex string |
preg_match('/^' . strtoupper($match[1]).'$/', strtoupper($file), $find); |
if (count($find)) { |
return $return; |
} |
} |
// check to see if the full path matches the regex |
preg_match('/^' . strtoupper($match[0]).'$/', |
strtoupper($path . DIRECTORY_SEPARATOR . $file), $find); |
if (count($find)) { |
return $return; |
} |
} else { |
// ignore parameter was just a pattern with no path delimiters |
// check it against the path |
preg_match('/^' . strtoupper($match).'$/', strtoupper($path), $find); |
if (count($find)) { |
return $return; |
} |
// check it against the file only |
preg_match('/^' . strtoupper($match).'$/', strtoupper($file), $find); |
if (count($find)) { |
return $return; |
} |
} |
} |
} |
return !$return; |
} |
/** |
* Construct the {@link $ignore} array |
* @param array strings of files/paths/wildcards to ignore |
* @param 0|1 0 = files to include, 1 = files to ignore |
* @access private |
*/ |
function _setupIgnore($ignore, $index) |
{ |
$ig = array(); |
if (is_array($ignore)) { |
for($i=0; $i<count($ignore);$i++) { |
$ignore[$i] = strtr($ignore[$i], "\\", "/"); |
$ignore[$i] = str_replace('//','/',$ignore[$i]); |
if (!empty($ignore[$i])) { |
if (!is_numeric(strpos($ignore[$i], '/'))) { |
$ig[] = $this->_getRegExpableSearchString($ignore[$i]); |
} else { |
if (basename($ignore[$i]) . '/' == $ignore[$i]) { |
$ig[] = $this->_getRegExpableSearchString($ignore[$i]); |
} else { |
$ig[] = array($this->_getRegExpableSearchString($ignore[$i]), |
$this->_getRegExpableSearchString(basename($ignore[$i]))); |
} |
} |
} |
} |
if (count($ig)) { |
$this->ignore[$index] = $ig; |
} else { |
$this->ignore[$index] = false; |
} |
} else $this->ignore[$index] = false; |
} |
/** |
* Converts $s into a string that can be used with preg_match |
* @param string $s string with wildcards ? and * |
* @return string converts * to .*, ? to ., etc. |
* @access private |
*/ |
function _getRegExpableSearchString($s) |
{ |
$y = '\/'; |
if (DIRECTORY_SEPARATOR == '\\') { |
$y = '\\\\'; |
} |
$s = str_replace('/', DIRECTORY_SEPARATOR, $s); |
$x = strtr($s, array('?' => '.','*' => '.*','.' => '\\.','\\' => '\\\\','/' => '\\/', |
'[' => '\\[',']' => '\\]','-' => '\\-')); |
if (strpos($s, DIRECTORY_SEPARATOR) !== false && |
strrpos($s, DIRECTORY_SEPARATOR) === strlen($s) - 1) { |
$x = "(?:.*$y$x?.*|$x.*)"; |
} |
return $x; |
} |
/** |
* Recursively move contents of $struc into associative array |
* |
* The contents of $struc have many indexes like 'dir/subdir/subdir2'. |
* This function converts them to |
* array('dir' => array('subdir' => array('subdir2'))) |
* @param array struc is array('dir' => array of files in dir, |
* 'dir/subdir' => array of files in dir/subdir,...) |
* @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2') |
* @return array same as struc but with array('dir' => |
* array(file1,file2,'subdir' => array(file1,...))) |
* @access private |
*/ |
function _setupDirs($struc, $dir, $contents) |
{ |
if (!count($dir)) { |
foreach($contents as $dir => $files) { |
if (is_string($dir)) { |
if (strpos($dir, '/')) { |
$test = true; |
$a = $contents[$dir]; |
unset($contents[$dir]); |
$b = explode('/', $dir); |
$c = array_shift($b); |
if (isset($contents[$c])) { |
$contents[$c] = $this->_setDir($contents[$c], $this->_setupDirs(array(), $b, $a)); |
} else { |
$contents[$c] = $this->_setupDirs(array(), $b, $a); |
} |
} |
} |
} |
return $contents; |
} |
$me = array_shift($dir); |
if (!isset($struc[$me])) { |
$struc[$me] = array(); |
} |
$struc[$me] = $this->_setupDirs($struc[$me], $dir, $contents); |
return $struc; |
} |
/** |
* Recursively add all the subdirectories of $contents to $dir without erasing anything in |
* $dir |
* @param array |
* @param array |
* @return array processed $dir |
* @access private |
*/ |
function _setDir($dir, $contents) |
{ |
while(list($one,$two) = each($contents)) { |
if (isset($dir[$one])) { |
$dir[$one] = $this->_setDir($dir[$one], $contents[$one]); |
} else { |
$dir[$one] = $two; |
} |
} |
return $dir; |
} |
/**#@+ |
* Sorting functions for the file list |
* @param string |
* @param string |
* @access private |
*/ |
function sortfiles($a, $b) |
{ |
return strnatcasecmp($a['file'],$b['file']); |
} |
function mystrucsort($a, $b) |
{ |
if (is_numeric($a) && is_string($b)) return 1; |
if (is_numeric($b) && is_string($a)) return -1; |
if (is_numeric($a) && is_numeric($b)) |
{ |
if ($a > $b) return 1; |
if ($a < $b) return -1; |
if ($a == $b) return 0; |
} |
return strnatcasecmp($a,$b); |
} |
/**#@-*/ |
} |
?> |
/trunk/bibliotheque/pear/PEAR/PackageFileManager/SimpleGenerator.php |
---|
New file |
0,0 → 1,323 |
<?php |
// |
// +------------------------------------------------------------------------+ |
// | PEAR :: Package File Manager | |
// +------------------------------------------------------------------------+ |
// | Copyright (c) 2004 Gregory Beaver | |
// | Email cellog@phpdoc.org | |
// +------------------------------------------------------------------------+ |
// | This source file is subject to version 3.00 of the PHP License, | |
// | that is available at http://www.php.net/license/3_0.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +------------------------------------------------------------------------+ |
// | Portions of this code based on phpDocumentor | |
// | Web http://www.phpdoc.org | |
// | Mirror http://phpdocu.sourceforge.net/ | |
// +------------------------------------------------------------------------+ |
// $Id: SimpleGenerator.php,v 1.4 2005/05/20 22:42:59 cellog Exp $ |
// |
require_once 'PEAR/PackageFile/Generator/v1.php'; |
/** |
* Class for XML output |
* |
* @author Greg Beaver <cellog@php.net> |
* @since 1.2.0 |
* @copyright 2003 |
* @package PEAR_PackageFileManager |
*/ |
class PEAR_PackageFileManager_SimpleGenerator extends PEAR_PackageFile_Generator_v1 |
{ |
var $_options; |
/** |
* remove a warning about missing parameters - don't delete this |
*/ |
function PEAR_PackageFileManager_SimpleGenerator() |
{ |
} |
/** |
* @param array |
*/ |
function setPackageFileManagerOptions($opts) |
{ |
$this->_options = $opts; |
} |
/** |
* Return an XML document based on the package info (as returned |
* by the PEAR_Common::infoFrom* methods). |
* |
* @param array $pkginfo package info |
* |
* @return string XML data |
* |
* @access public |
* @deprecated use a PEAR_PackageFile_v* object's generator instead |
*/ |
function xmlFromInfo($pkginfo) |
{ |
include_once 'PEAR/PackageFile.php'; |
include_once 'PEAR/Config.php'; |
$config = &PEAR_Config::singleton(); |
$packagefile = &new PEAR_PackageFile($config); |
$pf = &$packagefile->fromArray($pkginfo); |
parent::PEAR_PackageFile_Generator_v1($pf); |
return $this->toXml(); |
} |
function getFileRoles() |
{ |
return PEAR_Common::getFileRoles(); |
} |
function getReplacementTypes() |
{ |
return PEAR_Common::getReplacementTypes(); |
} |
/** |
* Validate XML package definition file. |
* |
* @param string $info Filename of the package archive or of the |
* package definition file |
* @param array $errors Array that will contain the errors |
* @param array $warnings Array that will contain the warnings |
* @param string $dir_prefix (optional) directory where source files |
* may be found, or empty if they are not available |
* @access public |
* @return boolean |
* @deprecated use the validation of PEAR_PackageFile objects |
*/ |
function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') |
{ |
include_once 'PEAR/PackageFile.php'; |
include_once 'PEAR/Config.php'; |
$config = &PEAR_Config::singleton(); |
$packagefile = &new PEAR_PackageFile($config); |
PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); |
if (is_array($info)) { |
$pf = &$packagefile->fromArray($info); |
if (!$pf->validate(PEAR_VALIDATE_NORMAL)) { |
foreach ($pf->getValidationWarnings() as $err) { |
if ($error['level'] == 'error') { |
$errors[] = $error['message']; |
} else { |
$warnings[] = $error['message']; |
} |
} |
return false; |
} |
} else { |
$pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); |
} |
PEAR::staticPopErrorHandling(); |
if (PEAR::isError($pf)) { |
$errs = $pf->getUserinfo(); |
if (is_array($errs)) { |
foreach ($errs as $error) { |
if ($error['level'] == 'error') { |
$errors[] = $error['message']; |
} else { |
$warnings[] = $error['message']; |
} |
} |
} |
return false; |
} |
return true; |
} |
/** |
* @param array |
* @access protected |
*/ |
function recursiveXmlFilelist($list) |
{ |
$this->_dirs = array(); |
foreach ($list as $file => $attributes) { |
$this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); |
} |
if (!isset($this->_dirs['dirs'])) { |
$this->_dirs['dirs'] = array(); |
} |
if (count($this->_dirs['dirs']) != 1 || isset($this->_dirs['files'])) { |
$this->_dirs = array('dirs' => array('/' => $this->_dirs)); |
} |
return $this->_formatDir($this->_dirs, '', '', true); |
} |
/** |
* @param array |
* @param array |
* @param string|null |
* @param array|null |
* @access private |
*/ |
function _addDir(&$dirs, $dir, $file = null, $attributes = null) |
{ |
if ($dir == array() || $dir == array('.')) { |
$dirs['files'][basename($file)] = $attributes; |
return; |
} |
$curdir = array_shift($dir); |
if (!isset($dirs['dirs'][$curdir])) { |
$dirs['dirs'][$curdir] = array(); |
} |
$this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); |
} |
/** |
* @param array |
* @param string |
* @param string |
* @access private |
*/ |
function _formatDir($dirs, $indent = '', $curdir = '', $toplevel = false) |
{ |
$ret = ''; |
if (!count($dirs)) { |
return ''; |
} |
if (isset($dirs['dirs'])) { |
uksort($dirs['dirs'], 'strnatcasecmp'); |
foreach ($dirs['dirs'] as $dir => $contents) { |
if ($dir == '/') { |
$usedir = '/'; |
} else { |
if ($curdir == '/') { |
$curdir = ''; |
} |
$usedir = "$curdir/$dir"; |
} |
$ret .= "$indent <dir name=\"$dir\""; |
if ($toplevel) { |
$ret .= ' baseinstalldir="' . $this->_options['baseinstalldir'] . '"'; |
} else { |
if (isset($this->_options['installexceptions'][$dir])) { |
$ret .= ' baseinstalldir="' . $this->_options['installexceptions'][$dir] . '"'; |
} |
} |
$ret .= ">\n"; |
$ret .= $this->_formatDir($contents, "$indent ", $usedir); |
$ret .= "$indent </dir> <!-- $usedir -->\n"; |
} |
} |
if (isset($dirs['files'])) { |
uksort($dirs['files'], 'strnatcasecmp'); |
foreach ($dirs['files'] as $file => $attribs) { |
$ret .= $this->_formatFile($file, $attribs, $indent); |
} |
} |
return $ret; |
} |
/** |
* @param string |
* @param array |
* @param string |
* @access private |
*/ |
function _formatFile($file, $attributes, $indent) |
{ |
$ret = "$indent <file role=\"$attributes[role]\""; |
if (isset($this->_options['installexceptions'][$file])) { |
$ret .= ' baseinstalldir="' . $this->_options['installexceptions'][$file] . '"'; |
} |
if (isset($attributes['md5sum'])) { |
$ret .= " md5sum=\"$attributes[md5sum]\""; |
} |
if (isset($attributes['platform'])) { |
$ret .= " platform=\"$attributes[platform]\""; |
} |
if (!empty($attributes['install-as'])) { |
$ret .= ' install-as="' . |
htmlspecialchars($attributes['install-as']) . '"'; |
} |
$ret .= ' name="' . htmlspecialchars($file) . '"'; |
if (empty($attributes['replacements'])) { |
$ret .= "/>\n"; |
} else { |
$ret .= ">\n"; |
foreach ($attributes['replacements'] as $r) { |
$ret .= "$indent <replace"; |
foreach ($r as $k => $v) { |
$ret .= " $k=\"" . htmlspecialchars($v) .'"'; |
} |
$ret .= "/>\n"; |
} |
$ret .= "$indent </file>\n"; |
} |
return $ret; |
} |
/** |
* Generate the <filelist> tag |
* @access private |
* @return string |
*/ |
function _doFileList($indent, $filelist, $curdir) |
{ |
$ret = ''; |
foreach ($filelist as $file => $fa) { |
if (isset($fa['##files'])) { |
$ret .= "$indent <dir"; |
} else { |
$ret .= "$indent <file"; |
} |
if (isset($fa['role'])) { |
$ret .= " role=\"$fa[role]\""; |
} |
if (isset($fa['baseinstalldir'])) { |
$ret .= ' baseinstalldir="' . |
htmlspecialchars($fa['baseinstalldir']) . '"'; |
} |
if (isset($fa['md5sum'])) { |
$ret .= " md5sum=\"$fa[md5sum]\""; |
} |
if (isset($fa['platform'])) { |
$ret .= " platform=\"$fa[platform]\""; |
} |
if (!empty($fa['install-as'])) { |
$ret .= ' install-as="' . |
htmlspecialchars($fa['install-as']) . '"'; |
} |
$ret .= ' name="' . htmlspecialchars($file) . '"'; |
if (isset($fa['##files'])) { |
$ret .= ">\n"; |
$recurdir = $curdir; |
if ($recurdir == '///') { |
$recurdir = ''; |
} |
$ret .= $this->_doFileList("$indent ", $fa['##files'], $recurdir . $file . '/'); |
$displaydir = $curdir; |
if ($displaydir == '///' || $displaydir == '/') { |
$displaydir = ''; |
} |
$ret .= "$indent </dir> <!-- $displaydir$file -->\n"; |
} else { |
if (empty($fa['replacements'])) { |
$ret .= "/>\n"; |
} else { |
$ret .= ">\n"; |
foreach ($fa['replacements'] as $r) { |
$ret .= "$indent <replace"; |
foreach ($r as $k => $v) { |
$ret .= " $k=\"" . htmlspecialchars($v) .'"'; |
} |
$ret .= "/>\n"; |
} |
$ret .= "$indent </file>\n"; |
} |
} |
} |
return $ret; |
} |
} |
?> |
/trunk/bibliotheque/pear/PEAR/PackageFileManager/XMLOutput.php |
---|
New file |
0,0 → 1,180 |
<?php |
// |
// +------------------------------------------------------------------------+ |
// | PEAR :: Package File Manager | |
// +------------------------------------------------------------------------+ |
// | Copyright (c) 2004 Gregory Beaver | |
// | Email cellog@phpdoc.org | |
// +------------------------------------------------------------------------+ |
// | This source file is subject to version 3.00 of the PHP License, | |
// | that is available at http://www.php.net/license/3_0.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +------------------------------------------------------------------------+ |
// | Portions of this code based on phpDocumentor | |
// | Web http://www.phpdoc.org | |
// | Mirror http://phpdocu.sourceforge.net/ | |
// +------------------------------------------------------------------------+ |
// $Id: XMLOutput.php,v 1.4 2004/02/07 18:04:00 cellog Exp $ |
// |
/** |
* Class for XML output |
* |
* @author Greg Beaver <cellog@php.net> |
* @since 1.2.0 |
* @copyright 2003 |
* @package PEAR_PackageFileManager |
*/ |
class PEAR_PackageFileManager_XMLOutput extends PEAR_Common { |
/** |
* Generate part of an XML description with release information. |
* |
* @param array $pkginfo array with release information |
* @param bool $changelog whether the result will be in a changelog element |
* |
* @return string XML data |
* |
* @access private |
*/ |
function _makeReleaseXml($pkginfo, $changelog = false) |
{ |
$indent = $changelog ? " " : ""; |
$ret = "$indent <release>\n"; |
if (!empty($pkginfo['version'])) { |
$ret .= "$indent <version>$pkginfo[version]</version>\n"; |
} |
if (!empty($pkginfo['release_date'])) { |
$ret .= "$indent <date>$pkginfo[release_date]</date>\n"; |
} |
if (!empty($pkginfo['release_license'])) { |
$ret .= "$indent <license>$pkginfo[release_license]</license>\n"; |
} |
if (!empty($pkginfo['release_state'])) { |
$ret .= "$indent <state>$pkginfo[release_state]</state>\n"; |
} |
if (!empty($pkginfo['release_notes'])) { |
$ret .= "$indent <notes>".htmlspecialchars($pkginfo['release_notes'])."</notes>\n"; |
} |
if (!empty($pkginfo['release_warnings'])) { |
$ret .= "$indent <warnings>".htmlspecialchars($pkginfo['release_warnings'])."</warnings>\n"; |
} |
if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { |
$ret .= "$indent <deps>\n"; |
foreach ($pkginfo['release_deps'] as $dep) { |
$ret .= "$indent <dep type=\"$dep[type]\" rel=\"$dep[rel]\""; |
if (isset($dep['version'])) { |
$ret .= " version=\"$dep[version]\""; |
} |
if (isset($dep['optional'])) { |
$ret .= " optional=\"$dep[optional]\""; |
} |
if (isset($dep['name'])) { |
$ret .= ">$dep[name]</dep>\n"; |
} else { |
$ret .= "/>\n"; |
} |
} |
$ret .= "$indent </deps>\n"; |
} |
if (isset($pkginfo['configure_options'])) { |
$ret .= "$indent <configureoptions>\n"; |
foreach ($pkginfo['configure_options'] as $c) { |
$ret .= "$indent <configureoption name=\"". |
htmlspecialchars($c['name']) . "\""; |
if (isset($c['default'])) { |
$ret .= " default=\"" . htmlspecialchars($c['default']) . "\""; |
} |
$ret .= " prompt=\"" . htmlspecialchars($c['prompt']) . "\""; |
$ret .= "/>\n"; |
} |
$ret .= "$indent </configureoptions>\n"; |
} |
if (isset($pkginfo['provides'])) { |
foreach ($pkginfo['provides'] as $key => $what) { |
$ret .= "$indent <provides type=\"$what[type]\" "; |
$ret .= "name=\"$what[name]\" "; |
if (isset($what['extends'])) { |
$ret .= "extends=\"$what[extends]\" "; |
} |
$ret .= "/>\n"; |
} |
} |
if (isset($pkginfo['filelist'])) { |
$ret .= "$indent <filelist>\n"; |
$ret .= $this->_doFileList($indent, $pkginfo['filelist'], '/'); |
$ret .= "$indent </filelist>\n"; |
} |
$ret .= "$indent </release>\n"; |
return $ret; |
} |
/** |
* Generate the <filelist> tag |
* @access private |
* @return string |
*/ |
function _doFileList($indent, $filelist, $curdir) |
{ |
$ret = ''; |
foreach ($filelist as $file => $fa) { |
if (isset($fa['##files'])) { |
$ret .= "$indent <dir"; |
} else { |
$ret .= "$indent <file"; |
} |
if (isset($fa['role'])) { |
$ret .= " role=\"$fa[role]\""; |
} |
if (isset($fa['baseinstalldir'])) { |
$ret .= ' baseinstalldir="' . |
htmlspecialchars($fa['baseinstalldir']) . '"'; |
} |
if (isset($fa['md5sum'])) { |
$ret .= " md5sum=\"$fa[md5sum]\""; |
} |
if (isset($fa['platform'])) { |
$ret .= " platform=\"$fa[platform]\""; |
} |
if (!empty($fa['install-as'])) { |
$ret .= ' install-as="' . |
htmlspecialchars($fa['install-as']) . '"'; |
} |
$ret .= ' name="' . htmlspecialchars($file) . '"'; |
if (isset($fa['##files'])) { |
$ret .= ">\n"; |
$recurdir = $curdir; |
if ($recurdir == '///') { |
$recurdir = ''; |
} |
$ret .= $this->_doFileList("$indent ", $fa['##files'], $recurdir . $file . '/'); |
$displaydir = $curdir; |
if ($displaydir == '///' || $displaydir == '/') { |
$displaydir = ''; |
} |
$ret .= "$indent </dir> <!-- $displaydir$file -->\n"; |
} else { |
if (empty($fa['replacements'])) { |
$ret .= "/>\n"; |
} else { |
$ret .= ">\n"; |
foreach ($fa['replacements'] as $r) { |
$ret .= "$indent <replace"; |
foreach ($r as $k => $v) { |
$ret .= " $k=\"" . htmlspecialchars($v) .'"'; |
} |
$ret .= "/>\n"; |
} |
$ret .= "$indent </file>\n"; |
} |
} |
} |
return $ret; |
} |
} |
?> |
/trunk/bibliotheque/pear/PEAR/PackageFileManager/Perforce.php |
---|
New file |
0,0 → 1,102 |
<?php |
/* |
* +------------------------------------------------------------------------+ |
* | PEAR :: Package File Manager :: Perforce | |
* +------------------------------------------------------------------------+ |
* | Copyright (c) 2004 Jon Parise | |
* | Email jon@php.net | |
* +------------------------------------------------------------------------+ |
* | This source file is subject to version 3.00 of the PHP License, | |
* | that is available at http://www.php.net/license/3_0.txt. | |
* | If you did not receive a copy of the PHP license and are unable to | |
* | obtain it through the world-wide-web, please send a note to | |
* | license@php.net so we can mail you a copy immediately. | |
* +------------------------------------------------------------------------+ |
* $Id: Perforce.php,v 1.2 2004/08/25 06:02:30 jon Exp $ |
*/ |
/** |
* @package PEAR_PackageFileManager |
*/ |
/** |
* The PEAR_PackageFileManager_File class |
*/ |
require_once 'PEAR/PackageFileManager/File.php'; |
/** |
* Generate a file list from a Perforce checkout. This requires the 'p4' |
* command line client, a properly-configured Perforce environment, and a |
* connection to the Perforce server. Specifically, the 'p4 have' command |
* is used to determine which local files are under Perforce's control. |
* |
* @author Jon Parise <jon@php.net> |
* @package PEAR_PackageFileManager |
*/ |
class PEAR_PackageFileManager_Perforce extends PEAR_PackageFileManager_File |
{ |
/** |
* Build a list of files based on the output of the 'p4 have' command. |
* |
* @param string $directory The directory in which to list the files. |
* |
* @return mixed An array of full filenames or a PEAR_Error value if |
* $directory does not exist. |
*/ |
function dirList($directory) |
{ |
/* Return an error if the directory does not exist. */ |
if (@is_dir($directory) === false) { |
return PEAR_PackageFileManager::raiseError( |
PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST, |
$directory); |
} |
/* List the files below $directory that are under Perforce control. */ |
exec("p4 have $directory/...", $output); |
/* Strip off everything except the filename from each line of output. */ |
$files = preg_replace('/^.* \- /', '', $output); |
/* If we have a list of files to include, remove all other entries. */ |
if ($this->ignore[0]) { |
$files = array_filter($files, array($this, '_includeFilter')); |
} |
/* If we have a list of files to ignore, remove them from the array. */ |
if ($this->ignore[1]) { |
$files = array_filter($files, array($this, '_ignoreFilter')); |
} |
return $files; |
} |
/** |
* Determine whether a given file should be excluded from the file list. |
* |
* @param string $file The full pathname of file to check. |
* |
* @return bool True if the specified file should be included. |
* |
* @access private |
*/ |
function _includeFilter($file) |
{ |
return ($this->_checkIgnore(basename($file), $file, 0) === 0); |
} |
/** |
* Determine whether a given file should be included (i.e., not ignored) |
* from the file list. |
* |
* @param string $file The full pathname of file to check. |
* |
* @return bool True if the specified file should be included. |
* |
* @access private |
*/ |
function _ignoreFilter($file) |
{ |
return ($this->_checkIgnore(basename($file), $file, 1) !== 1); |
} |
} |
/trunk/bibliotheque/pear/PEAR/PackageFileManager/Svn.php |
---|
New file |
0,0 → 1,169 |
<?php |
// |
// +------------------------------------------------------------------------+ |
// | PEAR :: Package File Manager | |
// +------------------------------------------------------------------------+ |
// | Copyright (c) 2003-2004 Gregory Beaver | |
// | Email cellog@phpdoc.org | |
// +------------------------------------------------------------------------+ |
// | This source file is subject to version 3.00 of the PHP License, | |
// | that is available at http://www.php.net/license/3_0.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +------------------------------------------------------------------------+ |
// | Portions of this code based on phpDocumentor | |
// | Web http://www.phpdoc.org | |
// | Mirror http://phpdocu.sourceforge.net/ | |
// +------------------------------------------------------------------------+ |
// $Id: Svn.php,v 1.1 2004/05/31 12:02:31 arnaud Exp $ |
// |
/** |
* @package PEAR_PackageFileManager |
*/ |
/** |
* The PEAR_PackageFileManager_File class |
*/ |
require_once 'PEAR/PackageFileManager/File.php'; |
/** |
* Generate a file list from a Subversion checkout |
* |
* Largely based on the CVS class, modified to suit |
* subversion organization. |
* |
* Note that this will <b>NOT</b> work on a |
* repository, only on a checked out Subversion module |
* @package PEAR_PackageFileManager |
* @author Arnaud Limbour <arnaud@limbourg.com> |
*/ |
class PEAR_PackageFileManager_Svn extends PEAR_PackageFileManager_File |
{ |
/** |
* Return a list of all files in the CVS repository |
* |
* This function is like {@link parent::dirList()} except |
* that instead of retrieving a regular filelist, it first |
* retrieves a listing of all the .svn/entries files in |
* $directory and all of the subdirectories. Then, it |
* reads the entries file, and creates a listing of files |
* that are a part of the Subversion checkout. No check is |
* made to see if they have been modified, but removed files |
* are ignored. |
* |
* @access protected |
* @return array list of files in a directory |
* @param string $directory full path to the directory you want the list of |
* @uses _recurDirList() |
* @uses _readSVNEntries() |
*/ |
function dirList($directory) |
{ |
static $in_recursion = false; |
if (!$in_recursion) { |
// include only .svn/entries files |
// since subversion keeps its data in a hidden |
// directory we must force PackageFileManager to |
// consider hidden directories. |
$this->_options['addhiddenfiles'] = true; |
$this->_setupIgnore(array('*/.svn/entries'), 0); |
$this->_setupIgnore(array(), 1); |
$in_recursion = true; |
$entries = parent::dirList($directory); |
$in_recursion = false; |
} else { |
return parent::dirList($directory); |
} |
if (!$entries || !is_array($entries)) { |
return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_NOSVNENTRIES, $directory); |
} |
return $this->_readSVNEntries($entries); |
} |
/** |
* Iterate over the SVN Entries files, and retrieve every |
* file in the repository |
* |
* @uses _getSVNEntries() |
* @param array array of full paths to .svn/entries files |
* @access private |
*/ |
function _readSVNEntries($entries) |
{ |
$ret = array(); |
$ignore = $this->_options['ignore']; |
// implicitly ignore packagefile |
$ignore[] = $this->_options['packagefile']; |
$include = $this->_options['include']; |
$this->ignore = array(false, false); |
$this->_setupIgnore($ignore, 1); |
$this->_setupIgnore($include, 0); |
foreach($entries as $cvsentry) { |
$directory = @dirname(@dirname($cvsentry)); |
if (!$directory) { |
continue; |
} |
$d = $this->_getSVNEntries($cvsentry); |
if (!is_array($d)) { |
continue; |
} |
foreach($d as $entry) { |
if ($ignore) { |
if ($this->_checkIgnore($entry, |
$directory . '/' . $entry, 1)) { |
continue; |
} |
} |
if ($include) { |
if ($this->_checkIgnore($entry, |
$directory . '/' . $entry, 0)) { |
continue; |
} |
} |
$ret[] = $directory . '/' . $entry; |
} |
} |
return $ret; |
} |
/** |
* Retrieve the entries in a .svn/entries file |
* |
* Uses XML_Tree to parse the XML subversion file |
* |
* It keeps only files, excluding directories. It also |
* makes sure no deleted file in included. |
* |
* @return array an array with full paths to files |
* @uses PEAR::XML_Tree |
* @param string full path to a .svn/entries file |
* @access private |
*/ |
function _getSVNEntries($svnentriesfilename) |
{ |
require_once 'XML/Tree.php'; |
$parser = &new XML_Tree($svnentriesfilename); |
$tree = &$parser->getTreeFromFile(); |
// loop through the xml tree and keep only valid entries being files |
$entries = array(); |
foreach ($tree->children as $entry) { |
if ($entry->name == 'entry' |
&& $entry->attributes['kind'] == 'file') { |
if (isset($entry->attributes['deleted'])) { |
continue; |
} |
array_push($entries, $entry->attributes['name']); |
} |
} |
unset($parser, $tree); |
if (is_array($entries)) { |
return $entries; |
} else { |
return false; |
} |
} |
} |
?> |
/trunk/bibliotheque/pear/PEAR/PackageFileManager/Cvs.php |
---|
New file |
0,0 → 1,175 |
<?php |
// |
// +------------------------------------------------------------------------+ |
// | PEAR :: Package File Manager | |
// +------------------------------------------------------------------------+ |
// | Copyright (c) 2003-2004 Gregory Beaver | |
// | Email cellog@phpdoc.org | |
// +------------------------------------------------------------------------+ |
// | This source file is subject to version 3.00 of the PHP License, | |
// | that is available at http://www.php.net/license/3_0.txt. | |
// | If you did not receive a copy of the PHP license and are unable to | |
// | obtain it through the world-wide-web, please send a note to | |
// | license@php.net so we can mail you a copy immediately. | |
// +------------------------------------------------------------------------+ |
// | Portions of this code based on phpDocumentor | |
// | Web http://www.phpdoc.org | |
// | Mirror http://phpdocu.sourceforge.net/ | |
// +------------------------------------------------------------------------+ |
// $Id: Cvs.php,v 1.9 2005/03/25 22:37:15 cellog Exp $ |
// |
/** |
* @package PEAR_PackageFileManager |
*/ |
/** |
* The PEAR_PackageFileManager_File class |
*/ |
require_once 'PEAR/PackageFileManager/File.php'; |
/** |
* Generate a file list from a CVS checkout |
* |
* Note that this will <b>NOT</b> work on a |
* repository, only on a checked out CVS module |
* @package PEAR_PackageFileManager |
*/ |
class PEAR_PackageFileManager_CVS extends PEAR_PackageFileManager_File { |
/** |
* List of CVS-specific files that may exist in CVS but should be |
* ignored when building the package's file list. |
* @var array |
* @access private |
*/ |
var $_cvsIgnore = array('.cvsignore'); |
/** |
* Return a list of all files in the CVS repository |
* |
* This function is like {@link parent::dirList()} except |
* that instead of retrieving a regular filelist, it first |
* retrieves a listing of all the CVS/Entries files in |
* $directory and all of the subdirectories. Then, it |
* reads the Entries file, and creates a listing of files |
* that are a part of the CVS repository. No check is |
* made to see if they have been modified, but newly |
* added or removed files are ignored. |
* @return array list of files in a directory |
* @param string $directory full path to the directory you want the list of |
* @uses _recurDirList() |
* @uses _readCVSEntries() |
*/ |
function dirList($directory) |
{ |
static $in_recursion = false; |
if (!$in_recursion) { |
// include only CVS/Entries files |
$this->_setupIgnore(array('*/CVS/Entries'), 0); |
$this->_setupIgnore(array(), 1); |
$in_recursion = true; |
$entries = parent::dirList($directory); |
$in_recursion = false; |
} else { |
return parent::dirList($directory); |
} |
if (!$entries || !is_array($entries)) { |
return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES, $directory); |
} |
return $this->_readCVSEntries($entries); |
} |
/** |
* Iterate over the CVS Entries files, and retrieve every |
* file in the repository |
* @uses _getCVSEntries() |
* @uses _isCVSFile() |
* @param array array of full paths to CVS/Entries files |
* @access private |
*/ |
function _readCVSEntries($entries) |
{ |
$ret = array(); |
$ignore = array_merge((array) $this->_options['ignore'], $this->_cvsIgnore); |
// implicitly ignore packagefile |
$ignore[] = $this->_options['packagefile']; |
$include = $this->_options['include']; |
$this->ignore = array(false, false); |
$this->_setupIgnore($ignore, 1); |
$this->_setupIgnore($include, 0); |
foreach($entries as $cvsentry) { |
$directory = @dirname(@dirname($cvsentry)); |
if (!$directory) { |
continue; |
} |
$d = $this->_getCVSEntries($cvsentry); |
if (!is_array($d)) { |
continue; |
} |
foreach($d as $entry) { |
if ($ignore) { |
if ($this->_checkIgnore($this->_getCVSFileName($entry), |
$directory . '/' . $this->_getCVSFileName($entry), 1)) { |
// print 'Ignoring '.$file."<br>\n"; |
continue; |
} |
} |
if ($include) { |
if ($this->_checkIgnore($this->_getCVSFileName($entry), |
$directory . '/' . $this->_getCVSFileName($entry), 0)) { |
// print 'Including '.$file."<br\n"; |
continue; |
} |
} |
if ($this->_isCVSFile($entry)) { |
$ret[] = $directory . '/' . $this->_getCVSFileName($entry); |
} |
} |
} |
return $ret; |
} |
/** |
* Retrieve the filename from an entry |
* |
* This method assumes that the entry is a file, |
* use _isCVSFile() to verify before calling |
* @param string a line in a CVS/Entries file |
* @return string the filename (no path information) |
* @access private |
*/ |
function _getCVSFileName($cvsentry) |
{ |
$stuff = explode('/', $cvsentry); |
array_shift($stuff); |
return array_shift($stuff); |
} |
/** |
* Retrieve the entries in a CVS/Entries file |
* @return array each line of the entries file, output of file() |
* @uses function file() |
* @param string full path to a CVS/Entries file |
* @access private |
*/ |
function _getCVSEntries($cvsentryfilename) |
{ |
$cvsfile = @file($cvsentryfilename); |
if (is_array($cvsfile)) { |
return $cvsfile; |
} else { |
return false; |
} |
} |
/** |
* Check whether an entry is a file or a directory |
* @return boolean |
* @param string a line in a CVS/Entries file |
* @access private |
*/ |
function _isCVSFile($cvsentry) |
{ |
// make sure we ignore entries that have either been removed or added, but not committed yet |
return $cvsentry{0} == '/' && !strpos($cvsentry, 'dummy timestamp'); |
} |
} |
?> |