      1: <?php
      2: /**
      3:  * DataTables PHP libraries.
      4:  *
      5:  * PHP libraries for DataTables and DataTables Editor, utilising PHP 5.3+.
      6:  *
      7:  *  @author    SpryMedia
      8:  *  @copyright 2012 SpryMedia ( http://sprymedia.co.uk )
      9:  *  @license   http://editor.datatables.net/license DataTables Editor
     10:  *  @link      http://editor.datatables.net
     11:  */
     12:
     13: namespace DataTables;
     14: if (!defined('DATATABLES')) exit();
     15:
     16:
     17: /**
     18:  * Base class for DataTables classes.
     19:  */
     20: class Ext {
     21:     /**
     22:      * Static method to instantiate a new instance of a class.
     23:      *
     24:      * A factory method that will create a new instance of the class
     25:      * that has extended 'Ext'. This allows classes to be instantiated
     26:      * and then chained - which otherwise isn't available until PHP 5.4.
     27:      * If using PHP 5.4 or later, simply create a 'new' instance of the
     28:      * target class and chain methods as normal.
     29:      *  @return \DataTables\Editor|\DataTables\Editor\Field|\DataTables\Editor\Join|\DataTables\Editor\Upload Instantiated class
     30:      *  @static
     31:      */
     32:     public static function instantiate ()
     33:     {
     34:         $rc = new \ReflectionClass( get_called_class() );
     35:         $args = func_get_args();
     36:
     37:         return count( $args ) === 0 ?
     38:             $rc->newInstance() :
     39:             $rc->newInstanceArgs( $args );
     40:     }
     41:
     42:     /**
     43:      * Static method to instantiate a new instance of a class (shorthand of
     44:      * 'instantiate').
     45:      *
     46:      * This method performs exactly the same actions as the 'instantiate'
     47:      * static method, but is simply shorter and easier to type!
     48:      *  @return \DataTables\Editor|\DataTables\Editor\Field|\DataTables\Editor\Join|\DataTables\Editor\Upload class
     49:      *  @static
     50:      */
     51:     public static function inst ()
     52:     {
     53:         $rc = new \ReflectionClass( get_called_class() );
     54:         $args = func_get_args();
     55:
     56:         return count( $args ) === 0 ?
     57:             $rc->newInstance() :
     58:             $rc->newInstanceArgs( $args );
     59:     }
     60:
     61:     /**
     62:      * Common getter / setter function for DataTables classes.
     63:      *
     64:      * This getter / setter method makes building getter / setting methods
     65:      * easier, by abstracting everything to a single function call.
     66:      *  @param mixed &$prop The property to set
     67:      *  @param mixed $val The value to set - if given as null, then we assume
     68:      *    that the function is being used as a getter.
     69:      *  @param boolean $array Treat the target property as an array or not
     70:      *    (default false). If used as an array, then values passed in are added
     71:      *    to the $prop array.
     72:      *  @return self|mixed Class instance if setting (allowing chaining), or
     73:      *    the value requested if getting.
     74:      */
     75:     protected function _getSet( &$prop, $val, $array=false )
     76:     {
     77:         // Get
     78:         if ( $val === null ) {
     79:             return $prop;
     80:         }
     81:
     82:         // Set
     83:         if ( $array ) {
     84:             // Property is an array, merge or add to array
     85:             is_array( $val ) ?
     86:                 $prop = array_merge( $prop, $val ) :
     87:                 $prop[] = $val;
     88:         }
     89:         else {
     90:             // Property is just a value
     91:             $prop = $val;
     92:         }
     93:
     94:         return $this;
     95:     }
     96:
     97:     /**
     98:      * Determine if a property is available in a data set (allowing `null` to be
     99:      * a valid value)
    100:      * @param  string $name  Javascript dotted object name to write to
    101:      * @param  array  $data  Data source array to read from
    102:      * @return boolean       true if present, false otherwise
    103:      * @private
    104:      */
    105:     protected function _propExists ( $name, $data )
    106:     {
    107:         if ( strpos($name, '.') === false ) {
    108:             return isset( $data[ $name ] );
    109:         }
    110:
    111:         $names = explode( '.', $name );
    112:         $inner = $data;
    113:
    114:         for ( $i=0 ; $i<count($names)-1 ; $i++ ) {
    115:             if ( ! isset( $inner[ $names[$i] ] ) ) {
    116:                 return false;
    117:             }
    118:
    119:             $inner = $inner[ $names[$i] ];
    120:         }
    121:
    122:         if ( isset( $names[count($names)-1] ) ) {
    123:             $idx = $names[count($names)-1];
    124:
    125:             return isset( $inner[ $idx ] );
    126:         }
    127:
    128:         return false;
    129:     }
    130:
    131:     /**
    132:      * Read a value from a data structure, using Javascript dotted object
    133:      * notation. This is the inverse of the `_writeProp` method and provides
    134:      * the same support, matching DataTables' ability to read nested JSON
    135:      * data objects.
    136:      *
    137:      * @param  string $name  Javascript dotted object name to write to
    138:      * @param  array  $data  Data source array to read from
    139:      * @return mixed         The read value, or null if no value found.
    140:      * @private
    141:      */
    142:     protected function _readProp ( $name, $data )
    143:     {
    144:         if ( strpos($name, '.') === false ) {
    145:             return isset( $data[ $name ] ) ?
    146:                 $data[ $name ] :
    147:                 null;
    148:         }
    149:
    150:         $names = explode( '.', $name );
    151:         $inner = $data;
    152:
    153:         for ( $i=0 ; $i<count($names)-1 ; $i++ ) {
    154:             if ( ! isset( $inner[ $names[$i] ] ) ) {
    155:                 return null;
    156:             }
    157:
    158:             $inner = $inner[ $names[$i] ];
    159:         }
    160:
    161:         if ( isset( $names[count($names)-1] ) ) {
    162:             $idx = $names[count($names)-1];
    163:
    164:             return isset( $inner[ $idx ] ) ?
    165:                 $inner[ $idx ] :
    166:                 null;
    167:         }
    168:
    169:         return null;
    170:     }
    171:
    172:     /**
    173:      * Write the field's value to an array structure, using Javascript dotted
    174:      * object notation to indicate JSON data structure. For example `name.first`
    175:      * gives the data structure: `name: { first: ... }`. This matches DataTables
    176:      * own ability to do this on the client-side, although this doesn't
    177:      * implement implement quite such a complex structure (no array / function
    178:      * support).
    179:      *
    180:      * @param  array  &$out   Array to write the data to
    181:      * @param  string  $name  Javascript dotted object name to write to
    182:      * @param  mixed   $value Value to write
    183:      * @throws \Exception Information about duplicate properties
    184:      * @private
    185:      */
    186:     protected function _writeProp( &$out, $name, $value )
    187:     {
    188:         if ( strpos($name, '.') === false ) {
    189:             $out[ $name ] = $value;
    190:             return;
    191:         }
    192:
    193:         $names = explode( '.', $name );
    194:         $inner = &$out;
    195:         for ( $i=0 ; $i<count($names)-1 ; $i++ ) {
    196:             $loopName = $names[$i];
    197:
    198:             if ( ! isset( $inner[ $loopName ] ) ) {
    199:                 $inner[ $loopName ] = array();
    200:             }
    201:             else if ( ! is_array( $inner[ $loopName ] ) ) {
    202:                 throw new \Exception(
    203:                     'A property with the name `'.$name.'` already exists. This '.
    204:                     'can occur if you have properties which share a prefix - '.
    205:                     'for example `name` and `name.first`.'
    206:                 );
    207:             }
    208:
    209:             $inner = &$inner[ $loopName ];
    210:         }
    211:
    212:         if ( isset( $inner[ $names[count($names)-1] ] ) ) {
    213:             throw new \Exception(
    214:                 'Duplicate field detected - a field with the name `'.$name.'` '.
    215:                 'already exists.'
    216:             );
    217:         }
    218:
    219:         $inner[ $names[count($names)-1] ] = $value;
    220:     }
    221: }
    222:
    223: