MDB2_Schema
[ class tree: MDB2_Schema ] [ index: MDB2_Schema ] [ all elements ]

Source for file Parser2.php

Documentation is available at Parser2.php

  1. <?php
  2. /**
  3.  * PHP versions 4 and 5
  4.  *
  5.  * Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,
  6.  * Stig. S. Bakken, Lukas Smith, Igor Feghali
  7.  * All rights reserved.
  8.  *
  9.  * MDB2_Schema enables users to maintain RDBMS independant schema files
  10.  * in XML that can be used to manipulate both data and database schemas
  11.  * This LICENSE is in the BSD license style.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  *
  17.  * Redistributions of source code must retain the above copyright
  18.  * notice, this list of conditions and the following disclaimer.
  19.  *
  20.  * Redistributions in binary form must reproduce the above copyright
  21.  * notice, this list of conditions and the following disclaimer in the
  22.  * documentation and/or other materials provided with the distribution.
  23.  *
  24.  * Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,
  25.  * Lukas Smith, Igor Feghali nor the names of his contributors may be
  26.  * used to endorse or promote products derived from this software
  27.  * without specific prior written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  30.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  31.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  32.  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
  33.  * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  34.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  35.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  36.  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  37.  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  39.  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  40.  * POSSIBILITY OF SUCH DAMAGE.
  41.  *
  42.  * Author: Igor Feghali <ifeghali@php.net>
  43.  *
  44.  * @category Database
  45.  * @package  MDB2_Schema
  46.  * @author   Igor Feghali <ifeghali@php.net>
  47.  * @license  BSD http://www.opensource.org/licenses/bsd-license.php
  48.  * @version  CVS: $Id: Parser2.php,v 1.12 2008/11/30 03:34:00 clockwerx Exp $
  49.  * @link     http://pear.php.net/packages/MDB2_Schema
  50.  */
  51.  
  52. require_once 'XML/Unserializer.php';
  53. require_once 'MDB2/Schema/Validate.php';
  54.  
  55. /**
  56.  * Parses an XML schema file
  57.  *
  58.  * @category Database
  59.  * @package  MDB2_Schema
  60.  * @author   Lukas Smith <smith@pooteeweet.org>
  61.  * @author   Igor Feghali <ifeghali@php.net>
  62.  * @license  BSD http://www.opensource.org/licenses/bsd-license.php
  63.  * @link     http://pear.php.net/packages/MDB2_Schema
  64.  */
  65. class MDB2_Schema_Parser2 extends XML_Unserializer
  66. {
  67.     var $database_definition = array();
  68.  
  69.     var $database_loaded = array();
  70.  
  71.     var $variables = array();
  72.  
  73.     var $error;
  74.  
  75.     var $structure = false;
  76.  
  77.     var $val;
  78.  
  79.     var $options = array();
  80.  
  81.     var $table = array();
  82.  
  83.     var $table_name = '';
  84.  
  85.     var $field = array();
  86.  
  87.     var $field_name = '';
  88.  
  89.     var $index = array();
  90.  
  91.     var $index_name = '';
  92.  
  93.     var $constraint = array();
  94.  
  95.     var $constraint_name = '';
  96.  
  97.     var $sequence = array();
  98.  
  99.     var $sequence_name = '';
  100.  
  101.     var $init = array();
  102.  
  103.     function __construct($variables$fail_on_invalid_names = true$structure = false$valid_types = array()$force_defaults = true)
  104.     {
  105.         // force ISO-8859-1 due to different defaults for PHP4 and PHP5
  106.         // todo: this probably needs to be investigated some more and cleaned up
  107.         $this->options['encoding''ISO-8859-1';
  108.  
  109.         $this->options['XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE']    = true;
  110.         $this->options['XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY'= false;
  111.  
  112.         $this->options['forceEnum'= array('table''field''index''foreign''insert''update''delete''sequence');
  113.  
  114.         /*
  115.          * todo: find a way to force the following items not to be parsed as arrays
  116.          * as it cause problems in functions with multiple arguments
  117.          */
  118.         //$this->options['forceNEnum'] = array('value', 'column');
  119.         $this->variables = $variables;
  120.         $this->structure = $structure;
  121.  
  122.         $this->val =new MDB2_Schema_Validate($fail_on_invalid_names$valid_types$force_defaults);
  123.         parent::XML_Unserializer($this->options);
  124.     }
  125.  
  126.     function MDB2_Schema_Parser2($variables$fail_on_invalid_names = true$structure = false$valid_types = array()$force_defaults = true)
  127.     {
  128.         $this->__construct($variables$fail_on_invalid_names$structure$valid_types$force_defaults);
  129.     }
  130.  
  131.     function parse()
  132.     {
  133.         $result $this->unserialize($this->filenametrue);
  134.  
  135.         if (PEAR::isError($result)) {
  136.             return $result;
  137.         else {
  138.             $this->database_loaded = $this->getUnserializedData();
  139.             return $this->fixDatabaseKeys($this->database_loaded);
  140.         }
  141.     }
  142.  
  143.     function setInputFile($filename)
  144.     {
  145.         $this->filename $filename;
  146.         return MDB2_OK;
  147.     }
  148.  
  149.     function renameKey(&$arr$oKey$nKey)
  150.     {
  151.         $arr[$nKey&$arr[$oKey];
  152.         unset($arr[$oKey]);
  153.     }
  154.  
  155.     function fixDatabaseKeys($database)
  156.     {
  157.         $this->database_definition = array(
  158.             'name' => '',
  159.             'create' => '',
  160.             'overwrite' => '',
  161.             'charset' => '',
  162.             'description' => '',
  163.             'comments' => '',
  164.             'tables' => array(),
  165.             'sequences' => array()
  166.         );
  167.  
  168.         if (!empty($database['name'])) {
  169.             $this->database_definition['name'$database['name'];
  170.         }
  171.         if (!empty($database['create'])) {
  172.             $this->database_definition['create'$database['create'];
  173.         }
  174.         if (!empty($database['overwrite'])) {
  175.             $this->database_definition['overwrite'$database['overwrite'];
  176.         }
  177.         if (!empty($database['charset'])) {
  178.             $this->database_definition['charset'$database['charset'];
  179.         }
  180.         if (!empty($database['description'])) {
  181.             $this->database_definition['description'$database['description'];
  182.         }
  183.         if (!empty($database['comments'])) {
  184.             $this->database_definition['comments'$database['comments'];
  185.         }
  186.  
  187.         if (!empty($database['table']&& is_array($database['table'])) {
  188.             foreach ($database['table'as $table{
  189.                 $this->fixTableKeys($table);
  190.             }
  191.         }
  192.  
  193.         if (!empty($database['sequence']&& is_array($database['sequence'])) {
  194.             foreach ($database['sequence'as $sequence{
  195.                 $this->fixSequenceKeys($sequence);
  196.             }
  197.         }
  198.  
  199.         $result $this->val->validateDatabase($this->database_definition);
  200.         if (PEAR::isError($result)) {
  201.             return $this->raiseError($result->getUserinfo());
  202.         }
  203.  
  204.         return MDB2_OK;
  205.     }
  206.  
  207.     function fixTableKeys($table)
  208.     {
  209.         $this->table = array(
  210.             'was' => '',
  211.             'description' => '',
  212.             'comments' => '',
  213.             'fields' => array(),
  214.             'indexes' => array(),
  215.             'constraints' => array(),
  216.             'initialization' => array()
  217.         );
  218.  
  219.         if (!empty($table['name'])) {
  220.             $this->table_name = $table['name'];
  221.         else {
  222.             $this->table_name = '';
  223.         }
  224.         if (!empty($table['was'])) {
  225.             $this->table['was'$table['was'];
  226.         }
  227.         if (!empty($table['description'])) {
  228.             $this->table['description'$table['description'];
  229.         }
  230.         if (!empty($table['comments'])) {
  231.             $this->table['comments'$table['comments'];
  232.         }
  233.  
  234.         if (!empty($table['declaration']&& is_array($table['declaration'])) {
  235.             if (!empty($table['declaration']['field']&& is_array($table['declaration']['field'])) {
  236.                 foreach ($table['declaration']['field'as $field{
  237.                     $this->fixTableFieldKeys($field);
  238.                 }
  239.             }
  240.  
  241.             if (!empty($table['declaration']['index']&& is_array($table['declaration']['index'])) {
  242.                 foreach ($table['declaration']['index'as $index{
  243.                     $this->fixTableIndexKeys($index);
  244.                 }
  245.             }
  246.  
  247.             if (!empty($table['declaration']['foreign']&& is_array($table['declaration']['foreign'])) {
  248.                 foreach ($table['declaration']['foreign'as $constraint{
  249.                     $this->fixTableConstraintKeys($constraint);
  250.                 }
  251.             }
  252.         }
  253.  
  254.         if (!empty($table['initialization']&& is_array($table['initialization'])) {
  255.             if (!empty($table['initialization']['insert']&& is_array($table['initialization']['insert'])) {
  256.                 foreach ($table['initialization']['insert'as $init{
  257.                     $this->fixTableInitializationKeys($init'insert');
  258.                 }
  259.             }
  260.             if (!empty($table['initialization']['update']&& is_array($table['initialization']['update'])) {
  261.                 foreach ($table['initialization']['update'as $init{
  262.                     $this->fixTableInitializationKeys($init'update');
  263.                 }
  264.             }
  265.             if (!empty($table['initialization']['delete']&& is_array($table['initialization']['delete'])) {
  266.                 foreach ($table['initialization']['delete'as $init{
  267.                     $this->fixTableInitializationKeys($init'delete');
  268.                 }
  269.             }
  270.         }
  271.  
  272.         $result $this->val->validateTable($this->database_definition['tables']$this->table$this->table_name);
  273.         if (PEAR::isError($result)) {
  274.             return $this->raiseError($result->getUserinfo());
  275.         else {
  276.             $this->database_definition['tables'][$this->table_name$this->table;
  277.         }
  278.  
  279.         return MDB2_OK;
  280.     }
  281.  
  282.     function fixTableFieldKeys($field)
  283.     {
  284.         $this->field = array();
  285.         if (!empty($field['name'])) {
  286.             $this->field_name = $field['name'];
  287.         else {
  288.             $this->field_name = '';
  289.         }
  290.         if (!empty($field['was'])) {
  291.             $this->field['was'$field['was'];
  292.         }
  293.         if (!empty($field['type'])) {
  294.             $this->field['type'$field['type'];
  295.         }
  296.         if (!empty($field['fixed'])) {
  297.             $this->field['fixed'$field['fixed'];
  298.         }
  299.         if (isset($field['default'])) {
  300.             $this->field['default'$field['default'];
  301.         }
  302.         if (!empty($field['notnull'])) {
  303.             $this->field['notnull'$field['notnull'];
  304.         }
  305.         if (!empty($field['autoincrement'])) {
  306.             $this->field['autoincrement'$field['autoincrement'];
  307.         }
  308.         if (!empty($field['unsigned'])) {
  309.             $this->field['unsigned'$field['unsigned'];
  310.         }
  311.         if (!empty($field['length'])) {
  312.             $this->field['length'$field['length'];
  313.         }
  314.         if (!empty($field['description'])) {
  315.             $this->field['description'$field['description'];
  316.         }
  317.         if (!empty($field['comments'])) {
  318.             $this->field['comments'$field['comments'];
  319.         }
  320.  
  321.         $result $this->val->validateField($this->table['fields']$this->field$this->field_name);
  322.         if (PEAR::isError($result)) {
  323.             return $this->raiseError($result->getUserinfo());
  324.         else {
  325.             $this->table['fields'][$this->field_name$this->field;
  326.         }
  327.  
  328.         return MDB2_OK;
  329.     }
  330.  
  331.     function fixTableIndexKeys($index)
  332.     {
  333.         $this->index = array(
  334.             'was' => '',
  335.             'unique' =>'',
  336.             'primary' => '',
  337.             'fields' => array()
  338.         );
  339.  
  340.         if (!empty($index['name'])) {
  341.             $this->index_name = $index['name'];
  342.         else {
  343.             $this->index_name = '';
  344.         }
  345.         if (!empty($index['was'])) {
  346.             $this->index['was'$index['was'];
  347.         }
  348.         if (!empty($index['unique'])) {
  349.             $this->index['unique'$index['unique'];
  350.         }
  351.         if (!empty($index['primary'])) {
  352.             $this->index['primary'$index['primary'];
  353.         }
  354.         if (!empty($index['field'])) {
  355.             foreach ($index['field'as $field{
  356.                 if (!empty($field['name'])) {
  357.                     $this->field_name = $field['name'];
  358.                 else {
  359.                     $this->field_name = '';
  360.                 }
  361.                 $this->field = array(
  362.                     'sorting' => '',
  363.                     'length' => ''
  364.                 );
  365.  
  366.                 if (!empty($field['sorting'])) {
  367.                     $this->field['sorting'$field['sorting'];
  368.                 }
  369.                 if (!empty($field['length'])) {
  370.                     $this->field['length'$field['length'];
  371.                 }
  372.  
  373.                 $result $this->val->validateIndexField($this->index['fields']$this->field$this->field_name);
  374.                 if (PEAR::isError($result)) {
  375.                     return $this->raiseError($result->getUserinfo());
  376.                 }
  377.  
  378.                 $this->index['fields'][$this->field_name$this->field;
  379.             }
  380.         }
  381.  
  382.         $result $this->val->validateIndex($this->table['indexes']$this->index$this->index_name);
  383.         if (PEAR::isError($result)) {
  384.             return $this->raiseError($result->getUserinfo());
  385.         else {
  386.             $this->table['indexes'][$this->index_name$this->index;
  387.         }
  388.  
  389.         return MDB2_OK;
  390.     }
  391.  
  392.     function fixTableConstraintKeys($constraint
  393.     {
  394.         $this->constraint = array(
  395.             'was' => '',
  396.             'match' => '',
  397.             'ondelete' => '',
  398.             'onupdate' => '',
  399.             'deferrable' => '',
  400.             'initiallydeferred' => '',
  401.             'foreign' => true,
  402.             'fields' => array(),
  403.             'references' => array('table' => '''fields' => array())
  404.         );
  405.  
  406.         if (!empty($constraint['name'])) {
  407.             $this->constraint_name = $constraint['name'];
  408.         else {
  409.             $this->constraint_name = '';
  410.         }
  411.         if (!empty($constraint['was'])) {
  412.             $this->constraint['was'$constraint['was'];
  413.         }
  414.         if (!empty($constraint['match'])) {
  415.             $this->constraint['match'$constraint['match'];
  416.         }
  417.         if (!empty($constraint['ondelete'])) {
  418.             $this->constraint['ondelete'$constraint['ondelete'];
  419.         }
  420.         if (!empty($constraint['onupdate'])) {
  421.             $this->constraint['onupdate'$constraint['onupdate'];
  422.         }
  423.         if (!empty($constraint['deferrable'])) {
  424.             $this->constraint['deferrable'$constraint['deferrable'];
  425.         }
  426.         if (!empty($constraint['initiallydeferred'])) {
  427.             $this->constraint['initiallydeferred'$constraint['initiallydeferred'];
  428.         }
  429.         if (!empty($constraint['field']&& is_array($constraint['field'])) {
  430.             foreach ($constraint['field'as $field{
  431.                 $result $this->val->validateConstraintField($this->constraint['fields']$field);
  432.                 if (PEAR::isError($result)) {
  433.                     return $this->raiseError($result->getUserinfo());
  434.                 }
  435.  
  436.                 $this->constraint['fields'][$field'';
  437.             }
  438.         }
  439.  
  440.         if (!empty($constraint['references']&& is_array($constraint['references'])) {
  441.             /**
  442.              * As we forced 'table' to be enumerated
  443.              * we have to fix it on the foreign-references-table context
  444.              */
  445.             if (!empty($constraint['references']['table']&& is_array($constraint['references']['table'])) {
  446.                 $this->constraint['references']['table'$constraint['references']['table'][0];
  447.             }
  448.  
  449.             if (!empty($constraint['references']['field']&& is_array($constraint['references']['field'])) {
  450.                 foreach ($constraint['references']['field'as $field{
  451.                     $result $this->val->validateConstraintReferencedField($this->constraint['references']['fields']$field);
  452.                     if (PEAR::isError($result)) {
  453.                         return $this->raiseError($result->getUserinfo());
  454.                     }
  455.  
  456.                     $this->constraint['references']['fields'][$field'';
  457.                 }
  458.             }
  459.         }
  460.  
  461.         $result $this->val->validateConstraint($this->table['constraints']$this->constraint$this->constraint_name);
  462.         if (PEAR::isError($result)) {
  463.             return $this->raiseError($result->getUserinfo());
  464.         else {
  465.             $this->table['constraints'][$this->constraint_name$this->constraint;
  466.         }
  467.  
  468.         return MDB2_OK;
  469.     }
  470.  
  471.     function fixTableInitializationKeys($element$type '')
  472.     {
  473.         if (!empty($element['select']&& is_array($element['select'])) {
  474.             $this->fixTableInitializationDataKeys($element['select']);
  475.             $this->init = array'select' => $this->init );
  476.         else {
  477.             $this->fixTableInitializationDataKeys($element);
  478.         }
  479.  
  480.         $this->table['initialization'][= array'type' => $type'data' => $this->init );
  481.     }
  482.  
  483.     function fixTableInitializationDataKeys($element)
  484.     {
  485.         $this->init = array();
  486.         if (!empty($element['field']&& is_array($element['field'])) {
  487.             foreach ($element['field'as $field{
  488.                 $name $field['name'];
  489.                 unset($field['name']);
  490.  
  491.                 $this->setExpression($field);
  492.                 $this->init['field'][= array'name' => $name'group' => $field );
  493.             }
  494.         }
  495.         /**
  496.          * As we forced 'table' to be enumerated
  497.          * we have to fix it on the insert-select context
  498.          */
  499.         if (!empty($element['table']&& is_array($element['table'])) {
  500.             $this->init['table'$element['table'][0];
  501.         }
  502.         if (!empty($element['where']&& is_array($element['where'])) {
  503.             $this->init['where'$element['where'];
  504.             $this->setExpression($this->init['where']);
  505.         }
  506.     }
  507.  
  508.     function setExpression(&$arr)
  509.     {
  510.         $element each($arr);
  511.  
  512.         $arr = array'type' => $element['key');
  513.  
  514.         $element $element['value'];
  515.  
  516.         switch ($arr['type']{
  517.         case 'null':
  518.             break;
  519.         case 'value':
  520.         case 'column':
  521.             $arr['data'$element;
  522.             break;
  523.         case 'function':
  524.             if (!empty($element)
  525.                 && is_array($element)
  526.             {
  527.                 $arr['data'= array'name' => $element['name');
  528.                 unset($element['name']);
  529.  
  530.                 foreach ($element as $type => $value{
  531.                     if (!empty($value)) {
  532.                         if (is_array($value)) {
  533.                             foreach ($value as $argument{
  534.                                 $argument = array$type => $argument );
  535.                                 $this->setExpression($argument);
  536.                                 $arr['data']['arguments'][$argument;
  537.                             }
  538.                         else {
  539.                             $arr['data']['arguments'][= array'type' => $type'data' => $value );
  540.                         }
  541.                     }
  542.                 }
  543.             }
  544.             break;
  545.         case 'expression':
  546.             $arr['data'= array'operants' => array()'operator' => $element['operator');
  547.             unset($element['operator']);
  548.  
  549.             foreach ($element as $k => $v{
  550.                 $argument = array$k => $v );
  551.                 $this->setExpression($argument);
  552.                 $arr['data']['operants'][$argument;
  553.             }
  554.             break;
  555.         }
  556.     }
  557.  
  558.     function fixSequenceKeys($sequence)
  559.     {
  560.         $this->sequence = array(
  561.             'was' => '',
  562.             'start' => '',
  563.             'description' => '',
  564.             'comments' => '',
  565.             'on' => array('table' => '''field' => '')
  566.         );
  567.  
  568.         if (!empty($sequence['name'])) {
  569.             $this->sequence_name = $sequence['name'];
  570.         else {
  571.             $this->sequence_name = '';
  572.         }
  573.         if (!empty($sequence['was'])) {
  574.             $this->sequence['was'$sequence['was'];
  575.         }
  576.         if (!empty($sequence['start'])) {
  577.             $this->sequence['start'$sequence['start'];
  578.         }
  579.         if (!empty($sequence['description'])) {
  580.             $this->sequence['description'$sequence['description'];
  581.         }
  582.         if (!empty($sequence['comments'])) {
  583.             $this->sequence['comments'$sequence['comments'];
  584.         }
  585.         if (!empty($sequence['on']&& is_array($sequence['on'])) {
  586.             /**
  587.              * As we forced 'table' to be enumerated
  588.              * we have to fix it on the sequence-on-table context
  589.              */
  590.             if (!empty($sequence['on']['table']&& is_array($sequence['on']['table'])) {
  591.                 $this->sequence['on']['table'$sequence['on']['table'][0];
  592.             }
  593.  
  594.             /**
  595.              * As we forced 'field' to be enumerated
  596.              * we have to fix it on the sequence-on-field context
  597.              */
  598.             if (!empty($sequence['on']['field']&& is_array($sequence['on']['field'])) {
  599.                 $this->sequence['on']['field'$sequence['on']['field'][0];
  600.             }
  601.         }
  602.  
  603.         $result $this->val->validateSequence($this->database_definition['sequences']$this->sequence$this->sequence_name);
  604.         if (PEAR::isError($result)) {
  605.             return $this->raiseError($result->getUserinfo());
  606.         else {
  607.             $this->database_definition['sequences'][$this->sequence_name$this->sequence;
  608.         }
  609.  
  610.         return MDB2_OK;
  611.     }
  612.  
  613.     function &raiseError($msg = null$ecode = MDB2_SCHEMA_ERROR_PARSE)
  614.     {
  615.         if (is_null($this->error)) {
  616.             $error 'Parser error: '.$msg."\n";
  617.  
  618.             $this->error =MDB2_Schema::raiseError($ecodenullnull$error);
  619.         }
  620.         return $this->error;
  621.     }
  622. }
  623.  
  624. ?>

Documentation generated on Sun, 22 Feb 2009 22:30:07 +0000 by phpDocumentor 1.4.2. PEAR Logo Copyright © PHP Group 2004.