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

Source for file Validate.php

Documentation is available at Validate.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: Christian Dickmann <dickmann@php.net>                        |
  43. // | Author: Igor Feghali <ifeghali@php.net>                              |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: Validate.php,v 1.38 2008/02/06 23:13:51 ifeghali Exp $
  47. //
  48.  
  49. /**
  50.  * Validates an XML schema file
  51.  *
  52.  * @package MDB2_Schema
  53.  * @category Database
  54.  * @access protected
  55.  * @author Igor Feghali <ifeghali@php.net>
  56.  */
  57. {
  58.     // {{{ properties
  59.  
  60.     var $fail_on_invalid_names = true;
  61.     var $valid_types = array();
  62.     var $force_defaults = true;
  63.  
  64.     // }}}
  65.     // {{{ constructor
  66.  
  67.     function __construct($fail_on_invalid_names = true$valid_types = array()$force_defaults = true)
  68.     {
  69.         if (empty($GLOBALS['_MDB2_Schema_Reserved'])) {
  70.             $GLOBALS['_MDB2_Schema_Reserved'= array();
  71.         }
  72.  
  73.         if (is_array($fail_on_invalid_names)) {
  74.             $this->fail_on_invalid_names
  75.                 = array_intersect($fail_on_invalid_namesarray_keys($GLOBALS['_MDB2_Schema_Reserved']));
  76.         elseif ($fail_on_invalid_names === true{
  77.             $this->fail_on_invalid_names = array_keys($GLOBALS['_MDB2_Schema_Reserved']);
  78.         else {
  79.             $this->fail_on_invalid_names = array();
  80.         }
  81.         $this->valid_types = $valid_types;
  82.         $this->force_defaults = $force_defaults;
  83.     }
  84.  
  85.     function MDB2_Schema_Validate($fail_on_invalid_names = true$valid_types = array()$force_defaults = true)
  86.     {
  87.         $this->__construct($fail_on_invalid_names$valid_types$force_defaults);
  88.     }
  89.  
  90.     // }}}
  91.     // {{{ raiseError()
  92.  
  93.     function &raiseError($ecode$msg = null)
  94.     {
  95.         $error =MDB2_Schema::raiseError($ecodenullnull$msg);
  96.         return $error;
  97.     }
  98.  
  99.     // }}}
  100.     // {{{ isBoolean()
  101.  
  102.     /**
  103.      * Verifies if a given value can be considered boolean. If yes, set value
  104.      * to true or false according to its actual contents and return true. If
  105.      * not, keep its contents untouched and return false.
  106.      *
  107.      * @param mixed  value to be checked
  108.      *
  109.      * @return bool 
  110.      *
  111.      * @access public
  112.      * @static
  113.      */
  114.     function isBoolean(&$value)
  115.     {
  116.         if (is_bool($value)) {
  117.             return true;
  118.         }
  119.         if ($value === 0 || $value === 1 || $value === ''{
  120.             $value = (bool)$value;
  121.             return true;
  122.         }
  123.         if (!is_string($value)) {
  124.             return false;
  125.         }
  126.         switch ($value{
  127.         case '0':
  128.         case 'N':
  129.         case 'n':
  130.         case 'no':
  131.         case 'false':
  132.             $value = false;
  133.             break;
  134.         case '1':
  135.         case 'Y':
  136.         case 'y':
  137.         case 'yes':
  138.         case 'true':
  139.             $value = true;
  140.             break;
  141.         default:
  142.             return false;
  143.         }
  144.         return true;
  145.     }
  146.  
  147.     // }}}
  148.     // {{{ validateTable()
  149.  
  150.     /* Definition */
  151.     /**
  152.      * Checks whether the definition of a parsed table is valid. Modify table
  153.      * definition when necessary.
  154.      *
  155.      * @param array  multi dimensional array that contains the
  156.      *                 tables of current database.
  157.      * @param array  multi dimensional array that contains the
  158.      *                 structure and optional data of the table.
  159.      * @param string  name of the parsed table
  160.      *
  161.      * @return bool|errorobject
  162.      *
  163.      * @access public
  164.      */
  165.     function validateTable($tables&$table$table_name)
  166.     {
  167.         /* Have we got a name? */
  168.         if (!$table_name{
  169.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  170.                 'a table has to have a name');
  171.         }
  172.  
  173.         /* Table name duplicated? */
  174.         if (is_array($tables&& isset($tables[$table_name])) {
  175.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  176.                 'table "'.$table_name.'" already exists');
  177.         }
  178.  
  179.         /* Table name reserved? */
  180.         if (is_array($this->fail_on_invalid_names)) {
  181.             $name strtoupper($table_name);
  182.             foreach ($this->fail_on_invalid_names as $rdbms{
  183.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  184.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  185.                         'table name "'.$table_name.'" is a reserved word in: '.$rdbms);
  186.                 }
  187.             }
  188.         }
  189.  
  190.         /* Was */
  191.         if (empty($table['was'])) {
  192.             $table['was'$table_name;
  193.         }
  194.  
  195.         /* Have we got fields? */
  196.         if (empty($table['fields']|| !is_array($table['fields'])) {
  197.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  198.                 'tables need one or more fields');
  199.         }
  200.  
  201.         /* Autoincrement */
  202.         $autoinc $primary = false;
  203.         foreach ($table['fields'as $field_name => $field{
  204.             if (!empty($field['autoincrement'])) {
  205.                 if ($primary{
  206.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  207.                         'there was already an autoincrement field in "'.$table_name.'" before "'.$field_name.'"');
  208.                 }
  209.                 $autoinc $primary = true;
  210.             }
  211.         }
  212.  
  213.         /*
  214.          * Checking Indexes
  215.          * this have to be done here otherwise we can't
  216.          * guarantee that all table fields were already
  217.          * defined in the moment we are parsing indexes
  218.          */
  219.         if (!empty($table['indexes']&& is_array($table['indexes'])) {
  220.             foreach ($table['indexes'as $name => $index{
  221.                 $skip_index = false;
  222.                 if (!empty($index['primary'])) {
  223.                     /*
  224.                      * Lets see if we should skip this index since there is
  225.                      * already an auto increment on this field this implying
  226.                      * a primary key index.
  227.                      */
  228.                     if ($autoinc && count($index['fields']== '1'{
  229.                         $skip_index = true;
  230.                     elseif ($primary{
  231.                         return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  232.                             'there was already an primary index or autoincrement field in "'.$table_name.'" before "'.$name.'"');
  233.                     else {
  234.                         $primary = true;
  235.                     }
  236.                 }
  237.  
  238.                 if (!$skip_index && is_array($index['fields'])) {
  239.                     foreach ($index['fields'as $field_name => $field{
  240.                         if (!isset($table['fields'][$field_name])) {
  241.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  242.                                 'index field "'.$field_name.'" does not exist');
  243.                         }
  244.                         if (!empty($index['primary'])
  245.                             && !$table['fields'][$field_name]['notnull']
  246.                         {
  247.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  248.                                 'all primary key fields must be defined notnull in "'.$table_name.'"');
  249.                         }
  250.                     }
  251.                 else {
  252.                     unset($table['indexes'][$name]);
  253.                 }
  254.             }
  255.         }
  256.         return MDB2_OK;
  257.     }
  258.  
  259.     // }}}
  260.     // {{{ validateField()
  261.  
  262.     /**
  263.      * Checks whether the definition of a parsed field is valid. Modify field
  264.      * definition when necessary.
  265.      *
  266.      * @param array  multi dimensional array that contains the
  267.      *                 fields of current table.
  268.      * @param array  multi dimensional array that contains the
  269.      *                 structure of the parsed field.
  270.      * @param string  name of the parsed field
  271.      *
  272.      * @return bool|errorobject
  273.      *
  274.      * @access public
  275.      */
  276.     function validateField($fields&$field$field_name)
  277.     {
  278.         /* Have we got a name? */
  279.         if (!$field_name{
  280.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  281.                 'field name missing');
  282.         }
  283.  
  284.         /* Field name duplicated? */
  285.         if (is_array($fields&& isset($fields[$field_name])) {
  286.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  287.                 'field "'.$field_name.'" already exists');
  288.         }
  289.  
  290.         /* Field name reserverd? */
  291.         if (is_array($this->fail_on_invalid_names)) {
  292.             $name strtoupper($field_name);
  293.             foreach ($this->fail_on_invalid_names as $rdbms{
  294.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  295.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  296.                         'field name "'.$field_name.'" is a reserved word in: '.$rdbms);
  297.                 }
  298.             }
  299.         }
  300.  
  301.         /* Type check */
  302.         if (empty($field['type'])) {
  303.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  304.                 'no field type specified');
  305.         }
  306.         if (!empty($this->valid_types&& !array_key_exists($field['type']$this->valid_types)) {
  307.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  308.                 'no valid field type ("'.$field['type'].'") specified');
  309.         }
  310.  
  311.         /* Unsigned */
  312.         if (array_key_exists('unsigned'$field&& !$this->isBoolean($field['unsigned'])) {
  313.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  314.                 'unsigned has to be a boolean value');
  315.         }
  316.  
  317.         /* Fixed */
  318.         if (array_key_exists('fixed'$field&& !$this->isBoolean($field['fixed'])) {
  319.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  320.                 'fixed has to be a boolean value');
  321.         }
  322.  
  323.         /* Length */
  324.         if (array_key_exists('length'$field&& $field['length'<= 0{
  325.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  326.                 'length has to be an integer greater 0');
  327.         }
  328.  
  329.         // if it's a DECIMAL datatype, check if a 'scale' value is provided:
  330.         // <length>8,4</length> should be translated to DECIMAL(8,4)
  331.         if (is_float($this->valid_types[$field['type']])
  332.             && !empty($field['length'])
  333.             && strpos($field['length']','!== false
  334.         {
  335.             list($field['length']$field['scale']explode(','$field['length']);
  336.         }
  337.  
  338.         /* Was */
  339.         if (empty($field['was'])) {
  340.             $field['was'$field_name;
  341.         }
  342.  
  343.         /* Notnull */
  344.         if (empty($field['notnull'])) {
  345.             $field['notnull'= false;
  346.         }
  347.         if (!$this->isBoolean($field['notnull'])) {
  348.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  349.                 'field "notnull" has to be a boolean value');
  350.         }
  351.  
  352.         /* Default */
  353.         if ($this->force_defaults
  354.             && !array_key_exists('default'$field)
  355.             && $field['type'!= 'clob' && $field['type'!= 'blob'
  356.         {
  357.             $field['default'$this->valid_types[$field['type']];
  358.         }
  359.         if (array_key_exists('default'$field)) {
  360.             if ($field['type'== 'clob' || $field['type'== 'blob'{
  361.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  362.                     '"'.$field['type'].'"-fields are not allowed to have a default value');
  363.             }
  364.             if ($field['default'=== '' && !$field['notnull']{
  365.                 $field['default'= null;
  366.             }
  367.         }
  368.         if (isset($field['default'])
  369.             && PEAR::isError($result $this->validateDataFieldValue($field$field['default']$field_name))
  370.         {
  371.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  372.                 'default value of "'.$field_name.'" is incorrect: '.$result->getUserinfo());
  373.         }
  374.  
  375.         /* Autoincrement */
  376.         if (!empty($field['autoincrement'])) {
  377.             if (!$field['notnull']{
  378.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  379.                     'all autoincrement fields must be defined notnull');
  380.             }
  381.  
  382.             if (empty($field['default'])) {
  383.                 $field['default''0';
  384.             elseif ($field['default'!== '0' && $field['default'!== 0{
  385.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  386.                     'all autoincrement fields must be defined default "0"');
  387.             }
  388.         }
  389.         return MDB2_OK;
  390.     }
  391.  
  392.     // }}}
  393.     // {{{ validateIndex()
  394.  
  395.     /**
  396.      * Checks whether a parsed index is valid. Modify index definition when
  397.      * necessary.
  398.      *
  399.      * @param array  multi dimensional array that contains the
  400.      *                 indexes of current table.
  401.      * @param array  multi dimensional array that contains the
  402.      *                 structure of the parsed index.
  403.      * @param string  name of the parsed index
  404.      *
  405.      * @return bool|errorobject
  406.      *
  407.      * @access public
  408.      */
  409.     function validateIndex($table_indexes&$index$index_name)
  410.     {
  411.         if (!$index_name{
  412.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  413.                 'an index has to have a name');
  414.         }
  415.         if (is_array($table_indexes&& isset($table_indexes[$index_name])) {
  416.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  417.                 'index "'.$index_name.'" already exists');
  418.         }
  419.         if (array_key_exists('unique'$index&& !$this->isBoolean($index['unique'])) {
  420.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  421.                 'field "unique" has to be a boolean value');
  422.         }
  423.         if (array_key_exists('primary'$index&& !$this->isBoolean($index['primary'])) {
  424.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  425.                 'field "primary" has to be a boolean value');
  426.         }
  427.  
  428.         /* Have we got fields? */
  429.         if (empty($index['fields']|| !is_array($index['fields'])) {
  430.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  431.                 'indexes need one or more fields');
  432.         }
  433.  
  434.         if (empty($index['was'])) {
  435.             $index['was'$index_name;
  436.         }
  437.         return MDB2_OK;
  438.     }
  439.  
  440.     // }}}
  441.     // {{{ validateIndexField()
  442.  
  443.     /**
  444.      * Checks whether a parsed index-field is valid. Modify its definition when
  445.      * necessary.
  446.      *
  447.      * @param array  multi dimensional array that contains the
  448.      *                 fields of current index.
  449.      * @param array  multi dimensional array that contains the
  450.      *                 structure of the parsed index-field.
  451.      * @param string  name of the parsed index-field
  452.      *
  453.      * @return bool|errorobject
  454.      *
  455.      * @access public
  456.      */
  457.     function validateIndexField($index_fields&$field$field_name)
  458.     {
  459.         if (is_array($index_fields&& isset($index_fields[$field_name])) {
  460.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  461.                 'index field "'.$field_name.'" already exists');
  462.         }
  463.         if (!$field_name{
  464.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  465.                 'the index-field-name is required');
  466.         }
  467.         if (empty($field['sorting'])) {
  468.             $field['sorting''ascending';
  469.         elseif($field['sorting'!== 'ascending' && $field['sorting'!== 'descending'{
  470.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  471.                 'sorting type unknown');
  472.         }
  473.         return MDB2_OK;
  474.     }
  475.  
  476.     // }}}
  477.     // {{{ validateConstraint()
  478.  
  479.     /**
  480.      * Checks whether a parsed foreign key is valid. Modify its definition when
  481.      * necessary.
  482.      *
  483.      * @param array  multi dimensional array that contains the
  484.      *                 constraints of current table.
  485.      * @param array  multi dimensional array that contains the
  486.      *                 structure of the parsed foreign key.
  487.      * @param string  name of the parsed foreign key
  488.      *
  489.      * @return bool|errorobject
  490.      *
  491.      * @access public
  492.      */
  493.     function validateConstraint($table_constraints&$constraint$constraint_name)
  494.     {
  495.         if (!$constraint_name{
  496.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  497.                 'a foreign key has to have a name');
  498.         }
  499.         if (is_array($table_constraints&& isset($table_constraints[$constraint_name])) {
  500.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  501.                 'foreign key "'.$constraint_name.'" already exists');
  502.         }
  503.  
  504.         /* Have we got fields? */
  505.         if (empty($constraint['fields']|| !is_array($constraint['fields'])) {
  506.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  507.                 'foreign key "'.$constraint_name.'" need one or more fields');
  508.         }
  509.  
  510.         /* Have we got referenced fields? */
  511.         if (empty($constraint['references']|| !is_array($constraint['references'])) {
  512.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  513.                 'foreign key "'.$constraint_name.'" need to reference one or more fields');
  514.         }
  515.  
  516.         /* Have we got referenced table? */
  517.         if (empty($constraint['references']['table'])) {
  518.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  519.                 'foreign key "'.$constraint_name.'" need to reference a table');
  520.         }
  521.  
  522.         if (empty($constraint['was'])) {
  523.             $constraint['was'$constraint_name;
  524.         }
  525.         return MDB2_OK;
  526.     }
  527.  
  528.     // }}}
  529.     // {{{ validateConstraintField()
  530.  
  531.     /**
  532.      * Checks whether a foreign-field is valid.
  533.      *
  534.      * @param array  multi dimensional array that contains the
  535.      *                 fields of current foreign key.
  536.      * @param string  name of the parsed foreign-field
  537.      *
  538.      * @return bool|errorobject
  539.      *
  540.      * @access public
  541.      */
  542.     function validateConstraintField($constraint_fields$field_name)
  543.     {
  544.         if (!$field_name{
  545.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  546.                 'empty value for foreign-field');
  547.         }
  548.         if (is_array($constraint_fields&& isset($constraint_fields[$field_name])) {
  549.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  550.                 'foreign field "'.$field_name.'" already exists');
  551.         }
  552.         return MDB2_OK;
  553.     }
  554.  
  555.     // }}}
  556.     // {{{ validateConstraintReferencedField()
  557.  
  558.     /**
  559.      * Checks whether a foreign-referenced field is valid.
  560.      *
  561.      * @param array  multi dimensional array that contains the
  562.      *                 fields of current foreign key.
  563.      * @param string  name of the parsed foreign-field
  564.      *
  565.      * @return bool|errorobject
  566.      *
  567.      * @access public
  568.      */
  569.     function validateConstraintReferencedField($referenced_fields$field_name)
  570.     {
  571.         if (!$field_name{
  572.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  573.                 'empty value for referenced foreign-field');
  574.         }
  575.         if (is_array($referenced_fields&& isset($referenced_fields[$field_name])) {
  576.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  577.                 'foreign field "'.$field_name.'" already referenced');
  578.         }
  579.         return MDB2_OK;
  580.     }
  581.  
  582.     // }}}
  583.     // {{{ validateSequence()
  584.  
  585.     /**
  586.      * Checks whether the definition of a parsed sequence is valid. Modify
  587.      * sequence definition when necessary.
  588.      *
  589.      * @param array  multi dimensional array that contains the
  590.      *                 sequences of current database.
  591.      * @param array  multi dimensional array that contains the
  592.      *                 structure of the parsed sequence.
  593.      * @param string  name of the parsed sequence
  594.      *
  595.      * @return bool|errorobject
  596.      *
  597.      * @access public
  598.      */
  599.     function validateSequence($sequences&$sequence$sequence_name)
  600.     {
  601.         if (!$sequence_name{
  602.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  603.                 'a sequence has to have a name');
  604.         }
  605.  
  606.         if (is_array($sequences&& isset($sequences[$sequence_name])) {
  607.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  608.                 'sequence "'.$sequence_name.'" already exists');
  609.         }
  610.  
  611.         if (is_array($this->fail_on_invalid_names)) {
  612.             $name strtoupper($sequence_name);
  613.             foreach ($this->fail_on_invalid_names as $rdbms{
  614.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  615.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  616.                         'sequence name "'.$sequence_name.'" is a reserved word in: '.$rdbms);
  617.                 }
  618.             }
  619.         }
  620.  
  621.         if (empty($sequence['was'])) {
  622.             $sequence['was'$sequence_name;
  623.         }
  624.  
  625.         if (!empty($sequence['on'])
  626.             && (empty($sequence['on']['table']|| empty($sequence['on']['field']))
  627.         {
  628.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  629.                 'sequence "'.$sequence_name.'" on a table was not properly defined');
  630.         }
  631.         return MDB2_OK;
  632.     }
  633.  
  634.     // }}}
  635.     // {{{ validateDatabase()
  636.  
  637.     /**
  638.      * Checks whether a parsed database is valid. Modify its structure and
  639.      * data when necessary.
  640.      *
  641.      * @param array  multi dimensional array that contains the
  642.      *                 structure and optional data of the database.
  643.      *
  644.      * @return bool|errorobject
  645.      *
  646.      * @access public
  647.      */
  648.     function validateDatabase(&$database)
  649.     {
  650.         /* Have we got a name? */
  651.         if (!is_array($database|| !isset($database['name']|| !$database['name']{
  652.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  653.                 'a database has to have a name');
  654.         }
  655.  
  656.         /* Database name reserved? */
  657.         if (is_array($this->fail_on_invalid_names)) {
  658.             $name strtoupper($database['name']);
  659.             foreach ($this->fail_on_invalid_names as $rdbms{
  660.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  661.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  662.                         'database name "'.$database['name'].'" is a reserved word in: '.$rdbms);
  663.                 }
  664.             }
  665.         }
  666.  
  667.         /* Create */
  668.         if (isset($database['create'])
  669.             && !$this->isBoolean($database['create'])
  670.         {
  671.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  672.                 'field "create" has to be a boolean value');
  673.         }
  674.  
  675.         /* Overwrite */
  676.         if (isset($database['overwrite'])
  677.             && $database['overwrite'!== ''
  678.             && !$this->isBoolean($database['overwrite'])
  679.         {
  680.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  681.                 'field "overwrite" has to be a boolean value');
  682.         }
  683.  
  684.         /*
  685.          * This have to be done here otherwise we can't guarantee that all
  686.          * tables were already defined in the moment we are parsing constraints
  687.          */
  688.         if (isset($database['tables'])) {
  689.             foreach ($database['tables'as $table_name => $table{
  690.                 if (!empty($table['constraints'])) {
  691.                     foreach ($table['constraints'as $constraint_name => $constraint{
  692.                         $referenced_table_name $constraint['references']['table'];
  693.  
  694.                         if (!isset($database['tables'][$referenced_table_name])) {
  695.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  696.                                 'referenced table "'.$referenced_table_name.'" of foreign key "'.$constraint_name.'" of table "'.$table_name.'" does not exist');
  697.                         }
  698.  
  699.                         if (empty($constraint['references']['fields'])) {
  700.                             $referenced_table $database['tables'][$referenced_table_name];
  701.                             $primary = false;
  702.  
  703.                             if (!empty($referenced_table['indexes'])) {
  704.                                 foreach ($referenced_table['indexes'as $index_name => $index{
  705.                                     if (array_key_exists('primary'$index)
  706.                                         && $index['primary']
  707.                                     {
  708.                                         $primary = array();
  709.                                         foreach ($index['fields'as $field_name => $field{
  710.                                             $primary[$field_name'';
  711.                                         }
  712.                                         break;
  713.                                     }
  714.                                 }
  715.                             }
  716.  
  717.                             if (!$primary{
  718.                                 foreach ($referenced_table['fields'as $field_name => $field{
  719.                                     if (array_key_exists('autoincrement'$field)
  720.                                         && $field['autoincrement']
  721.                                     {
  722.                                         $primary = array$field_name => '' );
  723.                                         break;
  724.                                     }
  725.                                 }
  726.                             }
  727.  
  728.                             if (!$primary{
  729.                                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  730.                                     'referenced table "'.$referenced_table_name.'" has no primary key and no referenced field was specified for foreign key "'.$constraint_name.'" of table "'.$table_name.'"');
  731.                             }
  732.  
  733.                             $constraint['references']['fields'$primary;
  734.                         }
  735.  
  736.                         /* the same number of referencing and referenced fields ? */
  737.                         if (count($constraint['fields']!= count($constraint['references']['fields'])) {
  738.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  739.                                 'The number of fields in the referenced key must match those of the foreign key "'.$constraint_name.'"');
  740.                         }
  741.  
  742.                         $database['tables'][$table_name]['constraints'][$constraint_name]['references']['fields'$constraint['references']['fields'];
  743.                     }
  744.                 }
  745.             }
  746.         }
  747.  
  748.         /*
  749.          * This have to be done here otherwise we can't guarantee that all
  750.          * tables were already defined in the moment we are parsing sequences
  751.          */
  752.         if (isset($database['sequences'])) {
  753.             foreach ($database['sequences'as $seq_name => $seq{
  754.                 if (!empty($seq['on'])
  755.                     && empty($database['tables'][$seq['on']['table']]['fields'][$seq['on']['field']])
  756.                 {
  757.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  758.                         'sequence "'.$seq_name.'" was assigned on unexisting field/table');
  759.                 }
  760.             }
  761.         }
  762.         return MDB2_OK;
  763.     }
  764.  
  765.     // }}}
  766.     // {{{ validateDataField()
  767.  
  768.     /* Data Manipulation */
  769.     /**
  770.      * Checks whether a parsed DML-field is valid. Modify its structure when
  771.      * necessary. This is called when validating INSERT and
  772.      * UPDATE.
  773.      *
  774.      * @param array  multi dimensional array that contains the
  775.      *                 definition for current table's fields.
  776.      * @param array  multi dimensional array that contains the
  777.      *                 parsed fields of the current DML instruction.
  778.      * @param string  array that contains the parsed instruction field
  779.      *
  780.      * @return bool|errorobject
  781.      *
  782.      * @access public
  783.      */
  784.     function validateDataField($table_fields$instruction_fields&$field)
  785.     {
  786.         if (!$field['name']{
  787.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  788.                 'field-name has to be specified');
  789.         }
  790.         if (is_array($instruction_fields&& isset($instruction_fields[$field['name']])) {
  791.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  792.                 'field "'.$field['name'].'" already initialized');
  793.         }
  794.         if (is_array($table_fields&& !isset($table_fields[$field['name']])) {
  795.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  796.                 '"'.$field['name'].'" is not defined');
  797.         }
  798.         if (!isset($field['group']['type'])) {
  799.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  800.                 '"'.$field['name'].'" has no initial value');
  801.         }
  802.         if (isset($field['group']['data'])
  803.             && $field['group']['type'== 'value'
  804.             && $field['group']['data'!== ''
  805.             && PEAR::isError($result $this->validateDataFieldValue($table_fields[$field['name']]$field['group']['data']$field['name']))
  806.         {
  807.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  808.                 'value of "'.$field['name'].'" is incorrect: '.$result->getUserinfo());
  809.         }
  810.         return MDB2_OK;
  811.     }
  812.  
  813.     // }}}
  814.     // {{{ validateDataFieldValue()
  815.  
  816.     /**
  817.      * Checks whether a given value is compatible with a table field. This is
  818.      * done when parsing a field for a INSERT or UPDATE instruction.
  819.      *
  820.      * @param array  multi dimensional array that contains the
  821.      *                 definition for current table's fields.
  822.      * @param string  value to fill the parsed field
  823.      * @param string  name of the parsed field
  824.      *
  825.      * @return bool|errorobject
  826.      *
  827.      * @access public
  828.      * @see MDB2_Schema_Validate::validateInsertField()
  829.      */
  830.     function validateDataFieldValue($field_def&$field_value$field_name)
  831.     {
  832.         switch ($field_def['type']{
  833.         case 'text':
  834.         case 'clob':
  835.             if (!empty($field_def['length']&& strlen($field_value$field_def['length']{
  836.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  837.                     '"'.$field_value.'" is larger than "'.$field_def['length'].'"');
  838.             }
  839.             break;
  840.         case 'blob':
  841.             $field_value pack('H*'$field_value);
  842.             if (!empty($field_def['length']&& strlen($field_value$field_def['length']{
  843.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  844.                     '"'.$field_value.'" is larger than "'.$field_def['type'].'"');
  845.             }
  846.             break;
  847.         case 'integer':
  848.             if ($field_value != ((int)$field_value)) {
  849.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  850.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  851.             }
  852.             //$field_value = (int)$field_value;
  853.             if (!empty($field_def['unsigned']&& $field_def['unsigned'&& $field_value < 0{
  854.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  855.                     '"'.$field_value.'" signed instead of unsigned');
  856.             }
  857.             break;
  858.         case 'boolean':
  859.             if (!$this->isBoolean($field_value)) {
  860.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  861.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  862.             }
  863.             break;
  864.         case 'date':
  865.             if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/'$field_value)
  866.                 && $field_value !== 'CURRENT_DATE'
  867.             {
  868.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  869.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  870.             }
  871.             break;
  872.         case 'timestamp':
  873.             if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/'$field_value)
  874.                 && $field_value !== 'CURRENT_TIMESTAMP'
  875.             {
  876.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  877.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  878.             }
  879.             break;
  880.         case 'time':
  881.             if (!preg_match("/([0-9]{2}):([0-9]{2}):([0-9]{2})/"$field_value)
  882.                 && $field_value !== 'CURRENT_TIME'
  883.             {
  884.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  885.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  886.             }
  887.             break;
  888.         case 'float':
  889.         case 'double':
  890.             if ($field_value != (double)$field_value{
  891.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  892.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  893.             }
  894.             //$field_value = (double)$field_value;
  895.             break;
  896.         }
  897.         return MDB2_OK;
  898.     }
  899. }
  900.  
  901. ?>

Documentation generated on Mon, 11 Mar 2019 15:16:45 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.