542 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			542 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?
 | |
| class XMLDB{
 | |
| 
 | |
| 	const SELECT = 'select';
 | |
| 	const INSERT = 'insert';
 | |
| 	const DELETE = 'delete';
 | |
| 	const UPDATE = 'update';
 | |
| 
 | |
| 	/**
 | |
| 	 * Request
 | |
| 	 */
 | |
| 	protected $current_request;
 | |
| 	protected $operation;
 | |
| 	protected $from;
 | |
|     protected $setID;
 | |
|     protected $setChild;
 | |
| 	protected $whereID;
 | |
| 	protected $whereChildren;
 | |
|     protected $position;
 | |
| 
 | |
| 	// Path and name to the file
 | |
| 	protected $_file;
 | |
| 
 | |
| 	// Primary key
 | |
| 	protected $_primaryKey;
 | |
| 
 | |
| 	// Selected table
 | |
| 	protected $_table;
 | |
| 
 | |
| 	// XPATH of the doc
 | |
| 	protected $_xpath;
 | |
| 
 | |
| 	// Content of the XML DB File
 | |
| 	protected $_doc;
 | |
| 
 | |
| 	// Name of the main root
 | |
| 	protected $_databaseName;
 | |
| 
 | |
| 	// Name of each table root
 | |
| 	protected $_tableName;
 | |
| 
 | |
| 	// Name of each item inside tables
 | |
| 	protected $_itemName;
 | |
| 
 | |
| 	// Encoding used for the XML
 | |
| 	protected $_encoding;
 | |
| 
 | |
| 	// Node buffered
 | |
| 	protected $_buffer;
 | |
| 
 | |
| 
 | |
| 
 | |
| 	/**
 | |
| 	 * Constructor
 | |
| 	 * @param $file string path to the file to read/create
 | |
| 	 * @param $pk string name of the primary key
 | |
| 	 * @param $createIfNotExist bool create the file if it doesn't exist
 | |
| 	 */
 | |
| 	public function __construct($file, $pk = "id", $createIfNotExist = false, $databaseName = "Database", $tableName = "table", $itemName = "item", $encoding = "utf-8"){
 | |
| 		$this->_buffer			= null;
 | |
| 		$this->_databaseName 	= $databaseName;
 | |
| 		$this->_itemName 		= $itemName;
 | |
| 		$this->_tableName 		= $tableName;
 | |
| 		$this->_encoding 		= $encoding;
 | |
| 		$this->_primaryKey 		= $pk;
 | |
| 		$this->_file 			= $file;
 | |
| 		$this->_doc 			= new DOMDocument;
 | |
| 		$this->_doc->preserveWhiteSpace = false;
 | |
| 		$this->_doc->formatOutput = true;
 | |
| 		if($this->_doc->load($this->_file)){
 | |
| 			$this->_xpath = new DOMXpath($this->_doc);
 | |
| 		}
 | |
| 		else{
 | |
| 			if($createIfNotExist){
 | |
| 				$this->createDatabase($file);
 | |
| 			}else{
 | |
| 				$this->_file 	= null;
 | |
| 				$this->_doc 	= null;
 | |
| 				$this->xpath 	= null;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
|     public function __destruct(){
 | |
|         $this->commit();
 | |
|     }
 | |
| 
 | |
| 	public function createDatabase($file){
 | |
| 		$this->_file 	= $file;
 | |
| 		$this->_doc 	= DOMDocument::loadXML('<?xml version="1.0" encoding="' . $this->_encoding . '"?>
 | |
| 			<' . $this->_databaseName . '>
 | |
| 			</' . $this->_databaseName . '>');
 | |
| 		$this->_xpath 	= new DOMXpath($this->_doc);
 | |
| 		return $this->commit();
 | |
| 	}
 | |
| 
 | |
| 	public function dropDatabase($definitely = false){
 | |
| 		if($definitely){
 | |
| 			unlink($this->_file);
 | |
| 		}else{
 | |
| 			$this->createDatabase($this->_file);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
|     /**
 | |
| 	 * @return bool
 | |
| 	 */
 | |
| 	public function tableAlreadyExists($tableName){
 | |
| 		$request = $this->_xpath->query('//' .  $this->_tableName . '[@name = "'.$tableName.'"]');
 | |
| 		if($this->getResult($request, 'count') >= 1)
 | |
| 			return true;
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	public function isTableAI($tableName){
 | |
| 		if($this->tableAlreadyExists($tableName)){
 | |
| 			$table = $this->_xpath->query('//' .  $this->_tableName . '[@name = "'.$tableName.'"]');
 | |
| 			$ai = $this->getAttribute('autoincrement', $table);
 | |
| 			if($ai == 'true')
 | |
| 				return true;
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
|     public function isLoaded(){
 | |
| 		if($this->_doc != null)
 | |
| 			return true;
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 
 | |
|    	public function setPrimaryKey($pk){
 | |
| 		$this->_primaryKey = $pk;
 | |
| 	}
 | |
| 
 | |
| 	public function getPrimaryKey(){
 | |
| 		return $this->_primaryKey;
 | |
| 	}
 | |
| 
 | |
| 	public function getXPath(){
 | |
| 		return $this->_xpath;
 | |
| 	}
 | |
| 
 | |
| 	public function setBuffer($node){
 | |
| 		$this->_buffer = $node;
 | |
| 	}
 | |
| 
 | |
| 	public function getBuffer($buffer){
 | |
| 		return $this->_buffer;
 | |
| 	}
 | |
| 
 | |
|     /**
 | |
| 	 * Saving the DB file
 | |
| 	 */
 | |
| 	 public function commit(){
 | |
| 		if($this->_doc != null && $this->_file != null){
 | |
| 			$this->_doc->preserveWhiteSpace = false;
 | |
| 			$this->_doc->formatOutput = true;
 | |
| 			$this->_doc->save($this->_file);
 | |
| 			return true;
 | |
| 		}else{
 | |
| 			return false;
 | |
| 		}
 | |
| 	 }
 | |
|      
 | |
| 	public function createTable($name, $autoincrement = false, $aiDefaultValue = 0){
 | |
| 		if($name == '*' || $this->tableAlreadyExists($name))
 | |
| 			return false;
 | |
| 		else{
 | |
| 			if($autoincrement)
 | |
| 				return $this->_insert(array('name'=>$this->_tableName, 'attributes'=>array('name'=>$name, 'autoincrement'=>'true', 'aivalue'=>$aiDefaultValue)));
 | |
| 			else
 | |
| 				return $this->_insert(array('name'=>$this->_tableName, 'attributes'=>array('name'=>$name)));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function dropTable($table){
 | |
| 		return $this->_delete($table);
 | |
| 	}
 | |
| 
 | |
| 	private function updateTableAIValue($table){
 | |
| 		if($this->tableAlreadyExists($table)){
 | |
| 			$table = $this->selectTable($table);
 | |
| 			$newValue = $table->item(0)->getAttribute('aivalue')+1;
 | |
| 			$table->item(0)->setAttribute('aivalue', $newValue);
 | |
| 			return $newValue;
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
|     private function _getNewIncrement($table){
 | |
| 		return $this->updateTableAIValue($table);
 | |
| 	}
 | |
| 
 | |
| 	public function pkAlreadyExists($pk, $table = '*'){
 | |
| 		if($this->selectFromPK($table, $pk , 'count') > 0){
 | |
| 			return true;
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 	private function getResult($request, $format){
 | |
| 		switch($format){
 | |
| 			case "node":
 | |
| 				return $request;
 | |
| 				break;
 | |
| 			case "count":
 | |
| 				return $request->length;
 | |
| 				break;
 | |
| 			case "array":
 | |
| 			default:
 | |
| 				return $this->requestToArray($request);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function select(array $what = array('*')){
 | |
| 		$this->current_request = self::SELECT;
 | |
| 		$this->operation = $what;
 | |
| 	}
 | |
| 
 | |
|     public function insert(array $what = null){
 | |
| 		$this->current_request = self::INSERT;
 | |
| 		if($what != null)
 | |
| 			$this->operation = $what;
 | |
| 		else
 | |
| 			throw new Exception('You must indicate something to insert');
 | |
| 	}
 | |
| 
 | |
|     public function delete(){
 | |
| 		$this->current_request = self::DELETE;
 | |
| 	}
 | |
| 
 | |
|     // TODO 
 | |
|     public function update(string $from){
 | |
| 		$this->current_request = self::UPDATE;
 | |
|         $this->from = $from;
 | |
| 	}
 | |
| 
 | |
| 	public function from(string $from = '*'){
 | |
| 		if($this->tableAlreadyExists($from))
 | |
| 			$this->from = $from;
 | |
| 		else
 | |
| 			$this->from = '*';
 | |
| 	}
 | |
| 
 | |
|     public function set(array $setID = null, array $setChild = null){
 | |
|         $this->setID    = $setID;
 | |
|         $this->setChild = $setChild;
 | |
|     }
 | |
|     
 | |
| 	public function where(string $whereID = null, array $whereChildren = null){
 | |
| 		$this->whereID 			= $whereID;
 | |
| 		$this->whereChildren 	= $whereChildren;
 | |
| 	}
 | |
| 
 | |
|     public function toPosition(int $to){
 | |
|         $this->position = $to;
 | |
|     }
 | |
| 
 | |
| 	public function query(){
 | |
| 		return $this->_prepareStmt();
 | |
| 	}
 | |
| 
 | |
| 	private function _prepareStmt(){
 | |
| 		switch($this->current_request()){
 | |
| 			case self::SELECT:
 | |
| 				return $this->_select($this->what, $this->from, $this->whereID, $this->whereChildren);
 | |
| 				break;
 | |
| 			case self::INSERT:
 | |
|                 return $this->_insert($this->operation, $this->from, $this->position);
 | |
| 				break;
 | |
| 			case self::DELETE:
 | |
|                 return $this->_delete($this->from, $this->whereID);
 | |
| 				break;
 | |
| 			case self::UPDATE:
 | |
|                 return $this->_update($this->from, $this->setID, $this->setChild, $this->whereID, $this->whereChildren);
 | |
| 				break;
 | |
| 			default:
 | |
|                 throw new Exception('no request detected.');
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private function _getAttribute($attribute, $node){
 | |
| 		if($node->length == 1){
 | |
| 			return $node->item(0)->getAttribute($attribute);
 | |
| 		}else{
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private function _getChildValue($child, $node){
 | |
|         $nodeArray = array();
 | |
| 		if($node->length == 1){
 | |
| 			$nodeArray = $this->_requestToArray($node);
 | |
| 			if(isset($nodeArray[0]['childs'][$child]))
 | |
| 				return $nodeArray[0]['childs'][$child];
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	private function _requestToArray($request){
 | |
| 		$return = array();
 | |
| 		$number = 0;
 | |
| 
 | |
| 		foreach($request as $element){
 | |
| 			/*if($childName != null && $childValue != null)
 | |
| 			$element = $element->parentNode;*/
 | |
| 			$elementValue = $element->attributes->item(0)->value;
 | |
| 			$return[$number]['name'] = $this->_itemName;
 | |
| 			$return[$number]['attributes'] = array($this->_primaryKey => $elementValue);
 | |
| 			$return[$number]['childs'] = array();
 | |
| 
 | |
| 			//Retrieving Attributes
 | |
| 			$attributes = $element->attributes;
 | |
| 			$length = $attributes->length;
 | |
| 			for ($i = 0; $i <= $length; $i++) {
 | |
| 				if($attributes->item($i)->name != '')
 | |
| 				$return[$number]['attributes'][$attributes->item($i)->name] = $attributes->item($i)->value;
 | |
| 			}
 | |
| 
 | |
| 			// Retrivieving childs
 | |
| 			$nodes = $element->childNodes;
 | |
| 			$length = $nodes->length;
 | |
| 			for ($i = 0; $i <= $length; $i++) {
 | |
| 				if($nodes->item($i)->nodeName != '')
 | |
| 				$return[$number]['childs'][$nodes->item($i)->nodeName] = $nodes->item($i)->nodeValue;
 | |
| 			}
 | |
| 			$number++;
 | |
| 		}
 | |
| 		return $return;
 | |
| 	}
 | |
| 
 | |
|     private function _update($from, $setID = null, $setChild = null, $whereID = null, $whereChildren = null){
 | |
|         $node = $this->_select(array('*'), $from, $whereID, $whereChildren);
 | |
|         if($node != null){
 | |
|             $this->updateChildValue($from, $node, $setChild, $forceInsert);
 | |
|             $this->updateItemAttribute($from, $node, $newAttribute, $forceInsert);
 | |
|         }else{
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
|     
 | |
| 	private function _select(array $what, string $from, string $id = null, $childs = null, $item = ''){
 | |
|         $attribute  = '';
 | |
|         $child      = '';
 | |
| 		if($id != null && !is_array($id)){
 | |
| 			$attribute = '[@' . $this->_primaryKey . ' = "' . $id . '"]';
 | |
| 		}
 | |
| 		if($childs != null && is_array($childs)){
 | |
| 			foreach($childs as $childName=>$childValue)
 | |
| 				$child .= '[' . $childName . '="' . $childValue . '"]';
 | |
| 		}
 | |
| 		if($from == '*')
 | |
| 			$request = $this->_xpath->query('//item'.$attribute.$child);
 | |
| 		else
 | |
| 			$request = $this->_xpath->query('//' .  $this->_tableName . '[@name = "'.$from.'"]'.$item.$attribute.$child);
 | |
| 		if($what == '*')
 | |
| 			return $request;
 | |
| 		else{
 | |
| 			return $this->_getChildValue($what, $request);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private function _arrayToNode($node){
 | |
| 		if(!is_array($node) || !in_array($node['name'], array($this->_tableName, $this->_itemName)))
 | |
| 			return;
 | |
| 		$element = $this->_doc->createElement($node['name']);
 | |
| 		if(isset($node['attributes'])){
 | |
| 			foreach($node['attributes'] as $attributeName=>$attributeValue){
 | |
| 				if($attributeName != '')
 | |
| 				$element->setAttribute($attributeName, $attributeValue);
 | |
| 			}
 | |
| 		}
 | |
| 		if(isset($node['childs'])){
 | |
| 			foreach($node['childs'] as $childName=>$childValue){
 | |
| 				if($childName != ''){
 | |
| 					$newElement = $this->_doc->createElement($childName, $childValue);
 | |
| 					$element->appendChild($newElement);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		return $element;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	/**
 | |
| 	 * Allows you to insert a node into your DB thanks to an array
 | |
| 	 * @param $node array with 'name' 'attributes' and 'childs'
 | |
| 	 * @param $table string in which node you want to put it. By default, the root of the xml file
 | |
| 	 * @param $position string 'before' or 'after'
 | |
| 	 * @return bool
 | |
| 	 */
 | |
| 	public function insertItem($id = null, $attributes = null, $childs = null, $table){
 | |
| 		if($id == null && $this->isTableAI($table)){
 | |
| 			$id = $this->_getNewIncrement($table);
 | |
| 		}
 | |
| 		else if(($id == null && !$this->isTableAI($table)) || ($id != null && $this->isTableAI($table)))
 | |
| 			return false;
 | |
| 
 | |
| 		if($attributes == null)
 | |
| 			$attributes = array($this->_primaryKey=>$id);
 | |
| 		else
 | |
| 			$attributes += array($this->_primaryKey=>$id);
 | |
| 		if($this->tableAlreadyExists($table) && !$this->pkAlreadyExists($id, $table))
 | |
| 			return $this->_insert(array('name'=>$this->_itemName, 'attributes'=>$attributes, 'childs'=>$childs), $table);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// TODO $position
 | |
| 	private function _insert(array $node, string $table = null, int $position = null){
 | |
| 		if(isset($node[0]))
 | |
| 			$node = $node[0];
 | |
| 		if(!is_array($node) || !isset($node['name']) || !isset($node['attributes'])){
 | |
| 			throw new Exception('The node is not well formated.');
 | |
| 		}
 | |
| 		// Creating the node from an array
 | |
| 		$element = $this->_arrayToNode($node);
 | |
| 
 | |
| 		// Inserting the node into the DB
 | |
| 		// case : creation of a new table
 | |
| 		if($table == null &&  !$this->tableAlreadyExists($node['name'])){
 | |
| 			$this->_doc->firstChild->appendChild($element);
 | |
| 		}else if($table != null){
 | |
| 		// case : insertion into the end of table
 | |
| 			if(!$this->tableAlreadyExists($table) || $this->pkAlreadyExists($node['attributes'][$this->_primaryKey], $table)){
 | |
| 				return false;
 | |
| 			}
 | |
| 			$totalItemInTable = $this->selectAllFromTable($table, 'count');
 | |
| 			if($position == null || $position < $totalItemInTable){
 | |
| 				$request = $this->_xpath->query('//' .  $this->_tableName . '[@name = "'.$table.'"]');
 | |
| 				$request->item(0)->appendChild($element);
 | |
| 			}else{
 | |
| 				$itemsAfter = $this->selectAllFromTable($table, 'node');
 | |
| 				$itemAfter = $itemsAfter->item($position-1);
 | |
| 				$itemAfter->parentNode->insertBefore($element, $itemAfter);
 | |
| 			}
 | |
| 		}else{
 | |
| 			return false;
 | |
| 		}
 | |
| 		return $this->commit();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 *
 | |
| 	 * @param $table string
 | |
| 	 * @param $oldAttribute string name of the attribute you want to change
 | |
| 	 * @param $newAttribute array name/value of the attribute you want to add
 | |
| 	 * @param $forceInsert bool
 | |
| 	 * @return bool
 | |
| 	 */
 | |
| 	public function updateItemAttribute($table, $oldAttribute, $newAttribute, $forceInsert = false){
 | |
| 		$request = $this->select($table, null, array($oldAttribute[0]=>$oldAttribute[1]), null, 'node', '/'.$this->_itemName);
 | |
| 		if($request->length == 1){
 | |
| 			if(!$forceInsert){
 | |
| 				$request->item(0)->setAttribute($oldAttribute[0],$newAttribute[1]);
 | |
| 			}else{
 | |
| 				$request->item(0)->setAttribute($newAttribute[0],$newAttribute[1]);
 | |
| 			}
 | |
| 			return $this->commit();
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 *
 | |
| 	 * @param $table string
 | |
| 	 * @param $value string new value of the node
 | |
| 	 * @return bool
 | |
| 	 */
 | |
| 	public function updateItemValue($table, $attribute = null, $child = null, $value){
 | |
| 		$request = $this->select($table, null, array($attribute[0]=>$attribute[1]), $child, 'node', '/'.$this->_itemName);
 | |
| 		//$request = $this->_xpath->query('//'.$node.'[@' . $attribute[0] . ' = "' . $attribute[1] . '"]');
 | |
| 		if($request->length == 1){
 | |
| 			$request = $request->item(0);
 | |
| 			$newText = new DOMText($value);
 | |
| 			$request->removeChild($request->firstChild);
 | |
| 			$request->appendChild($newText);
 | |
| 			return $this->commit();
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 
 | |
| 	public function updateChildValue($table, $node, $child, $value){
 | |
| 		if($node->length == 1){
 | |
| 			$node = $node->item(0);
 | |
| 			$newChild = $this->_doc->createElement($child, $value);
 | |
| 			$old_element_childNodes = $node->childNodes;
 | |
| 			$length = $old_element_childNodes->length;
 | |
| 			$index = 0;
 | |
| 			for($i = 0; $i < $length; $i++)
 | |
| 			{
 | |
| 				if($old_element_childNodes->item($i)->nodeName == $child){
 | |
| 					$index = $i;
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 			//$request = $node->getElementsByTagName($child)->item(0);
 | |
| 			if($node->replaceChild($newChild, $old_element_childNodes->item($index)))
 | |
| 			return $this->commit();
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
|     
 | |
| 	/**
 | |
| 	 * Delete an entry
 | |
| 	 * @param $table name of the table in which the entry is
 | |
| 	 * @param $id $attributes array where condition(s)
 | |
| 	 * @return bool
 | |
| 	 */
 | |
| 	private function _delete($table, $id = null){
 | |
| 		if($id != null)
 | |
|             $request = $this->_select (array('*'), $table, $id, null);
 | |
| 			//$request = $this->selectFromPK($table, $id, 'node')->item(0);
 | |
| 		else
 | |
| 			$request = $this->_select (array('*'), $table);
 | |
| 		if($request == null)
 | |
| 			return false;
 | |
| 		try{
 | |
| 			$request->parentNode->removeChild($request);
 | |
| 		}catch(Exception $e){
 | |
| 			echo $e->getMessage();
 | |
| 			return false;
 | |
| 		}
 | |
| 		return $this->commit();
 | |
| 	}
 | |
| 
 | |
| 	public function move($node, $to, $position = null){
 | |
| 		$this->_buffer = $node;
 | |
| 		if($this->deleteNode($node)){
 | |
| 			$nodeArray = $this->requestToArray($this->_buffer);
 | |
| 			return $this->_insert($nodeArray, $to, $position);
 | |
| 		}else
 | |
| 			return false;
 | |
| 	}
 | |
| } | 
