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

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