Author: xavier Date: 2010-05-14 17:30:15 +0200 (Fri, 14 May 2010) New Revision: 29469
Added: plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/ plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializer.class.php plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerJson.class.php plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerXml.class.php Removed: plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/sfRestInflector.class.php Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/README plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/view.yml plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/template/templates/indexSuccess.php plugins/sfDoctrineRestGeneratorPlugin/trunk/package.xml Log: [wiki:sfDoctrineRestGeneratorPlugin]: Added a JSON serializer, and fixed a few typos in the documentation Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/README =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/README 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/README 2010-05-14 15:30:15 UTC (rev 29469) @@ -14,6 +14,7 @@ * ability to limit the number of results, with/out pagination * support for constraints unions (ie., http://api.example.org/city?city_id=12,13,14) * abstract and replaceable objects serialization + * serialization as XML or JSON feeds ## How to installed @@ -118,6 +119,7 @@ default: # fields: # list here the fields. # created_at: { date_format: 'Y-m-d\TH:i:s', tag_name: 'created' } # for instance + # formats_enabled: [ xml, json ] # enabled formats # separator: ',' # separator used for multiple filters get: # display: [] # list here fields to render in the response @@ -155,9 +157,26 @@ * `tag_name`: the tag name to use for displaying this field. For instance, you might want to associate the title of the post to the key "post_title", and not "title". +#### formats_enabled + +This contains the list of the formats allowed in the communication with the +API. The default allowed formats are json and XML, XML being the default +format. + +This means that you can call a resource at the following URIs: + + * http://api.example.com/post will return a XML formatted list of the posts, + * http://api.example.com/post.xml will return a XML formatted list of the posts, + * http://api.example.com/post.json will return a JSON formatted list of the posts. + +Would you want to add a new serialization format, you should add this format +in the generator.yml, and create a serializer. See examples in the +`lib/serializer` directory of the plugin. + + #### separator -The separator to use in url when passing objects primary keys. The genertaed +The separator to use in url when passing objects primary keys. The generated module allows to require several ressources identified by their ids: http://api.example.com/post/?id=12,17,19 @@ -166,11 +185,13 @@ The `get` option lists several options specific to the "get" operation: + #### display -The `display` option contains the list of the fields to output in the XML -feed. For example with the previously defines "Post" model, you can choose to -only display the title and the author's id by changing this parameter: +The `display` option contains the list of the fields to output in the XML or +JSON feed. For example with the previously defines "Post" model, you can +choose to only display the title and the author's id by changing this +parameter: config: get: @@ -215,9 +236,9 @@ #### global_additional_fields -In some case, you might want to embed some additionnal fields in he XML -response. For instance, you might want to include the total number of posts, -an average price, etc. +In some case, you might want to embed some additionnal fields in the XML or +JSON response. For instance, you might want to include the total number of +posts, an average price, etc. The `global_additional_fields` is helpful in such a situation. It contains an array of the fields that you want to add and, for each field, the generator @@ -349,26 +370,38 @@ ## Serialization -The response to a get request is formatted as a XML feed. The serializer -generates a valid feed, enclosing the content of a field in CDATA sections if -necessary. +The response to a get request is formatted as a XML feed or a JSON array. The +XML serializer generates a valid feed, enclosing the content of a field in +CDATA sections if necessary. +The serialization is done directly in the action, not in the template, in +order to improve the performance when output escaping is enabled. + + ## Whishlist - * a JSON serializer. Currently, the plugin only allows to serialize the resultsets as a XML field (see the chapter "Serialization"). Mobile clients, which require the most compact possible streams, would take benefit from a JSON or even a BSON serialization. + * more serializers (BSON for example). Currently, the plugin only allows to serialize the resultsets as a XML or JSON feeds (see the chapter "Serialization"). Mobile clients, which require the most compact possible streams, would take benefit from a JSON or even a BSON serialization. * all the possible feedback! + ## Contribute to the plugin, ask for help Please ask for help on how to use the plugin on Symfony's users mailing list. You can also send me a mail directly : [email protected]. + ## License and credits This plugin has been developed by [Xavier Lacot](http://lacot.org/) and is licensed under the MIT license. + ## Changelog +### version 0.9 - 2010-05-14 + +Added a json serializer. + + ### version 0.8 - 2010-05-09 Initial public release. Features REST module generation with validation and a Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -7,6 +7,14 @@ { $this->forward404Unless($request->isMethod(sfRequest::GET)); $params = $request->getParameterHolder()->getAll(); + $format = $params['sf_format']; + $request->setRequestFormat('html'); + + if (!in_array($format, <?php var_export($this->configuration->getValue('default.formats_enabled', array('json', 'xml'))) ?>)) + { + $format = 'xml'; + } + unset($params['sf_format']); unset($params['module']); unset($params['action']); @@ -99,6 +107,8 @@ } <?php endif; ?> - $this->xml = sfRestInflector::arrayToXml($this->objects, $this->model); + $serializer = sfResourceSerializer::getInstance($format); + $this->getResponse()->setContentType($serializer->getContentType()); + $this->output = $serializer->serialize($this->objects, $this->model); unset($this->objects); } Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -1,17 +1,31 @@ - protected function parsePayload($xml, $force = false) + protected function parsePayload($payload, $force = false) { if ($force || !isset($this->_payload_array)) { - $dom = @simplexml_load_string($xml); + $format = $this->getRequest()->getParameter('sf_format); - if (!$dom) + if (!in_array($format, <?php var_export($this->configuration->getValue('default.formats_enabled', array('json', 'xml'))) ?>)) + { + $format = 'xml'; + } + + if ('xml' == $format) + { + $payload_array = @simplexml_load_string($payload); + } + elseif ('json' == $format) + { + $payload_array = json_decode($payload, true); + } + + if (!isset($payload_array) || !$payload_array) { throw new sfException('Could not load payload, obviously not a valid XML!'); } $this->_payload_array = array(); - foreach ($dom as $name => $value) + foreach ($payload_array as $name => $value) { $name = sfInflector::underscore($name); $this->_payload_array[$name] = trim(rtrim((string)$value)); Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml 2010-05-14 15:30:15 UTC (rev 29469) @@ -7,6 +7,7 @@ default: # fields: # list here the fields. # created_at: { date_format: 'Y-m-d\TH:i:s', tag_name: 'created' } # for instance +# formats_enabled: [ xml, json ] # enabled formats # separator: ',' # separator used for multiple filters get: # display: [] # list here fields to render in the response Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/view.yml =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/view.yml 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/view.yml 2010-05-14 15:30:15 UTC (rev 29469) @@ -1,4 +1,2 @@ all: - http_metas: - content-type: text/xml has_layout: false \ No newline at end of file Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/template/templates/indexSuccess.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/template/templates/indexSuccess.php 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/template/templates/indexSuccess.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -1 +1 @@ -[?php echo $sf_data->getRaw('xml'); \ No newline at end of file +[?php echo $sf_data->getRaw('output'); \ No newline at end of file Added: plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializer.class.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializer.class.php (rev 0) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializer.class.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -0,0 +1,20 @@ +<?php + +abstract class sfResourceSerializer +{ + abstract public function getContentType(); + + public static function getInstance($format = 'xml') + { + $classname = sprintf('sfResourceSerializer%s', ucfirst($format)); + + if (!class_exists($classname)) + { + throw new sfException(sprintf('Could not find seriaizer "%s"', $classname)); + } + + return new $classname; + } + + abstract public function serialize($array, $rootNodeName = 'data'); +} \ No newline at end of file Added: plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerJson.class.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerJson.class.php (rev 0) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerJson.class.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -0,0 +1,14 @@ +<?php + +class sfResourceSerializerJson extends sfResourceSerializer +{ + public function getContentType() + { + return 'application/json'; + } + + public function serialize($array, $rootNodeName = 'data') + { + return json_encode($array); + } +} \ No newline at end of file Added: plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerXml.class.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerXml.class.php (rev 0) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/serializer/sfResourceSerializerXml.class.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -0,0 +1,71 @@ +<?php + +class sfResourceSerializerXml extends sfResourceSerializer +{ + public function getContentType() + { + return 'application/xml'; + } + + public function serialize($array, $rootNodeName = 'data') + { + return $this->arrayToXml($array, $rootNodeName, 0); + } + + public function arrayToXml($array, $rootNodeName = 'data', $level = 0) + { + $xml = ''; + + if (0 == $level) + { + $xml .= '<?xml version="1.0" encoding="utf-8"?><'.ucfirst(sfInflector::camelize($rootNodeName)).'s>'; + } + + foreach ($array as $key => $value) + { + $key = ucfirst(sfInflector::camelize($key)); + + if (is_numeric($key)) + { + $key = ucfirst(sfInflector::camelize($rootNodeName)); + } + + if (is_array($value)) + { + $real_key = $key; + + if (!count($value) || isset($value[0])) + { + $real_key .= 's'; + } + + $xml .= '<'.$real_key.'>'; + $xml .= $this->arrayToXml($value, $key, $level + 1); + $xml .= '</'.$real_key.'>'; + } + else + { + $trimed_value = ($value !== false) ? trim($value) : '0'; + + if ($trimed_value !== '') + { + if (htmlspecialchars($trimed_value) != $trimed_value) + { + $xml .= '<'.$key.'><![CDATA['.$trimed_value.']]></'.$key.'>'; + } + else + { + $xml .= '<'.$key.'>'.$trimed_value.'</'.$key.'>'; + } + } + } + } + + if (0 == $level) + { + $xml .= '</'.ucfirst(sfInflector::camelize($rootNodeName)).'s>'; + } + + return $xml; + } +} \ No newline at end of file Deleted: plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/sfRestInflector.class.php =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/sfRestInflector.class.php 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/sfRestInflector.class.php 2010-05-14 15:30:15 UTC (rev 29469) @@ -1,61 +0,0 @@ -<?php - -class sfRestInflector extends sfInflector -{ - public static function arrayToXml($array, $rootNodeName = 'data', $level = 0) - { - $xml = ''; - - if (0 == $level) - { - $xml .= '<?xml version="1.0" encoding="utf-8"?><'.ucfirst(sfInflector::camelize($rootNodeName)).'s>'; - } - - foreach ($array as $key => $value) - { - $key = ucfirst(sfInflector::camelize($key)); - - if (is_numeric($key)) - { - $key = ucfirst(sfInflector::camelize($rootNodeName)); - } - - if (is_array($value)) - { - $real_key = $key; - - if (!count($value) || isset($value[0])) - { - $real_key .= 's'; - } - - $xml .= '<'.$real_key.'>'; - $xml .= self::arrayToXml($value, $key, $level + 1); - $xml .= '</'.$real_key.'>'; - } - else - { - $trimed_value = ($value !== false) ? trim($value) : '0'; - - if ($trimed_value !== '') - { - if (htmlspecialchars($trimed_value) != $trimed_value) - { - $xml .= '<'.$key.'><![CDATA['.$trimed_value.']]></'.$key.'>'; - } - else - { - $xml .= '<'.$key.'>'.$trimed_value.'</'.$key.'>'; - } - } - } - } - - if (0 == $level) - { - $xml .= '</'.ucfirst(sfInflector::camelize($rootNodeName)).'s>'; - } - - return $xml; - } -} \ No newline at end of file Modified: plugins/sfDoctrineRestGeneratorPlugin/trunk/package.xml =================================================================== --- plugins/sfDoctrineRestGeneratorPlugin/trunk/package.xml 2010-05-14 15:21:14 UTC (rev 29468) +++ plugins/sfDoctrineRestGeneratorPlugin/trunk/package.xml 2010-05-14 15:30:15 UTC (rev 29469) @@ -21,11 +21,11 @@ <email>[email protected]</email> <active>yes</active> </lead> - <date>2010-05-09</date> - <time>10:05:19</time> + <date>2010-05-14</date> + <time>17:35:12</time> <version> - <release>0.8.0</release> - <api>0.8.0</api> + <release>0.9.0</release> + <api>0.9.0</api> </version> <stability> <release>beta</release> @@ -89,7 +89,11 @@ <file name="sfDoctrineRestGenerator.class.php" role="data"/> <file name="sfDoctrineRestGeneratorConfiguration.class.php" role="data"/> </dir> - <file name="sfRestInflector.class.php" role="data"/> + <dir name="serializer"> + <file name="sfResourceSerializer.class.php" role="data"/> + <file name="sfResourceSerializerJson.class.php" role="data"/> + <file name="sfResourceSerializerXml.class.php" role="data"/> + </dir> <dir name="task"> <file name="sfDoctrineRestGenerateModuleTask.class.php" role="data"/> </dir> @@ -119,6 +123,21 @@ <changelog> <release> <version> + <release>0.9.0</release> + <api>0.9.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2010-05-14</date> + <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> + <notes> + * added a JSON serializer + </notes> + </release> + <release> + <version> <release>0.8.0</release> <api>0.8.0</api> </version> -- You received this message because you are subscribed to the Google Groups "symfony SVN" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/symfony-svn?hl=en.
