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: