Source for file jDaoParser.class.php

Documentation is available at jDaoParser.class.php

  1. <?php
  2. /**
  3. * @package     jelix
  4. * @subpackage  dao
  5. * @author      GĂ©rald Croes, Laurent Jouanneau
  6. * @contributor Laurent Jouanneau
  7. * @copyright   2001-2005 CopixTeam, 2005-2012 Laurent Jouanneau
  8. *  This class was get originally from the Copix project (CopixDAODefinitionV1, Copix 2.3dev20050901, http://www.copix.org)
  9. *  Few lines of code are still copyrighted 2001-2005 CopixTeam (LGPL licence).
  10. *  Initial authors of this Copix class are Gerald Croes and Laurent Jouanneau,
  11. *
  12. * @link        http://www.jelix.org
  13. * @licence  http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public Licence, see LICENCE file
  14. */
  15.  
  16. require(JELIX_LIB_PATH.'dao/jDaoXmlException.class.php');
  17. require(JELIX_LIB_PATH.'dao/jDaoProperty.class.php');
  18. require(JELIX_LIB_PATH.'dao/jDaoMethod.class.php');
  19. require(JELIX_LIB_PATH.'dao/jDaoGenerator.class.php');
  20.  
  21. /**
  22.  * extract data from a dao xml content
  23.  * @package  jelix
  24.  * @subpackage dao
  25.  * @see jDaoCompiler
  26.  */
  27. class jDaoParser {
  28.     /**
  29.     * the properties list.
  30.     * keys = field code name
  31.     * values = jDaoProperty
  32.     */
  33.     private $_properties = array ();
  34.  
  35.     /**
  36.     * all tables with their properties, and their own fields
  37.     * keys = table code name
  38.     * values = array()
  39.     *          'name'=> table code name, 'realname'=>'real table name',
  40.     *           'pk'=> primary keys list
  41.     *          'fk'=> foreign keys list
  42.     *          'fields'=>array(list of field code name)
  43.     */
  44.     private $_tables = array();
  45.  
  46.     /**
  47.     * primary table code name
  48.     */
  49.     private $_primaryTable = '';
  50.  
  51.     /**
  52.     * code name of foreign table with a outer join
  53.     * @var array  list of array(table code name, 0)
  54.     */
  55.     private $_ojoins = array ();
  56.  
  57.     /**
  58.     * code name of foreign table with a inner join
  59.     * @var array  list of table code name
  60.     */
  61.     private $_ijoins = array ();
  62.  
  63.     /**
  64.      * @var array list of jDaoMethod objects
  65.      */
  66.     private $_methods = array();
  67.  
  68.     /**
  69.      * list of main events to sent
  70.      */
  71.     private $_eventList = array();
  72.  
  73.     public $hasOnlyPrimaryKeys = false;
  74.  
  75.     /**
  76.      * selector of the user record class
  77.      * @var jSelectorDaoRecord 
  78.      */
  79.     private $_userRecord = null;
  80.     
  81.     /**
  82.      * selector of the imported dao
  83.      * @var jSelectorDao[] 
  84.      */
  85.     private $_importedDao = null;
  86.     
  87.     public $selector;
  88.     /**
  89.     * Constructor
  90.     */
  91.     function __construct($selector) {
  92.         $this->selector = $selector;
  93.     }
  94.  
  95.     /**
  96.     * parse a dao xml content
  97.     * @param SimpleXmlElement $xml 
  98.     * @param jDbTools $tools 
  99.     * @param int $debug  for debug only 0:parse all, 1:parse only datasource+record, 2;parse only datasource
  100.     */
  101.     public function parse ($xml, $tools) {
  102.         $this->import($xml, $tools);
  103.         $this->parseDatasource($xml);
  104.         $this->parseRecord($xml, $tools);
  105.         $this->parseFactory($xml);
  106.     }
  107.     
  108.     protected function import ($xml, $tools) {
  109.         if (isset($xml['import'])) {
  110.             $import = (string)$xml['import'];
  111.  
  112.             jApp::pushCurrentModule($this->selector->module);
  113.             // Keep the same driver as current used
  114.             $importSel = new jSelectorDao($import, $this->selector->driver);
  115.             jApp::popCurrentModule();
  116.  
  117.             $doc = new DOMDocument();
  118.             if (!$doc->load($importSel->getPath())) {
  119.                 throw new jException('jelix~daoxml.file.unknown', $importSel->getPath());
  120.             }
  121.             $parser = new jDaoParser ($importSel);
  122.             $parser->parse(simplexml_import_dom($doc), $tools);
  123.  
  124.             $this->_properties = $parser->getProperties();
  125.             $this->_tables = $parser->getTables();
  126.             $this->_primaryTable = $parser->getPrimaryTable();
  127.             $this->_methods = $parser->getMethods();
  128.             $this->_ojoins = $parser->getOuterJoins();
  129.             $this->_ijoins = $parser->getInnerJoins();
  130.             $this->_eventList = $parser->getEvents();
  131.             $this->_userRecord = $parser->getUserRecord();
  132.             $this->_importedDao = $parser->getImportedDao();
  133.             $this->hasOnlyPrimaryKeys = $parser->hasOnlyPrimaryKeys;
  134.  
  135.             if ($this->_importedDao)
  136.                 $this->_importedDao[] = $importSel;
  137.             else
  138.                 $this->_importedDao = array($importSel);
  139.         }
  140.     }
  141.     
  142.     protected function parseDatasource($xml) {
  143.         // -- tables
  144.         if(isset ($xml->datasources) && isset ($xml->datasources[0]->primarytable)) {
  145.             $previousTables = $this->_tables;
  146.             // erase table definitions (in the case where the dao imports an other one)
  147.             $this->_tables = array();
  148.             $this->_ijoins = array();
  149.             $this->_ojoins = array();
  150.  
  151.             $t = $this->_parseTable (0, $xml->datasources[0]->primarytable[0]);
  152.             $this->_primaryTable = $t['name'];
  153.             if (isset($previousTables[$t['name']])) {
  154.                 $this->_tables[$t['name']]['fields'] = $previousTables[$t['name']]['fields'];
  155.             }
  156.             if(isset($xml->datasources[0]->primarytable[1])){
  157.                 throw new jDaoXmlException ($this->selector, 'table.two.many');
  158.             }
  159.             foreach($xml->datasources[0]->foreigntable as $table){
  160.                 $t = $this->_parseTable (1, $table);
  161.                 if (isset($previousTables[$t['name']])) {
  162.                     $this->_tables[$t['name']]['fields'] = $previousTables[$t['name']]['fields'];
  163.                 }
  164.             }
  165.             foreach($xml->datasources[0]->optionalforeigntable as $table){
  166.                 $t = $this->_parseTable (2, $table);
  167.                 if (isset($previousTables[$t['name']])) {
  168.                     $this->_tables[$t['name']]['fields'] = $previousTables[$t['name']]['fields'];
  169.                 }
  170.             }
  171.         }else if ($this->_primaryTable === '') { // no imported dao
  172.             throw new jDaoXmlException ($this->selector, 'datasource.missing');
  173.         }
  174.     }
  175.     
  176.     protected function parseRecord($xml, $tools) {
  177.  
  178.         //add the record properties
  179.         if(isset($xml->record)){
  180.             if (isset($xml->record[0]['extends'])) {
  181.                 jApp::pushCurrentModule($this->selector->module);
  182.                 $this->_userRecord = new jSelectorDaoRecord((string)$xml->record[0]['extends']);
  183.                 jApp::popCurrentModule();
  184.             }
  185.             if (isset($xml->record[0]->property)) {
  186.                 // don't append directly new properties into _properties,
  187.                 // so we can see the differences between imported properties
  188.                 // and readed properties
  189.                 $properties = array();
  190.                 foreach ($xml->record[0]->property as $prop){
  191.                     $p = new jDaoProperty ($prop->attributes(), $this, $tools);
  192.                     if (isset($properties[$p->name])) {
  193.                         throw new jDaoXmlException ($this->selector, 'property.already.defined', $p->name);
  194.                     }
  195.                     if (!in_array($p->name, $this->_tables[$p->table]['fields'])) { // if this property does not redefined an imported property
  196.                         $this->_tables[$p->table]['fields'][] = $p->name;
  197.                     }
  198.                     $properties[$p->name] = $p;
  199.                 }
  200.                 $this->_properties = array_merge($this->_properties, $properties);
  201.             }
  202.         }
  203.         // in the case when there is no defined property and no imported dao
  204.         if (count($this->_properties) == 0)
  205.             throw new jDaoXmlException ($this->selector, 'properties.missing');
  206.  
  207.         // check that properties are attached to a known table. It can be
  208.         // wrong if the datasource has been redefined with other table names
  209.         $countprop = 0;
  210.         foreach ($this->_properties as $p) {
  211.             if (!isset($this->_tables[$p->table]))
  212.                 throw new jDaoXmlException ($this->selector, 'property.imported.unknown.table', $p->name);
  213.             if($p->ofPrimaryTable && !$p->isPK)
  214.                 $countprop ++;
  215.         }
  216.         $this->hasOnlyPrimaryKeys = ($countprop == 0);
  217.     }
  218.  
  219.     protected function parseFactory($xml) {
  220.         // get additionnal methods definition
  221.         if (isset ($xml->factory)) {
  222.             if (isset($xml->factory[0]['events'])) {
  223.                 $events = (string)$xml->factory[0]['events'];
  224.                 $this->_eventList = preg_split("/[\s,]+/", $events);
  225.             }
  226.  
  227.             if (isset($xml->factory[0]->method)){
  228.                 $methods = array();
  229.                 foreach($xml->factory[0]->method as $method){
  230.                     $m = new jDaoMethod ($method, $this);
  231.                     if (isset ($methods[$m->name])){
  232.                         throw new jDaoXmlException ($this->selector, 'method.duplicate',$m->name);
  233.                     }
  234.                     $methods[$m->name] = $m;
  235.                 }
  236.                 $this->_methods = array_merge($this->_methods, $methods);
  237.             }
  238.         }
  239.     }
  240.  
  241.     /**
  242.     * parse a join definition
  243.     */
  244.     private function _parseTable ($typetable, $tabletag){
  245.         $infos = $this->getAttr($tabletag, array('name','realname','primarykey','onforeignkey'));
  246.  
  247.         if ($infos['name'] === null )
  248.             throw new jDaoXmlException ($this->selector, 'table.name');
  249.  
  250.         if($infos['realname'] === null)
  251.             $infos['realname'] = $infos['name'];
  252.  
  253.         if($infos['primarykey'] === null)
  254.             throw new jDaoXmlException ($this->selector, 'primarykey.missing');
  255.  
  256.         $infos['pk']= preg_split("/[\s,]+/", $infos['primarykey']);
  257.         unset($infos['primarykey']);
  258.  
  259.         if(count($infos['pk']) == 0 || $infos['pk'][0] == '')
  260.             throw new jDaoXmlException ($this->selector, 'primarykey.missing');
  261.  
  262.         if($typetable){ // for the foreigntable and optionalforeigntable
  263.             if($infos['onforeignkey'] === null)
  264.                 throw new jDaoXmlException ($this->selector, 'foreignkey.missing');
  265.             $infos['fk']=preg_split("/[\s,]+/",$infos['onforeignkey']);
  266.             unset($infos['onforeignkey']);
  267.             if(count($infos['fk']) == 0 || $infos['fk'][0] == '')
  268.                 throw new jDaoXmlException ($this->selector, 'foreignkey.missing');
  269.             if(count($infos['fk']) != count($infos['pk']))
  270.                 throw new jDaoXmlException ($this->selector, 'foreignkey.missing');
  271.             if($typetable == 1){
  272.                 $this->_ijoins[]=$infos['name'];
  273.             }else{
  274.                 $this->_ojoins[]=array($infos['name'],0);
  275.             }
  276.         }else{
  277.             unset($infos['onforeignkey']);
  278.         }
  279.  
  280.         $infos['fields'] = array ();
  281.         $this->_tables[$infos['name']] = $infos;
  282.  
  283.         return $infos;
  284.     }
  285.  
  286.     /**
  287.     * Try to read all given attributes
  288.     * @param SimpleXmlElement $tag 
  289.     * @param array $requiredattr attributes list
  290.     * @return array attributes and their values
  291.     */
  292.     public function getAttr($tag, $requiredattr){
  293.         $res=array();
  294.         foreach($requiredattr as $attr){
  295.             if(isset($tag[$attr]) && trim((string)$tag[$attr]) != '')
  296.                 $res[$attr]=(string)$tag[$attr];
  297.             else
  298.                 $res[$attr]=null;
  299.         }
  300.         return $res;
  301.     }
  302.  
  303.     /**
  304.     * just a quick way to retrieve boolean values from a string.
  305.     *  will accept yes, true, 1 as "true" values
  306.     *  all other values will be considered as false.
  307.     * @return boolean true / false
  308.     */
  309.     public function getBool ($value) {
  310.         return in_array (trim ($value), array ('true', '1', 'yes'));
  311.     }
  312.  
  313.     /**
  314.     * the properties list.
  315.     * keys = field code name
  316.     * values = jDaoProperty
  317.     * @return array 
  318.     */
  319.     public function getProperties () { return $this->_properties; }
  320.  
  321.     /**
  322.     * all tables with their properties, and their own fields
  323.     * keys = table code name
  324.     * values = array()
  325.     *          'name'=> table code name, 'realname'=>'real table name',
  326.     *           'pk'=> primary keys list
  327.     *          'fk'=> foreign keys list
  328.     *          'fields'=>array(list of field code name)
  329.     * @return array 
  330.     */
  331.     public function getTables(){  return $this->_tables;}
  332.  
  333.     /**
  334.     * @return string the primary table code name
  335.     */
  336.     public function getPrimaryTable(){  return $this->_primaryTable;}
  337.  
  338.     /**
  339.      * @return jDaoMethod[] list of jDaoMethod objects
  340.      */
  341.     public function getMethods(){  return $this->_methods;}
  342.  
  343.     /**
  344.     * list of code name of foreign table with a outer join
  345.     * @var array  list of array(table code name, 0)
  346.     */
  347.     public function getOuterJoins(){  return $this->_ojoins;}
  348.  
  349.     /**
  350.     * list of code name of foreign tables with a inner join
  351.     * @return array  the list
  352.     */
  353.     public function getInnerJoins(){  return $this->_ijoins;}
  354.  
  355.     public function getEvents(){ return $this->_eventList;}
  356.     public function hasEvent($event){ return in_array($event,$this->_eventList);}
  357.  
  358.     /**
  359.      * selector of the user record class
  360.      * @return jSelectorDaoRecord 
  361.      */
  362.     public function getUserRecord() { return $this->_userRecord;}
  363.  
  364.     /**
  365.      * selector of the imported dao. If can return several selector, if
  366.      * an imported dao import itself an other dao etc.
  367.      * @return jSelectorDao[] 
  368.      */
  369.     public function getImportedDao(){ return $this->_importedDao;}
  370. }

Documentation generated on Wed, 04 Jan 2017 22:53:23 +0100 by phpDocumentor 1.4.3