├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── classes ├── Dataflow.php ├── Dataflow │ ├── Decode.php │ ├── Decode │ │ ├── JSON.php │ │ ├── JSONP.php │ │ ├── PHP.php │ │ ├── XML.php │ │ └── YAML.php │ ├── Encode.php │ └── Encode │ │ ├── JSON.php │ │ ├── JSONP.php │ │ ├── PHP.php │ │ ├── XML.php │ │ └── YAML.php └── Kohana │ ├── Dataflow.php │ └── Dataflow │ ├── Decode.php │ ├── Decode │ ├── JSON.php │ ├── JSONP.php │ ├── PHP.php │ ├── XML.php │ └── YAML.php │ ├── Encode.php │ └── Encode │ ├── JSON.php │ ├── JSONP.php │ ├── PHP.php │ ├── XML.php │ └── YAML.php ├── config └── userguide.php ├── guide └── dataflow │ ├── basics.md │ ├── drivers │ └── xml.md │ ├── index.md │ └── menu.md └── tests └── kohana ├── DataflowTest.php └── dataflow ├── JSONPTest.php ├── JSONTest.php ├── PHPTest.php ├── XMLTest.php └── YAMLTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/yaml"] 2 | path = vendor/yaml 3 | url = git://github.com/fabpot/yaml.git 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.5.0 - 07/23/2013 2 | 3 | - Resolved separate issues with encoding and decoding of XML attributes 4 | - Added unit tests to test against newly resolved issues 5 | - Added documentation on how to encode and decode XML attributes 6 | - Updated copyright years 7 | - All tests pass: "OK (27 tests, 27 assertions)" 8 | 9 | # 0.4.1 - 12/10/2012 10 | 11 | - Resolved class case (correctly renamed class files and directories) 12 | - Updated documentation to reflect new driver case 13 | - All tests pass: "OK (25 tests, 25 assertions)" 14 | 15 | # 0.4.0 - 12/06/2012 16 | 17 | - Renamed `Encode::get_content_type` to `Encode::content_type` 18 | - Removed `Encode::_setup` and `Decode::_setup` due to limited usage, using constructor instead 19 | - Resolved issue with decoding XML attributes 20 | - Upgraded to support Kohana 3.3 21 | - Renamed class files and directories to support PSR-0 22 | - Resolved pass by reference issue (now testing in strict mode) 23 | - Expanded user guide documentation and unit test coverage 24 | - All tests pass: "OK (25 tests, 25 assertions)" 25 | 26 | # 0.3.0 - 04/09/2012 27 | 28 | - Added JSON-P encode and decode support. 29 | - Added "pluralize" option for XML encode. This enables children indexes to be wrapped in a plural key 30 | while children dynamically use singular keys. Example `array('values' => array('a', 'b'))` to 31 | `ab`. This keeps other serialized formats free of 32 | the singular keys when using more than one driver for output. 33 | - All tests pass: "OK (20 tests, 20 assertions)" 34 | 35 | # 0.2.0 - 10/19/2011 36 | 37 | - Added support for XML, YAML and serialized PHP 38 | - Renamed `Dataflow_Input` to `Dataflow_Decode` and `Dataflow_Output` to `Dataflow_Encode` 39 | - Encode and decode abstracts more consistent including expected variable types 40 | - `Dataflow_Encode::render` now accepts `Request` for modifying Content-Type header 41 | - Added `Dataflow::as_array` to return input array 42 | - Refactored unit tests into an abstract for consistent sampling across drivers 43 | 44 | # 0.1.0 - 06/04/2011 45 | 46 | - Initial release of Dataflow with support for JSON 47 | - `Dataflow_Input` abstraction for converting serialized format into an associative array 48 | - `Dataflow_Output` abstraction for converting associative array into serialized format 49 | - `Dataflow` acts as a bridge for handling input and output 50 | - Unit test coverage 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011-2012 by Micheal Morgan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | :warning: **Notice**: The Kohana Framework announced official retirement on 07/01/2017. Therefore, this repository is no longer maintained. 2 | 3 | ---- 4 | 5 | # Dataflow Module 6 | 7 | Simple way of translating to or from XML, YAML, JSON, JSON-P and serialized PHP. Great for general 8 | usage or incorporating into a REST API. 9 | 10 | // Set drivers (each key is config that passes through to its respective library, 11 | // `decode` to `Dataflow_Decode` and `encode` to `Dataflow_Encode`) 12 | $config = array 13 | ( 14 | 'decode' => array('driver' => 'YAML'), 15 | 'encode' => array('driver' => 'XML') 16 | ); 17 | 18 | // Example of converting XML to YAML and outputting results 19 | echo Dataflow::factory($config)->set($xml); 20 | 21 | // Convert any supported format to a standardized array 22 | Dataflow::factory() 23 | ->set($input) 24 | ->as_array(); 25 | 26 | // Decode XML to an associative array 27 | $array = Dataflow_Decode::factory(array('driver' => 'XML')) 28 | ->set($xml) 29 | ->get(); 30 | 31 | // Encode associative array to XML 32 | $xml = Dataflow_Encode::factory(array('driver' => 'XML')) 33 | ->set($array) 34 | ->get(); 35 | 36 | ## Getting Started 37 | 38 | Recommend starting out with Dataflow documentation using the User Guide module. 39 | 40 | ## Learning & References 41 | 42 | - User Guide 43 | - API Browser 44 | - Unit Tests 45 | 46 | ## Version 0.5.0 47 | 48 | This is release version 0.5.0 of [Dataflow](https://github.com/morgan/kohana-dataflow). 49 | -------------------------------------------------------------------------------- /classes/Dataflow.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow extends Kohana_Dataflow {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Decode.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | abstract class Dataflow_Decode extends Kohana_Dataflow_Decode {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Decode/JSON.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Decode_JSON extends Kohana_Dataflow_Decode_JSON {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Decode/JSONP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Decode_JSONP extends Kohana_Dataflow_Decode_JSONP {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Decode/PHP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Decode_PHP extends Kohana_Dataflow_Decode_PHP {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Decode/XML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Decode_XML extends Kohana_Dataflow_Decode_XML {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Decode/YAML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Decode_YAML extends Kohana_Dataflow_Decode_YAML {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Encode.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | abstract class Dataflow_Encode extends Kohana_Dataflow_Encode {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Encode/JSON.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Encode_JSON extends Kohana_Dataflow_Encode_JSON {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Encode/JSONP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2012-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Encode_JSONP extends Kohana_Dataflow_Encode_JSONP {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Encode/PHP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Encode_PHP extends Kohana_Dataflow_Encode_PHP {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Encode/XML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Encode_XML extends Kohana_Dataflow_Encode_XML {} 12 | -------------------------------------------------------------------------------- /classes/Dataflow/Encode/YAML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Dataflow_Encode_YAML extends Kohana_Dataflow_Encode_YAML {} 12 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2011-2013 Micheal Morgan 10 | * @license MIT 11 | */ 12 | class Kohana_Dataflow 13 | { 14 | /** 15 | * Factory pattern 16 | * 17 | * @static 18 | * @access public 19 | * @return Dataflow 20 | */ 21 | public static function factory(array $config = array()) 22 | { 23 | return new Dataflow($config); 24 | } 25 | 26 | /** 27 | * Configuration 28 | * 29 | * @access protected 30 | * @var array 31 | */ 32 | protected $_config = array 33 | ( 34 | 'decode' => array(), 35 | 'encode' => array() 36 | ); 37 | 38 | /** 39 | * Decoded input as array 40 | * 41 | * @access protected 42 | * @var array 43 | */ 44 | protected $_input = array(); 45 | 46 | /** 47 | * Dataflow Output 48 | * 49 | * @access protected 50 | * @var Dataflow_Encode|NULL 51 | */ 52 | protected $_output; 53 | 54 | /** 55 | * Initialize Dataflow 56 | * 57 | * @access public 58 | * @return void 59 | */ 60 | public function __construct(array $config = array()) 61 | { 62 | $this->_config = Arr::merge($config, $this->_config); 63 | } 64 | 65 | /** 66 | * Set input 67 | * 68 | * @access public 69 | * @return $this 70 | */ 71 | public function set($input) 72 | { 73 | if (is_array($input)) 74 | { 75 | $this->_input = $input; 76 | } 77 | else 78 | { 79 | $this->_input = Dataflow_Decode::factory($this->_config['decode']) 80 | ->set($input) 81 | ->get(); 82 | } 83 | 84 | // Reset output due to new input 85 | $this->_output = NULL; 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * Get output 92 | * 93 | * @access public 94 | * @param bool Whether to return encoded string or Dataflow_Encode 95 | * @return mixed string|Dataflow_Encode 96 | */ 97 | public function get($encoded = TRUE) 98 | { 99 | if ($this->_output === NULL) 100 | { 101 | $this->_output = Dataflow_Encode::factory($this->_config['encode'])->set($this->_input); 102 | } 103 | 104 | return ($encoded) ? $this->_output->get() : $this->_output; 105 | } 106 | 107 | /** 108 | * Return array 109 | * 110 | * @access public 111 | * @return array 112 | */ 113 | public function as_array() 114 | { 115 | return $this->_input; 116 | } 117 | 118 | /** 119 | * Magic method for converting object to string 120 | * 121 | * @access public 122 | * @return string 123 | */ 124 | public function __toString() 125 | { 126 | return (string) $this->get(FALSE); 127 | } 128 | 129 | /** 130 | * Render output 131 | * 132 | * @access public 133 | * @param bool 134 | * @param mixed Request|NULL 135 | * @return $this 136 | */ 137 | public function render($headers = TRUE, Request $request = NULL) 138 | { 139 | $this->get(FALSE)->render($headers, $request); 140 | 141 | return $this; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Decode.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | abstract class Kohana_Dataflow_Decode 12 | { 13 | /** 14 | * Default driver 15 | * 16 | * @static 17 | * @access public 18 | * @var string 19 | */ 20 | public static $default = 'JSON'; 21 | 22 | /** 23 | * Factory pattern 24 | * 25 | * @static 26 | * @access public 27 | * @return Dataflow_Input 28 | */ 29 | public static function factory(array $config = array()) 30 | { 31 | $config['driver'] = (isset($config['driver'])) ? $config['driver'] : Dataflow_Decode::$default; 32 | 33 | $class = 'Dataflow_Decode_' . $config['driver']; 34 | 35 | return new $class($config); 36 | } 37 | 38 | /** 39 | * Parsed data 40 | * 41 | * @access protected 42 | * @var array 43 | */ 44 | protected $_decoded = array(); 45 | 46 | /** 47 | * Cache driver type 48 | * 49 | * @access protected 50 | * @var string 51 | */ 52 | protected $_type; 53 | 54 | /** 55 | * Default config 56 | * 57 | * @access protected 58 | * @var array 59 | */ 60 | protected $_config = array(); 61 | 62 | /** 63 | * Initialize 64 | * 65 | * @access public 66 | * @return void 67 | */ 68 | public function __construct(array $config) 69 | { 70 | $this->_config = Arr::merge($this->_config, $config); 71 | 72 | $this->_type = $config['driver']; 73 | } 74 | 75 | /** 76 | * Decode 77 | * 78 | * @access protected 79 | * @return array 80 | */ 81 | abstract protected function _decode($data); 82 | 83 | /** 84 | * Parsed input 85 | * 86 | * @access public 87 | * @return $this 88 | * @throws Kohana_Exception 89 | */ 90 | public function set($data) 91 | { 92 | if ( ! is_array($this->_decoded = $this->_decode($data))) 93 | throw new Kohana_Exception('Expecting `Dataflow_Decode_' . $this->type() . '::_decode` to return an array.'); 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * Abstract getter 100 | * 101 | * @access public 102 | * @return array 103 | */ 104 | public function & get() 105 | { 106 | return $this->_decoded; 107 | } 108 | 109 | /** 110 | * Type 111 | * 112 | * @access public 113 | * @return string 114 | */ 115 | public function type() 116 | { 117 | return $this->_type; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Decode/JSON.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Decode_JSON extends Dataflow_Decode 12 | { 13 | /** 14 | * Decode 15 | * 16 | * @access protected 17 | * @return array 18 | */ 19 | protected function _decode($data) 20 | { 21 | return json_decode($data, TRUE); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Decode/JSONP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Decode_JSONP extends Dataflow_Decode 12 | { 13 | /** 14 | * Decode 15 | * 16 | * @access protected 17 | * @return array 18 | */ 19 | protected function _decode($data) 20 | { 21 | if (FALSE !== $position = strpos($data, '(')) 22 | { 23 | // remove "any_callback_name(" and trim ")" 24 | $data = rtrim(substr($data, ++$position, strlen($data)), ')'); 25 | } 26 | 27 | return json_decode($data, TRUE); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Decode/PHP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Decode_PHP extends Dataflow_Decode 12 | { 13 | /** 14 | * Decode 15 | * 16 | * @access protected 17 | * @return array 18 | */ 19 | protected function _decode($data) 20 | { 21 | return unserialize($data); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Decode/XML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Decode_XML extends Dataflow_Decode 12 | { 13 | /** 14 | * Default config 15 | * 16 | * @access protected 17 | * @var array 18 | */ 19 | protected $_config = array 20 | ( 21 | ':attributes' => ':attributes' 22 | ); 23 | 24 | /** 25 | * Parser 26 | * 27 | * @access protected 28 | * @var NULL|resource 29 | */ 30 | protected $_parser; 31 | 32 | /** 33 | * Decode 34 | * 35 | * @access protected 36 | * @return array 37 | */ 38 | protected function _decode($data) 39 | { 40 | $this->_parser = xml_parser_create(); 41 | 42 | xml_set_object($this->_parser, $this); 43 | xml_set_element_handler($this->_parser, '_open', '_close'); 44 | xml_set_character_data_handler($this->_parser, '_data'); 45 | 46 | xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, FALSE); 47 | 48 | xml_parse($this->_parser, $data); 49 | 50 | if (is_array($this->_decoded)) 51 | return $this->_decoded; 52 | 53 | return array(); 54 | } 55 | 56 | /** 57 | * Handle open 58 | * 59 | * @access protected 60 | * @param resource 61 | * @param string 62 | * @param array 63 | * @return void 64 | */ 65 | protected function _open($parser, $index, $attributes) 66 | { 67 | if (isset($this->_decoded[$index][$this->_config[':attributes']])) 68 | { 69 | $key = 1; 70 | 71 | $this->_decoded[$index] = array($this->_decoded[$index]); 72 | } 73 | else if (isset($this->_decoded[$index])) 74 | { 75 | $key = count($this->_decoded[$index]); 76 | } 77 | 78 | if (isset($key)) 79 | { 80 | $this->_decoded[$index][$key] = array 81 | ( 82 | 'key' => $key, 83 | 'parent' => & $this->_decoded 84 | ); 85 | 86 | $this->_decoded =& $this->_decoded[$index][$key]; 87 | } 88 | else 89 | { 90 | $this->_decoded[$index] = array 91 | ( 92 | 'parent' => & $this->_decoded 93 | ); 94 | 95 | $this->_decoded =& $this->_decoded[$index]; 96 | } 97 | 98 | if ( ! empty($attributes)) 99 | { 100 | $this->_decoded[$this->_config[':attributes']] = $attributes; 101 | } 102 | } 103 | 104 | /** 105 | * Handle close 106 | * 107 | * @access protected 108 | * @param resource 109 | * @param string 110 | * @return void 111 | */ 112 | protected function _close($parser, $index) 113 | { 114 | $pointer =& $this->_decoded; 115 | 116 | if (isset($this->_decoded['key'])) 117 | { 118 | unset($pointer['key']); 119 | } 120 | 121 | $this->_decoded =& $this->_decoded['parent']; 122 | 123 | unset($pointer['parent']); 124 | 125 | if (isset($pointer['data']) AND count($pointer) == 1) 126 | { 127 | $pointer = $pointer['data']; 128 | } 129 | else if (empty($pointer['data']) OR $pointer['data'] == 0) 130 | { 131 | unset($pointer['data']); 132 | } 133 | } 134 | 135 | /** 136 | * Handle data 137 | * 138 | * @access protected 139 | * @param resource 140 | * @param array 141 | * @return void 142 | */ 143 | protected function _data($parser, $data) 144 | { 145 | $this->_decoded['data'] = $data; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Decode/YAML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Decode_YAML extends Dataflow_Decode 12 | { 13 | /** 14 | * Initialize 15 | * 16 | * @access public 17 | * @return void 18 | */ 19 | public function __construct(array $config) 20 | { 21 | parent::__construct($config); 22 | 23 | require_once Kohana::find_file('vendor', 'yaml/lib/sfYaml'); 24 | } 25 | 26 | /** 27 | * Decode 28 | * 29 | * @access protected 30 | * @return array 31 | */ 32 | protected function _decode($data) 33 | { 34 | return sfYaml::load($data); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Encode.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | abstract class Kohana_Dataflow_Encode 12 | { 13 | /** 14 | * Default driver 15 | * 16 | * @static 17 | * @access public 18 | * @var string 19 | */ 20 | public static $default = 'JSON'; 21 | 22 | /** 23 | * Factory pattern 24 | * 25 | * @static 26 | * @access public 27 | * @return Dataflow_Output 28 | */ 29 | public static function factory(array $config = array()) 30 | { 31 | $config['driver'] = (isset($config['driver'])) ? $config['driver'] : Dataflow_Encode::$default; 32 | 33 | $class = 'Dataflow_Encode_' . $config['driver']; 34 | 35 | return new $class($config); 36 | } 37 | 38 | /** 39 | * Data array 40 | * 41 | * @access protected 42 | * @var string 43 | */ 44 | protected $_encoded = ''; 45 | 46 | /** 47 | * Cache driver type 48 | * 49 | * @access protected 50 | * @var string|NULL 51 | */ 52 | protected $_type; 53 | 54 | /** 55 | * Default config 56 | * 57 | * @access protected 58 | * @var array 59 | */ 60 | protected $_config = array(); 61 | 62 | /** 63 | * Initialize 64 | * 65 | * @access public 66 | * @return void 67 | */ 68 | public function __construct(array $config) 69 | { 70 | $this->_config = Arr::merge($this->_config, $config); 71 | 72 | $this->_type = $config['driver']; 73 | } 74 | 75 | /** 76 | * Abstract content type for headers 77 | * 78 | * @access public 79 | * @return string 80 | */ 81 | abstract public function content_type(); 82 | 83 | /** 84 | * Transform array to driver format. Return value. 85 | * 86 | * @access protected 87 | * @param array 88 | * @return string 89 | */ 90 | abstract protected function _encode(array $data); 91 | 92 | /** 93 | * Encode array to string 94 | * 95 | * @access public 96 | * @return array 97 | */ 98 | public function set(array $data) 99 | { 100 | if ( ! is_string($this->_encoded = $this->_encode($data))) 101 | throw new Kohana_Exception('Expecting `Dataflow_Encode_' . $this->type() . '::_encode` to return a string.'); 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Get encoded 108 | * 109 | * @access public 110 | * @return string 111 | */ 112 | public function & get() 113 | { 114 | return $this->_encoded; 115 | } 116 | 117 | /** 118 | * Magic method for converting object to string. Intentionally not passing headers because 119 | * object is casted to a string. 120 | * 121 | * @access public 122 | * @return string 123 | */ 124 | public function __toString() 125 | { 126 | $this->_headers(); 127 | 128 | return $this->get(); 129 | } 130 | 131 | /** 132 | * Render output to screen using proper headers. 133 | * 134 | * @access public 135 | * @param bool Whether or not to handle headers 136 | * @param mixed Request|NULL Request object for modifying headers 137 | * @return $this 138 | */ 139 | public function render($headers = TRUE, Request $request = NULL) 140 | { 141 | if ($headers) 142 | { 143 | $this->_headers($request); 144 | } 145 | 146 | echo $this->get(); 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * Type 153 | * 154 | * @access public 155 | * @return string 156 | */ 157 | public function type() 158 | { 159 | return $this->_type; 160 | } 161 | 162 | /** 163 | * Handle headers 164 | * 165 | * @access public 166 | * @return $this 167 | */ 168 | protected function _headers(Request $request = NULL) 169 | { 170 | $request = ($request) ? $request : Request::current(); 171 | 172 | // Suppress passing of headers when no request - example during CLI for unit testing 173 | if ($request) 174 | { 175 | $request->response()->headers('content-type', $this->get_content_type()); 176 | } 177 | 178 | return $this; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Encode/JSON.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Encode_JSON extends Dataflow_Encode 12 | { 13 | /** 14 | * Get content type 15 | * 16 | * @access public 17 | * @return string 18 | */ 19 | public function content_type() 20 | { 21 | return 'application/json'; 22 | } 23 | 24 | /** 25 | * Encode 26 | * 27 | * @access protected 28 | * @return string 29 | */ 30 | protected function _encode(array $data) 31 | { 32 | // Force return of object if array empty 33 | if (empty($data)) 34 | return '{}'; 35 | else 36 | return json_encode($data); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Encode/JSONP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2012-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Encode_JSONP extends Dataflow_Encode 12 | { 13 | /** 14 | * Default config 15 | * 16 | * @access protected 17 | * @var array 18 | */ 19 | protected $_config = array 20 | ( 21 | 'callback' => 'callback' 22 | ); 23 | 24 | /** 25 | * Get content type 26 | * 27 | * @access public 28 | * @return string 29 | */ 30 | public function content_type() 31 | { 32 | return 'application/json-p'; 33 | } 34 | 35 | /** 36 | * Encode 37 | * 38 | * @access protected 39 | * @return string 40 | */ 41 | protected function _encode(array $data) 42 | { 43 | // Force return of object if array empty 44 | $data = empty($data) ? '{}' : json_encode($data); 45 | 46 | return $this->_config['callback'] . '(' . $data . ')'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Encode/PHP.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Encode_PHP extends Dataflow_Encode 12 | { 13 | /** 14 | * Get content type 15 | * 16 | * @access public 17 | * @return string 18 | */ 19 | public function content_type() 20 | { 21 | return 'application/php'; 22 | } 23 | 24 | /** 25 | * Encode 26 | * 27 | * @access protected 28 | * @return string 29 | */ 30 | protected function _encode(array $data) 31 | { 32 | return serialize($data); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Encode/XML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Encode_XML extends Dataflow_Encode 12 | { 13 | /** 14 | * Default config 15 | * 16 | * @access protected 17 | * @var array 18 | */ 19 | protected $_config = array 20 | ( 21 | ':content' => ':content', 22 | ':attributes' => ':attributes', 23 | ':xml' => ':xml', 24 | 'pluralize' => FALSE 25 | ); 26 | 27 | /** 28 | * XML Writer 29 | * 30 | * @access protected 31 | * @var NULL|XMLWriter 32 | */ 33 | protected $_writer; 34 | 35 | /** 36 | * Get content type 37 | * 38 | * @access public 39 | * @return string 40 | */ 41 | public function content_type() 42 | { 43 | return 'application/xml'; 44 | } 45 | 46 | /** 47 | * Encode 48 | * 49 | * @access protected 50 | * @return string 51 | */ 52 | protected function _encode(array $data) 53 | { 54 | $this->_writer = new XMLWriter; 55 | 56 | $this->_writer->openMemory(); 57 | $this->_writer->setIndent(TRUE); 58 | $this->_writer->setIndentString(' '); 59 | $this->_writer->startDocument('1.0', 'UTF-8'); 60 | 61 | $keys = array_keys($data); 62 | 63 | if ( ! empty($data) AND $key = array_shift($keys)) 64 | { 65 | $this->_writer->startElement($key); 66 | 67 | $this->_attributes($data[$key]); 68 | 69 | $data =& $data[$key]; 70 | } 71 | 72 | $this->_process($data); 73 | 74 | $this->_writer->endElement(); 75 | $this->_writer->endDocument(); 76 | 77 | return $this->_writer->outputMemory(); 78 | } 79 | 80 | /** 81 | * Process array 82 | * 83 | * @access protected 84 | * @param array 85 | * @param boolean 86 | * @return void 87 | */ 88 | protected function _process($data) 89 | { 90 | if (is_array($data) AND ! empty($data)) 91 | { 92 | foreach ($data as $index => $element) 93 | { 94 | if (is_array($element)) 95 | { 96 | if ( ! $this->_indexed($index, $element)) 97 | { 98 | $this->_writer->startElement($index); 99 | 100 | $this->_attributes($element); 101 | $this->_content($element); 102 | 103 | if ( ! empty($element)) 104 | { 105 | $this->_process($element); 106 | } 107 | 108 | $this->_writer->endElement(); 109 | } 110 | } 111 | else 112 | { 113 | $this->_writer->startElement($index); 114 | $this->_writer->text($element); 115 | $this->_writer->endElement(); 116 | } 117 | } 118 | } 119 | } 120 | 121 | /** 122 | * Handle nested 123 | * 124 | * @access protected 125 | * @param string 126 | * @param array 127 | * @return boolean 128 | */ 129 | protected function _indexed($index, $element) 130 | { 131 | if (is_array($element) AND isset($element[0])) 132 | { 133 | // If "pluralize" enabled, wrap children using plural index and set children to use 134 | // singular index 135 | if ($this->_config['pluralize']) 136 | { 137 | $this->_writer->startElement($index); 138 | 139 | $index = Inflector::singular($index); 140 | } 141 | 142 | foreach ($element as $key => $name) 143 | { 144 | $this->_writer->startElement($index); 145 | 146 | $this->_attributes($name); 147 | $this->_content($name); 148 | 149 | if ( ! empty($name)) 150 | { 151 | $this->_process($name); 152 | } 153 | 154 | $this->_writer->endElement(); 155 | } 156 | 157 | if ($this->_config['pluralize']) 158 | { 159 | $this->_writer->endElement(); 160 | } 161 | 162 | return TRUE; 163 | } 164 | 165 | return FALSE; 166 | } 167 | 168 | /** 169 | * Handle content 170 | * 171 | * @access protected 172 | * @param mixed 173 | * @return boolean 174 | */ 175 | protected function _content($element) 176 | { 177 | if (is_array($element)) 178 | { 179 | if (is_array($element) AND isset($element[$this->_config[':content']])) 180 | { 181 | $this->_writer->text($element[$this->_config[':content']]); 182 | 183 | unset($element[$this->_config[':content']]); 184 | 185 | return TRUE; 186 | } 187 | else if (is_array($element) AND isset($element[$this->_config[':xml']])) 188 | { 189 | $this->_writer->writeRaw($element[$this->_config[':xml']]); 190 | 191 | unset($element[$this->_config[':xml']]); 192 | 193 | return TRUE; 194 | } 195 | } 196 | else if ( ! is_array($element)) 197 | { 198 | $this->_writer->text($element); 199 | 200 | unset($element); 201 | 202 | return TRUE; 203 | } 204 | 205 | return FALSE; 206 | } 207 | 208 | /** 209 | * Handle attributes 210 | * 211 | * @access protected 212 | * @param array 213 | * @return boolean 214 | */ 215 | protected function _attributes( & $element) 216 | { 217 | if (is_array($element) AND isset($element[$this->_config[':attributes']])) 218 | { 219 | foreach ($element[$this->_config[':attributes']] as $key => $value) 220 | { 221 | $this->_writer->writeAttribute($key, $value); 222 | } 223 | 224 | unset($element[$this->_config[':attributes']]); 225 | 226 | return TRUE; 227 | } 228 | 229 | return FALSE; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /classes/Kohana/Dataflow/Encode/YAML.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright (c) 2011-2013 Micheal Morgan 9 | * @license MIT 10 | */ 11 | class Kohana_Dataflow_Encode_YAML extends Dataflow_Encode 12 | { 13 | /** 14 | * Initialize 15 | * 16 | * @access public 17 | * @return void 18 | */ 19 | public function __construct(array $config) 20 | { 21 | parent::__construct($config); 22 | 23 | require_once Kohana::find_file('vendor', 'yaml/lib/sfYaml'); 24 | } 25 | 26 | /** 27 | * Get content type 28 | * 29 | * @access public 30 | * @return string 31 | */ 32 | public function content_type() 33 | { 34 | return 'application/yaml'; 35 | } 36 | 37 | /** 38 | * Encode 39 | * 40 | * @access protected 41 | * @return string 42 | */ 43 | protected function _encode(array $data) 44 | { 45 | return sfYaml::dump($data); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/userguide.php: -------------------------------------------------------------------------------- 1 | array 5 | ( 6 | 'dataflow' => array 7 | ( 8 | 'enabled' => TRUE, 9 | 'name' => 'Dataflow', 10 | 'description' => 'Translate data from one encoded format to another.', 11 | 'copyright' => '© 2011-2013 Micheal Morgan', 12 | ) 13 | ) 14 | ); -------------------------------------------------------------------------------- /guide/dataflow/basics.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Basic Usage 4 | 5 | $dataflow = Dataflow::factory(); 6 | 7 | // Set basic JSON 8 | $dataflow->set('{}'); 9 | 10 | // Get input as array 11 | var_dump($dataflow->as_array()); 12 | 13 | // Get input as another format 14 | var_dump($dataflow->get()); 15 | 16 | ## Setting drivers 17 | 18 | $config = array 19 | ( 20 | 'decode' => array('driver' => 'YAML'), 21 | 'encode' => array('driver' => 'XML') 22 | ); 23 | 24 | $dataflow = Dataflow::factory($config); 25 | 26 | ## Rendering output 27 | 28 | Simply echo contents: 29 | 30 | echo $dataflow; 31 | 32 | Render passing headers based on driver. Uses default Request object: 33 | 34 | $dataflow->render(); 35 | 36 | Render without passing headers: 37 | 38 | $dataflow->render(FALSE); 39 | 40 | Apply headers to custom Request object: 41 | 42 | $dataflow->render(TRUE, $request); 43 | -------------------------------------------------------------------------------- /guide/dataflow/drivers/xml.md: -------------------------------------------------------------------------------- 1 | # XML Driver 2 | 3 | ## Encoding Attributes 4 | 5 | Encoding attributes requires using the `:attributes` key. 6 | 7 | // Setup XML encode driver 8 | $encode = Dataflow_Encode::factory(array('driver' => 'XML')); 9 | 10 | $decoded = array 11 | ( 12 | 'parent' => array 13 | ( 14 | 'child' => array 15 | ( 16 | ':attributes' => array('key1' => 'value1', 'key2' => 'value2') 17 | ) 18 | ) 19 | ); 20 | 21 | // Set decoded array 22 | $encode->set($decoded); 23 | 24 | // Output result 25 | echo Debug::vars($encode->get()); 26 | 27 | // Debug output 28 | string(96) " 29 | 30 | 31 | 32 | " 33 | 34 | ## Decoding Attributes 35 | 36 | Decoding attributes will put the attributes in the `:attributes` key. 37 | 38 | // Setup XML decode driver 39 | $decode = Dataflow_Decode::factory(array('driver' => 'XML')); 40 | 41 | $encoded = ' 42 | 43 | 44 | '; 45 | 46 | // Set encoded string 47 | $decode->set($encoded); 48 | 49 | // Output result 50 | echo Debug::vars($decode->get()); 51 | 52 | // Debug output 53 | array(1) ( 54 | "parent" => array(1) ( 55 | "child" => array(1) ( 56 | ":attributes" => array(2) ( 57 | "key1" => string(6) "value1" 58 | "key2" => string(6) "value2" 59 | ) 60 | ) 61 | ) 62 | ) 63 | -------------------------------------------------------------------------------- /guide/dataflow/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | Dataflow is built to decode data from one type and encode it to another. A byproduct of this 4 | allows for the decoding of data into a standardized array. [Click here to get started](basics). 5 | 6 | # Additional Resources 7 | 8 | - API Browser 9 | - Unit Tests 10 | -------------------------------------------------------------------------------- /guide/dataflow/menu.md: -------------------------------------------------------------------------------- 1 | ## [Dataflow]() 2 | - [The Basics](basics) 3 | - [XML Attributes](drivers/xml) 4 | -------------------------------------------------------------------------------- /tests/kohana/DataflowTest.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) 2011-2013 Micheal Morgan 12 | * @license MIT 13 | */ 14 | abstract class Kohana_DataflowTest extends Unittest_TestCase 15 | { 16 | /** 17 | * Factory to return Dataflow object configured for driver. 18 | * 19 | * @access public 20 | * @return Dataflow 21 | */ 22 | abstract public function factory(); 23 | 24 | /** 25 | * Sample provider 26 | * 27 | * @access public 28 | * @return array 29 | */ 30 | public function provider_samples() 31 | { 32 | return array 33 | ( 34 | array 35 | ( 36 | // test empty array 37 | array() 38 | ), 39 | array 40 | ( 41 | // test indexed array with a variety of variable types 42 | array 43 | ( 44 | 'samples' => array 45 | ( 46 | 'sample' => array('string(value)', 1) 47 | ) 48 | ) 49 | ), 50 | array 51 | ( 52 | // test associative array 53 | array 54 | ( 55 | 'key1' => array 56 | ( 57 | 'key2_1' => 'value2_1', 58 | 'key2_2' => array 59 | ( 60 | 'key3_1' => 'value_3_1', 61 | 'key3_2' => 'value_3_2' 62 | ) 63 | ) 64 | ) 65 | ), 66 | array 67 | ( 68 | // test attribute handling 69 | array 70 | ( 71 | 'parent' => array 72 | ( 73 | ':attributes' => array('key1' => 'value1'), 74 | 'child' => array 75 | ( 76 | 'value1', 77 | 'value2' 78 | ) 79 | ) 80 | ) 81 | ), 82 | array 83 | ( 84 | // Test nesting with attributes 85 | 'parent' => array 86 | ( 87 | 'child' => array 88 | ( 89 | ':attributes' => array('key1' => 'value1', 'key2' => 'value2'), 90 | 'child_child' => array 91 | ( 92 | 'key1' => 'value2' 93 | ) 94 | ) 95 | ) 96 | ) 97 | ); 98 | } 99 | 100 | /** 101 | * Test by encoding sample and comparing original array with decoded 102 | * 103 | * @covers Dataflow::factory 104 | * @covers Dataflow::set 105 | * @covers Dataflow::get 106 | * @covers Dataflow::as_array 107 | * @covers Dataflow_Decode::factory 108 | * @covers Dataflow_Decode::get 109 | * @covers Dataflow_Decode::set 110 | * @covers Dataflow_Decode::_decode 111 | * @covers Dataflow_Encode::factory 112 | * @covers Dataflow_Encode::get 113 | * @covers Dataflow_Encode::set 114 | * @covers Dataflow_Encode::_encode 115 | * @dataProvider provider_samples 116 | * @access public 117 | * @param array 118 | * @return void 119 | */ 120 | public function test_samples(array $sample) 121 | { 122 | $dataflow = $this->factory(); 123 | 124 | // Set sample input 125 | $dataflow->set($sample); 126 | 127 | // Get encoded 128 | $encoded = $dataflow->get(); 129 | 130 | // Decode encoded 131 | $dataflow->set($encoded); 132 | 133 | // Test decoded matches original sample 134 | $this->assertEquals($sample, $dataflow->as_array()); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /tests/kohana/dataflow/JSONPTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2011-2013 Micheal Morgan 10 | * @license MIT 11 | */ 12 | class Kohana_Dataflow_JSONPTest extends Kohana_DataflowTest 13 | { 14 | /** 15 | * Factory pattern 16 | * 17 | * @access public 18 | * @return Dataflow 19 | */ 20 | public function factory() 21 | { 22 | return Dataflow::factory(array('encode' => array('driver' => 'JSONP'), 'decode' => array('driver' => 'JSONP'))); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/kohana/dataflow/JSONTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2011-2013 Micheal Morgan 10 | * @license MIT 11 | */ 12 | class Kohana_Dataflow_JSONTest extends Kohana_DataflowTest 13 | { 14 | /** 15 | * Factory pattern 16 | * 17 | * @access public 18 | * @return Dataflow 19 | */ 20 | public function factory() 21 | { 22 | return Dataflow::factory(array('encode' => array('driver' => 'JSON'), 'decode' => array('driver' => 'JSON'))); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/kohana/dataflow/PHPTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2011-2013 Micheal Morgan 10 | * @license MIT 11 | */ 12 | class Kohana_Dataflow_PHPTest extends Kohana_DataflowTest 13 | { 14 | /** 15 | * Factory pattern 16 | * 17 | * @access public 18 | * @return Dataflow 19 | */ 20 | public function factory() 21 | { 22 | return Dataflow::factory(array('encode' => array('driver' => 'PHP'), 'decode' => array('driver' => 'PHP'))); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/kohana/dataflow/XMLTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2011-2013 Micheal Morgan 10 | * @license MIT 11 | */ 12 | class Kohana_Dataflow_XMLTest extends Kohana_DataflowTest 13 | { 14 | /** 15 | * Factory pattern 16 | * 17 | * @access public 18 | * @return Dataflow 19 | */ 20 | public function factory() 21 | { 22 | return Dataflow::factory(array('encode' => array('driver' => 'XML'), 'decode' => array('driver' => 'XML'))); 23 | } 24 | 25 | /** 26 | * Sample provider 27 | * 28 | * @access public 29 | * @return array 30 | */ 31 | public function provider_xml() 32 | { 33 | return array 34 | ( 35 | array 36 | ( 37 | array 38 | ( 39 | 'parent' => array 40 | ( 41 | 'child' => array 42 | ( 43 | ':attributes' => array('key1' => 'value1', 'key2' => 'value2') 44 | ) 45 | ) 46 | ), 47 | ' 48 | 49 | 50 | 51 | ' 52 | ) 53 | ); 54 | } 55 | 56 | /** 57 | * Test XML encoding 58 | * 59 | * @covers Dataflow_Encode::factory 60 | * @covers Dataflow_Encode::get 61 | * @covers Dataflow_Encode::set 62 | * @covers Dataflow_Encode::_encode 63 | * @dataProvider provider_xml 64 | * @access public 65 | * @param array 66 | * @return void 67 | */ 68 | public function test_xml_encode($decoded, $encoded) 69 | { 70 | // Setup XML encode driver 71 | $encode = Dataflow_Encode::factory(array('driver' => 'XML')); 72 | 73 | // Set decoded array 74 | $encode->set($decoded); 75 | 76 | // Test newly encoded matches decoded 77 | $this->assertEquals($encode->get(), $encoded); 78 | } 79 | 80 | /** 81 | * Test XML decoding 82 | * 83 | * @covers Dataflow_Encode::factory 84 | * @covers Dataflow_Encode::get 85 | * @covers Dataflow_Encode::set 86 | * @covers Dataflow_Encode::_encode 87 | * @dataProvider provider_xml 88 | * @access public 89 | * @param array 90 | * @return void 91 | */ 92 | public function test_xml_decode($decoded, $encoded) 93 | { 94 | // Setup XML decode driver 95 | $decode = Dataflow_Decode::factory(array('driver' => 'XML')); 96 | 97 | // Set decoded array 98 | $decode->set($encoded); 99 | 100 | // Test newly decoded matches decoded 101 | $this->assertEquals($decode->get(), $decoded); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tests/kohana/dataflow/YAMLTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) 2011-2013 Micheal Morgan 10 | * @license MIT 11 | */ 12 | class Kohana_Dataflow_YAMLTest extends Kohana_DataflowTest 13 | { 14 | /** 15 | * Factory pattern 16 | * 17 | * @access public 18 | * @return Dataflow 19 | */ 20 | public function factory() 21 | { 22 | return Dataflow::factory(array('encode' => array('driver' => 'YAML'), 'decode' => array('driver' => 'YAML'))); 23 | } 24 | } --------------------------------------------------------------------------------