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.40 2008/11/15 23:53:47 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 ($autoinc{
  206.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  207.                         'there was already an autoincrement field in "'.$table_name.'" before "'.$field_name.'"');
  208.                 }
  209.                 $autoinc $field_name;
  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 (count($index['fields']== '1'
  229.                         && array_key_exists($autoinc$index['fields'])) {
  230.                         $skip_index = true;
  231.                     elseif ($autoinc || $primary{
  232.                         return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  233.                             'there was already an primary index or autoincrement field in "'.$table_name.'" before "'.$name.'"');
  234.                     else {
  235.                         $primary = true;
  236.                     }
  237.                 }
  238.  
  239.                 if (!$skip_index && is_array($index['fields'])) {
  240.                     foreach ($index['fields'as $field_name => $field{
  241.                         if (!isset($table['fields'][$field_name])) {
  242.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  243.                                 'index field "'.$field_name.'" does not exist');
  244.                         }
  245.                         if (!empty($index['primary'])
  246.                             && !$table['fields'][$field_name]['notnull']
  247.                         {
  248.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  249.                                 'all primary key fields must be defined notnull in "'.$table_name.'"');
  250.                         }
  251.                     }
  252.                 else {
  253.                     unset($table['indexes'][$name]);
  254.                 }
  255.             }
  256.         }
  257.         return MDB2_OK;
  258.     }
  259.  
  260.     // }}}
  261.     // {{{ validateField()
  262.  
  263.     /**
  264.      * Checks whether the definition of a parsed field is valid. Modify field
  265.      * definition when necessary.
  266.      *
  267.      * @param array  multi dimensional array that contains the
  268.      *                 fields of current table.
  269.      * @param array  multi dimensional array that contains the
  270.      *                 structure of the parsed field.
  271.      * @param string  name of the parsed field
  272.      *
  273.      * @return bool|errorobject
  274.      *
  275.      * @access public
  276.      */
  277.     function validateField($fields&$field$field_name)
  278.     {
  279.         /* Have we got a name? */
  280.         if (!$field_name{
  281.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  282.                 'field name missing');
  283.         }
  284.  
  285.         /* Field name duplicated? */
  286.         if (is_array($fields&& isset($fields[$field_name])) {
  287.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  288.                 'field "'.$field_name.'" already exists');
  289.         }
  290.  
  291.         /* Field name reserverd? */
  292.         if (is_array($this->fail_on_invalid_names)) {
  293.             $name strtoupper($field_name);
  294.             foreach ($this->fail_on_invalid_names as $rdbms{
  295.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  296.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  297.                         'field name "'.$field_name.'" is a reserved word in: '.$rdbms);
  298.                 }
  299.             }
  300.         }
  301.  
  302.         /* Type check */
  303.         if (empty($field['type'])) {
  304.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  305.                 'no field type specified');
  306.         }
  307.         if (!empty($this->valid_types&& !array_key_exists($field['type']$this->valid_types)) {
  308.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  309.                 'no valid field type ("'.$field['type'].'") specified');
  310.         }
  311.  
  312.         /* Unsigned */
  313.         if (array_key_exists('unsigned'$field&& !$this->isBoolean($field['unsigned'])) {
  314.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  315.                 'unsigned has to be a boolean value');
  316.         }
  317.  
  318.         /* Fixed */
  319.         if (array_key_exists('fixed'$field&& !$this->isBoolean($field['fixed'])) {
  320.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  321.                 'fixed has to be a boolean value');
  322.         }
  323.  
  324.         /* Length */
  325.         if (array_key_exists('length'$field&& $field['length'<= 0{
  326.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  327.                 'length has to be an integer greater 0');
  328.         }
  329.  
  330.         // if it's a DECIMAL datatype, check if a 'scale' value is provided:
  331.         // <length>8,4</length> should be translated to DECIMAL(8,4)
  332.         if (is_float($this->valid_types[$field['type']])
  333.             && !empty($field['length'])
  334.             && strpos($field['length']','!== false
  335.         {
  336.             list($field['length']$field['scale']explode(','$field['length']);
  337.         }
  338.  
  339.         /* Was */
  340.         if (empty($field['was'])) {
  341.             $field['was'$field_name;
  342.         }
  343.  
  344.         /* Notnull */
  345.         if (empty($field['notnull'])) {
  346.             $field['notnull'= false;
  347.         }
  348.         if (!$this->isBoolean($field['notnull'])) {
  349.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  350.                 'field "notnull" has to be a boolean value');
  351.         }
  352.  
  353.         /* Default */
  354.         if ($this->force_defaults
  355.             && !array_key_exists('default'$field)
  356.             && $field['type'!= 'clob' && $field['type'!= 'blob'
  357.         {
  358.             $field['default'$this->valid_types[$field['type']];
  359.         }
  360.         if (array_key_exists('default'$field)) {
  361.             if ($field['type'== 'clob' || $field['type'== 'blob'{
  362.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  363.                     '"'.$field['type'].'"-fields are not allowed to have a default value');
  364.             }
  365.             if ($field['default'=== '' && !$field['notnull']{
  366.                 $field['default'= null;
  367.             }
  368.         }
  369.         if (isset($field['default'])
  370.             && PEAR::isError($result $this->validateDataFieldValue($field$field['default']$field_name))
  371.         {
  372.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  373.                 'default value of "'.$field_name.'" is incorrect: '.$result->getUserinfo());
  374.         }
  375.  
  376.         /* Autoincrement */
  377.         if (!empty($field['autoincrement'])) {
  378.             if (!$field['notnull']{
  379.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  380.                     'all autoincrement fields must be defined notnull');
  381.             }
  382.  
  383.             if (empty($field['default'])) {
  384.                 $field['default''0';
  385.             elseif ($field['default'!== '0' && $field['default'!== 0{
  386.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  387.                     'all autoincrement fields must be defined default "0"');
  388.             }
  389.         }
  390.         return MDB2_OK;
  391.     }
  392.  
  393.     // }}}
  394.     // {{{ validateIndex()
  395.  
  396.     /**
  397.      * Checks whether a parsed index is valid. Modify index definition when
  398.      * necessary.
  399.      *
  400.      * @param array  multi dimensional array that contains the
  401.      *                 indexes of current table.
  402.      * @param array  multi dimensional array that contains the
  403.      *                 structure of the parsed index.
  404.      * @param string  name of the parsed index
  405.      *
  406.      * @return bool|errorobject
  407.      *
  408.      * @access public
  409.      */
  410.     function validateIndex($table_indexes&$index$index_name)
  411.     {
  412.         if (!$index_name{
  413.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  414.                 'an index has to have a name');
  415.         }
  416.         if (is_array($table_indexes&& isset($table_indexes[$index_name])) {
  417.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  418.                 'index "'.$index_name.'" already exists');
  419.         }
  420.         if (array_key_exists('unique'$index&& !$this->isBoolean($index['unique'])) {
  421.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  422.                 'field "unique" has to be a boolean value');
  423.         }
  424.         if (array_key_exists('primary'$index&& !$this->isBoolean($index['primary'])) {
  425.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  426.                 'field "primary" has to be a boolean value');
  427.         }
  428.  
  429.         /* Have we got fields? */
  430.         if (empty($index['fields']|| !is_array($index['fields'])) {
  431.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  432.                 'indexes need one or more fields');
  433.         }
  434.  
  435.         if (empty($index['was'])) {
  436.             $index['was'$index_name;
  437.         }
  438.         return MDB2_OK;
  439.     }
  440.  
  441.     // }}}
  442.     // {{{ validateIndexField()
  443.  
  444.     /**
  445.      * Checks whether a parsed index-field is valid. Modify its definition when
  446.      * necessary.
  447.      *
  448.      * @param array  multi dimensional array that contains the
  449.      *                 fields of current index.
  450.      * @param array  multi dimensional array that contains the
  451.      *                 structure of the parsed index-field.
  452.      * @param string  name of the parsed index-field
  453.      *
  454.      * @return bool|errorobject
  455.      *
  456.      * @access public
  457.      */
  458.     function validateIndexField($index_fields&$field$field_name)
  459.     {
  460.         if (is_array($index_fields&& isset($index_fields[$field_name])) {
  461.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  462.                 'index field "'.$field_name.'" already exists');
  463.         }
  464.         if (!$field_name{
  465.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  466.                 'the index-field-name is required');
  467.         }
  468.         if (empty($field['sorting'])) {
  469.             $field['sorting''ascending';
  470.         elseif($field['sorting'!== 'ascending' && $field['sorting'!== 'descending'{
  471.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  472.                 'sorting type unknown');
  473.         }
  474.         return MDB2_OK;
  475.     }
  476.  
  477.     // }}}
  478.     // {{{ validateConstraint()
  479.  
  480.     /**
  481.      * Checks whether a parsed foreign key is valid. Modify its definition when
  482.      * necessary.
  483.      *
  484.      * @param array  multi dimensional array that contains the
  485.      *                 constraints of current table.
  486.      * @param array  multi dimensional array that contains the
  487.      *                 structure of the parsed foreign key.
  488.      * @param string  name of the parsed foreign key
  489.      *
  490.      * @return bool|errorobject
  491.      *
  492.      * @access public
  493.      */
  494.     function validateConstraint($table_constraints&$constraint$constraint_name)
  495.     {
  496.         if (!$constraint_name{
  497.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  498.                 'a foreign key has to have a name');
  499.         }
  500.         if (is_array($table_constraints&& isset($table_constraints[$constraint_name])) {
  501.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  502.                 'foreign key "'.$constraint_name.'" already exists');
  503.         }
  504.  
  505.         /* Have we got fields? */
  506.         if (empty($constraint['fields']|| !is_array($constraint['fields'])) {
  507.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  508.                 'foreign key "'.$constraint_name.'" need one or more fields');
  509.         }
  510.  
  511.         /* Have we got referenced fields? */
  512.         if (empty($constraint['references']|| !is_array($constraint['references'])) {
  513.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  514.                 'foreign key "'.$constraint_name.'" need to reference one or more fields');
  515.         }
  516.  
  517.         /* Have we got referenced table? */
  518.         if (empty($constraint['references']['table'])) {
  519.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  520.                 'foreign key "'.$constraint_name.'" need to reference a table');
  521.         }
  522.  
  523.         if (empty($constraint['was'])) {
  524.             $constraint['was'$constraint_name;
  525.         }
  526.         return MDB2_OK;
  527.     }
  528.  
  529.     // }}}
  530.     // {{{ validateConstraintField()
  531.  
  532.     /**
  533.      * Checks whether a foreign-field is valid.
  534.      *
  535.      * @param array  multi dimensional array that contains the
  536.      *                 fields of current foreign key.
  537.      * @param string  name of the parsed foreign-field
  538.      *
  539.      * @return bool|errorobject
  540.      *
  541.      * @access public
  542.      */
  543.     function validateConstraintField($constraint_fields$field_name)
  544.     {
  545.         if (!$field_name{
  546.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  547.                 'empty value for foreign-field');
  548.         }
  549.         if (is_array($constraint_fields&& isset($constraint_fields[$field_name])) {
  550.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  551.                 'foreign field "'.$field_name.'" already exists');
  552.         }
  553.         return MDB2_OK;
  554.     }
  555.  
  556.     // }}}
  557.     // {{{ validateConstraintReferencedField()
  558.  
  559.     /**
  560.      * Checks whether a foreign-referenced field is valid.
  561.      *
  562.      * @param array  multi dimensional array that contains the
  563.      *                 fields of current foreign key.
  564.      * @param string  name of the parsed foreign-field
  565.      *
  566.      * @return bool|errorobject
  567.      *
  568.      * @access public
  569.      */
  570.     function validateConstraintReferencedField($referenced_fields$field_name)
  571.     {
  572.         if (!$field_name{
  573.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  574.                 'empty value for referenced foreign-field');
  575.         }
  576.         if (is_array($referenced_fields&& isset($referenced_fields[$field_name])) {
  577.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  578.                 'foreign field "'.$field_name.'" already referenced');
  579.         }
  580.         return MDB2_OK;
  581.     }
  582.  
  583.     // }}}
  584.     // {{{ validateSequence()
  585.  
  586.     /**
  587.      * Checks whether the definition of a parsed sequence is valid. Modify
  588.      * sequence definition when necessary.
  589.      *
  590.      * @param array  multi dimensional array that contains the
  591.      *                 sequences of current database.
  592.      * @param array  multi dimensional array that contains the
  593.      *                 structure of the parsed sequence.
  594.      * @param string  name of the parsed sequence
  595.      *
  596.      * @return bool|errorobject
  597.      *
  598.      * @access public
  599.      */
  600.     function validateSequence($sequences&$sequence$sequence_name)
  601.     {
  602.         if (!$sequence_name{
  603.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  604.                 'a sequence has to have a name');
  605.         }
  606.  
  607.         if (is_array($sequences&& isset($sequences[$sequence_name])) {
  608.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  609.                 'sequence "'.$sequence_name.'" already exists');
  610.         }
  611.  
  612.         if (is_array($this->fail_on_invalid_names)) {
  613.             $name strtoupper($sequence_name);
  614.             foreach ($this->fail_on_invalid_names as $rdbms{
  615.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  616.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  617.                         'sequence name "'.$sequence_name.'" is a reserved word in: '.$rdbms);
  618.                 }
  619.             }
  620.         }
  621.  
  622.         if (empty($sequence['was'])) {
  623.             $sequence['was'$sequence_name;
  624.         }
  625.  
  626.         if (!empty($sequence['on'])
  627.             && (empty($sequence['on']['table']|| empty($sequence['on']['field']))
  628.         {
  629.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  630.                 'sequence "'.$sequence_name.'" on a table was not properly defined');
  631.         }
  632.         return MDB2_OK;
  633.     }
  634.  
  635.     // }}}
  636.     // {{{ validateDatabase()
  637.  
  638.     /**
  639.      * Checks whether a parsed database is valid. Modify its structure and
  640.      * data when necessary.
  641.      *
  642.      * @param array  multi dimensional array that contains the
  643.      *                 structure and optional data of the database.
  644.      *
  645.      * @return bool|errorobject
  646.      *
  647.      * @access public
  648.      */
  649.     function validateDatabase(&$database)
  650.     {
  651.         /* Have we got a name? */
  652.         if (!is_array($database|| !isset($database['name']|| !$database['name']{
  653.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  654.                 'a database has to have a name');
  655.         }
  656.  
  657.         /* Database name reserved? */
  658.         if (is_array($this->fail_on_invalid_names)) {
  659.             $name strtoupper($database['name']);
  660.             foreach ($this->fail_on_invalid_names as $rdbms{
  661.                 if (in_array($name$GLOBALS['_MDB2_Schema_Reserved'][$rdbms])) {
  662.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  663.                         'database name "'.$database['name'].'" is a reserved word in: '.$rdbms);
  664.                 }
  665.             }
  666.         }
  667.  
  668.         /* Create */
  669.         if (isset($database['create'])
  670.             && !$this->isBoolean($database['create'])
  671.         {
  672.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  673.                 'field "create" has to be a boolean value');
  674.         }
  675.  
  676.         /* Overwrite */
  677.         if (isset($database['overwrite'])
  678.             && $database['overwrite'!== ''
  679.             && !$this->isBoolean($database['overwrite'])
  680.         {
  681.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  682.                 'field "overwrite" has to be a boolean value');
  683.         }
  684.  
  685.         /*
  686.          * This have to be done here otherwise we can't guarantee that all
  687.          * tables were already defined in the moment we are parsing constraints
  688.          */
  689.         if (isset($database['tables'])) {
  690.             foreach ($database['tables'as $table_name => $table{
  691.                 if (!empty($table['constraints'])) {
  692.                     foreach ($table['constraints'as $constraint_name => $constraint{
  693.                         $referenced_table_name $constraint['references']['table'];
  694.  
  695.                         if (!isset($database['tables'][$referenced_table_name])) {
  696.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  697.                                 'referenced table "'.$referenced_table_name.'" of foreign key "'.$constraint_name.'" of table "'.$table_name.'" does not exist');
  698.                         }
  699.  
  700.                         if (empty($constraint['references']['fields'])) {
  701.                             $referenced_table $database['tables'][$referenced_table_name];
  702.                             $primary = false;
  703.  
  704.                             if (!empty($referenced_table['indexes'])) {
  705.                                 foreach ($referenced_table['indexes'as $index_name => $index{
  706.                                     if (array_key_exists('primary'$index)
  707.                                         && $index['primary']
  708.                                     {
  709.                                         $primary = array();
  710.                                         foreach ($index['fields'as $field_name => $field{
  711.                                             $primary[$field_name'';
  712.                                         }
  713.                                         break;
  714.                                     }
  715.                                 }
  716.                             }
  717.  
  718.                             if (!$primary{
  719.                                 foreach ($referenced_table['fields'as $field_name => $field{
  720.                                     if (array_key_exists('autoincrement'$field)
  721.                                         && $field['autoincrement']
  722.                                     {
  723.                                         $primary = array$field_name => '' );
  724.                                         break;
  725.                                     }
  726.                                 }
  727.                             }
  728.  
  729.                             if (!$primary{
  730.                                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  731.                                     'referenced table "'.$referenced_table_name.'" has no primary key and no referenced field was specified for foreign key "'.$constraint_name.'" of table "'.$table_name.'"');
  732.                             }
  733.  
  734.                             $constraint['references']['fields'$primary;
  735.                         }
  736.  
  737.                         /* the same number of referencing and referenced fields ? */
  738.                         if (count($constraint['fields']!= count($constraint['references']['fields'])) {
  739.                             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  740.                                 'The number of fields in the referenced key must match those of the foreign key "'.$constraint_name.'"');
  741.                         }
  742.  
  743.                         $database['tables'][$table_name]['constraints'][$constraint_name]['references']['fields'$constraint['references']['fields'];
  744.                     }
  745.                 }
  746.             }
  747.         }
  748.  
  749.         /*
  750.          * This have to be done here otherwise we can't guarantee that all
  751.          * tables were already defined in the moment we are parsing sequences
  752.          */
  753.         if (isset($database['sequences'])) {
  754.             foreach ($database['sequences'as $seq_name => $seq{
  755.                 if (!empty($seq['on'])
  756.                     && empty($database['tables'][$seq['on']['table']]['fields'][$seq['on']['field']])
  757.                 {
  758.                     return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  759.                         'sequence "'.$seq_name.'" was assigned on unexisting field/table');
  760.                 }
  761.             }
  762.         }
  763.         return MDB2_OK;
  764.     }
  765.  
  766.     // }}}
  767.     // {{{ validateDataField()
  768.  
  769.     /* Data Manipulation */
  770.     /**
  771.      * Checks whether a parsed DML-field is valid. Modify its structure when
  772.      * necessary. This is called when validating INSERT and
  773.      * UPDATE.
  774.      *
  775.      * @param array  multi dimensional array that contains the
  776.      *                 definition for current table's fields.
  777.      * @param array  multi dimensional array that contains the
  778.      *                 parsed fields of the current DML instruction.
  779.      * @param string  array that contains the parsed instruction field
  780.      *
  781.      * @return bool|errorobject
  782.      *
  783.      * @access public
  784.      */
  785.     function validateDataField($table_fields$instruction_fields&$field)
  786.     {
  787.         if (!$field['name']{
  788.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  789.                 'field-name has to be specified');
  790.         }
  791.         if (is_array($instruction_fields&& isset($instruction_fields[$field['name']])) {
  792.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  793.                 'field "'.$field['name'].'" already initialized');
  794.         }
  795.         if (is_array($table_fields&& !isset($table_fields[$field['name']])) {
  796.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  797.                 '"'.$field['name'].'" is not defined');
  798.         }
  799.         if (!isset($field['group']['type'])) {
  800.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  801.                 '"'.$field['name'].'" has no initial value');
  802.         }
  803.         if (isset($field['group']['data'])
  804.             && $field['group']['type'== 'value'
  805.             && $field['group']['data'!== ''
  806.             && PEAR::isError($result $this->validateDataFieldValue($table_fields[$field['name']]$field['group']['data']$field['name']))
  807.         {
  808.             return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  809.                 'value of "'.$field['name'].'" is incorrect: '.$result->getUserinfo());
  810.         }
  811.         return MDB2_OK;
  812.     }
  813.  
  814.     // }}}
  815.     // {{{ validateDataFieldValue()
  816.  
  817.     /**
  818.      * Checks whether a given value is compatible with a table field. This is
  819.      * done when parsing a field for a INSERT or UPDATE instruction.
  820.      *
  821.      * @param array  multi dimensional array that contains the
  822.      *                 definition for current table's fields.
  823.      * @param string  value to fill the parsed field
  824.      * @param string  name of the parsed field
  825.      *
  826.      * @return bool|errorobject
  827.      *
  828.      * @access public
  829.      * @see MDB2_Schema_Validate::validateInsertField()
  830.      */
  831.     function validateDataFieldValue($field_def&$field_value$field_name)
  832.     {
  833.         switch ($field_def['type']{
  834.         case 'text':
  835.         case 'clob':
  836.             if (!empty($field_def['length']&& strlen($field_value$field_def['length']{
  837.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  838.                     '"'.$field_value.'" is larger than "'.$field_def['length'].'"');
  839.             }
  840.             break;
  841.         case 'blob':
  842.             $field_value pack('H*'$field_value);
  843.             if (!empty($field_def['length']&& strlen($field_value$field_def['length']{
  844.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  845.                     '"'.$field_value.'" is larger than "'.$field_def['type'].'"');
  846.             }
  847.             break;
  848.         case 'integer':
  849.             if ($field_value != ((int)$field_value)) {
  850.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  851.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  852.             }
  853.             //$field_value = (int)$field_value;
  854.             if (!empty($field_def['unsigned']&& $field_def['unsigned'&& $field_value < 0{
  855.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  856.                     '"'.$field_value.'" signed instead of unsigned');
  857.             }
  858.             break;
  859.         case 'boolean':
  860.             if (!$this->isBoolean($field_value)) {
  861.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  862.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  863.             }
  864.             break;
  865.         case 'date':
  866.             if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/'$field_value)
  867.                 && $field_value !== 'CURRENT_DATE'
  868.             {
  869.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  870.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  871.             }
  872.             break;
  873.         case 'timestamp':
  874.             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)
  875.                 && strcasecmp($field_value'now()'!= 0
  876.                 && $field_value !== 'CURRENT_TIMESTAMP'
  877.             {
  878.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  879.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  880.             }
  881.             break;
  882.         case 'time':
  883.             if (!preg_match("/([0-9]{2}):([0-9]{2}):([0-9]{2})/"$field_value)
  884.                 && $field_value !== 'CURRENT_TIME'
  885.             {
  886.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  887.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  888.             }
  889.             break;
  890.         case 'float':
  891.         case 'double':
  892.             if ($field_value != (double)$field_value{
  893.                 return $this->raiseError(MDB2_SCHEMA_ERROR_VALIDATE,
  894.                     '"'.$field_value.'" is not of type "'.$field_def['type'].'"');
  895.             }
  896.             //$field_value = (double)$field_value;
  897.             break;
  898.         }
  899.         return MDB2_OK;
  900.     }
  901. }
  902.  
  903. ?>

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