Changeset 30080
- Timestamp:
- 07/01/10 02:33:55 (3 years ago)
- Files:
-
- plugins/sfDoctrineRestGeneratorPlugin/trunk/README (modified) (19 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/configuration.php (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/createAction.php (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/getCreateValidators.php (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/getIndexValidators.php (modified) (2 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/getUpdateValidators.php (added)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php (modified) (4 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php (modified) (2 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/query.php (modified) (2 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/queryAdditionnal.php (modified) (2 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/updateAction.php (added)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/validate.php (added)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/validateCreate.php (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/validateIndex.php (modified) (2 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/validateUpdate.php (added)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/template/actions/actions.class.php (modified) (3 diffs)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/generator/sfDoctrineRestGeneratorConfiguration.class.php (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/task/sfDoctrineRestGenerateModuleTask.class.php (modified) (1 diff)
- plugins/sfDoctrineRestGeneratorPlugin/trunk/package.xml (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/sfDoctrineRestGeneratorPlugin/trunk/README
r29536 r30080 9 9 * REST module generation "à la admin-generator" 10 10 * easy-to-customize generator.yml configuration file 11 * validation of the parameters passed to the service using symfony validators 12 * serialization as XML or JSON feeds 11 13 * possibility to embed related models 12 14 * possibility to embed extra fields 13 * validation of the GET and POST constraints using Symfony validators 14 * ability to limit the number of results, with/out pagination 15 * ability to limit the number of results, with ou without pagination 15 16 * support for constraints unions (ie., http://api.example.org/city?city_id=12,13,14) 17 * hookable through events and filters 16 18 * abstract and replaceable objects serialization 17 * serialization as XML or JSON feeds19 * full HTTP support (GET, POST, PUT, DELETE) 18 20 19 21 … … 87 89 options: 88 90 model: Post 89 actions: [ create, list, delete ]91 actions: [ create, delete, list, update ] 90 92 module: post 91 93 column: id … … 101 103 102 104 103 You should be able to see your posts as a XML feed at http://api.example.com/post/ 104 105 106 ## Service configuration 107 108 As for Symfony's admin-generator, the REST generator generates code on-the-fly, 105 You should be able to see your posts as a JSON feed at http://api.example.com/post.json 106 107 108 ## Main configuration 109 110 Before configuring the content of the response of the webservice, the first 111 most important configuration steps must be undergone. They address some 112 general concerns which impact security, stability and define what the 113 webservice is supposed to do: 114 115 * which types of operations does the webservice support? Only fetching objects, or also creating/updating/deleting it? 116 * how does one access to the webservice? Which are the main security guidelines? 117 118 ### Allowed operations 119 120 The REST web service supports four different operations: 121 122 * getting a list of items ("list"): http://api.example.com/post.json (`GET` method), 123 * creating a new item ("create"): http://api.example.com/post.json (`POST` method), 124 * updating an existing item ("update"): http://api.example.com/post/123.json (`PUT` method, the value "123" must be replaced with the primary key of the object to update), 125 * deleting an existing item ("delete"): http://api.example.com/post/123.json (`DELETE` method, the value "123" must be replaced with the primary key of the object to delete), 126 127 Each of these operations can be allowed or forbidden in the routing file, 128 with the `actions` key: only enable the ones that you want to use. 129 130 ### Security guidelines 131 132 You should never forget that exposing a webservice with write access may harm 133 your data. Because of a miss of attention in the way your webservice is 134 secured, you could lose some important data, or have it be altered while it 135 shouldn't. 136 137 First, be sure to only allow the strictly required operations. If the client 138 do not have to delete items with the webservice, then disable this action in 139 the `routing.yml` file. 140 141 Second, consider a way to make your webservice more secure: 142 143 * use SSL whenever possible, so that the posted data do not get intercepted and altered by a third party (man in the middle), 144 * use HTTP authentication, 145 * use a stronger / more extensible authentication system (OAuth for example), 146 * deliver unique API keys to your clients, and check the usage that they do of the API. 147 148 149 ## Detailed service configuration 150 151 As for symfony's admin-generator, the REST generator generates code on-the-fly, 109 152 depending on the configuration done in the `generator.yml` file. 110 153 … … 123 166 # separator: ',' # separator used for multiple filters 124 167 get: 168 # additional_params: [] # list here additional params names, which are not object properties 169 # default_format: json # the default format of the response. If not set, will default to json. Accepted values are "xml" or "json" 125 170 # display: [] # list here fields to render in the response 126 171 # embed_relations: [] # list here relations to embed in the response 127 # global_additional_fields: [] # list here addition nal calculated global fields172 # global_additional_fields: [] # list here additional calculated global fields 128 173 # max_items: 0 # uncomment to fix an absolute limit to the number of items in the response 129 # object_additional_fields: [] # list here addition nal calculated fields174 # object_additional_fields: [] # list here additional calculated fields 130 175 # pagination_enabled: false # set to true to activate the pagination 131 176 # pagination_custom_page_size: false # set to true to allow the client to pass a page_size parameter … … 161 206 162 207 This contains the list of the formats allowed in the communication with the 163 API. The default allowed formats are json and XML, XMLbeing the default208 API. The default allowed formats are JSON and XML, JSON being the default 164 209 format. 165 210 166 211 This means that you can call a resource at the following URIs: 167 212 168 * http://api.example.com/post will return a XMLformatted list of the posts,213 * http://api.example.com/post will return a JSON formatted list of the posts, 169 214 * http://api.example.com/post.xml will return a XML formatted list of the posts, 170 215 * http://api.example.com/post.json will return a JSON formatted list of the posts. 171 216 172 217 Would you want to add a new serialization format, you should add this format 173 in the generator.yml, and create a serializer. See examples in the218 in the `generator.yml`, and create a serializer. See examples in the 174 219 `lib/serializer` directory of the plugin. 175 220 … … 178 223 179 224 The separator to use in url when passing objects primary keys. The generated 180 module allows to require several res sources identified by their ids:225 module allows to require several resources identified by their ids: 181 226 http://api.example.com/post/?id=12,17,19 182 227 … … 185 230 186 231 The `get` option lists several options specific to the "get" operation: 232 233 234 #### additional_params 235 236 The `default_format` option allows to define an array of parameter names, 237 which the webservice will accept. 238 239 The validation of the parameters in the generator is rather strict, and for 240 every unrecognised parameter passed to the service, the generator will launch 241 an exception. The option allows not to launch this exception for certain 242 parameter types, even if these parameters do not actually get used by the 243 generator. 244 245 The purpose of this parameter is to allow third-party params to be passed to 246 the service. For instance, you might want to pass a "`token`" or "`api_key`" 247 parameter, which could then be used to check if the client is allowed to use 248 the service. 249 250 #### default_format 251 252 The `default_format` option allows to define the default serialization format 253 when no format is asked for in the request. The accepted values are "json" or 254 "xml", or any other serialization format that you could develop (see the 255 "Serialization" paragraph). If this parameter is not set, the generator will 256 default to a "json" serializer. 187 257 188 258 … … 198 268 display: [ title, author_id ] 199 269 200 If this option is left empty, all the fie ds of the model will be rendered.270 If this option is left empty, all the fields of the model will be rendered. 201 271 202 272 #### embed_relations 203 273 204 274 The `embed_relations` options contains the list of the Doctrine relations to 205 be embedded. It might be 1-n or n-n relations, which content will be embed ed275 be embedded. It might be 1-n or n-n relations, which content will be embedded 206 276 in each object. Here is a valid configuration for our "Post" model: 207 277 … … 237 307 #### global_additional_fields 238 308 239 In some case, you might want to embed some addition nal fields in the XML or309 In some case, you might want to embed some additional fields in the XML or 240 310 JSON response. For instance, you might want to include the total number of 241 311 posts, an average price, etc. … … 251 321 252 322 This will create an empty method, which has to be manually overridden in the 253 generated module, in order to include the addition nal field of your choice:254 255 public function embed AdditionalTotalPosts($params)323 generated module, in order to include the additional field of your choice: 324 325 public function embedGlobalAdditionalTotalPosts($params) 256 326 { 257 327 $totalObjects = count($this->objects); … … 271 341 #### object_additional_fields 272 342 273 The `object_additional_fields` contains the list of the addition nal fields343 The `object_additional_fields` contains the list of the additional fields 274 344 that have to be embedded in each item of the response. For instance, if you 275 345 want to add a field `NbWords`, which would give the number of words in the … … 281 351 282 352 This will create an empty method, which has to be manually overridden in the 283 generated module, in order to include the addition nal field of your choice:353 generated module, in order to include the additional field of your choice: 284 354 285 355 public function embedAdditionalNbWords($item, $params) … … 296 366 * use the `object_additional_fields` option to unset the non-desired fields. 297 367 298 The embedAdditionalXXX methods will always look like: 368 The `embedAdditionalXXX()` methods should always have the following form (the 369 generator generates this code as comments): 299 370 300 371 public function embedAdditionalXXXX($item, $params) … … 351 422 For instance, you might want to get only the posts of a certain category 352 423 using a category_id parameter in the request. If you want to allow the client 353 to request the posts of several categories, you have to explicit ely allow it,354 as it may create more complex (ie. res source-consuming and slow) requests. In424 to request the posts of several categories, you have to explicitly allow it, 425 as it may create more complex (ie. resource-consuming and slow) requests. In 355 426 that goal, the key `multiple` has to be set to `true` for this fieldname: 356 427 … … 360 431 category_id: { multiple: true } 361 432 433 This will allow to call the webservice with several category_ids at once, with 434 a request of the form http://api.example.org/post/?category_id=1,4,5 435 362 436 For the dates fields, you might want to tell the plugin which date format is 363 437 accepted. For example: … … 368 442 created_at: { date_format: 'd-m-Y' } 369 443 444 ### Other configuration variables 445 446 Some other configuration variables are not present in the default configuration file: 447 448 * the `actions_base_class` parameter allows to change the name of the base action class which is extended by the module's action class. This permits to use your own action class, which may package several methods which you will want to use in several REST modules. 449 450 370 451 371 452 ## Serialization 372 453 373 454 The response to a get request is formatted as a XML feed or a JSON array. The 374 XML serializer generates a valid feed, enclosing the content of a field in455 XML serializer generates a valid feed, enclosing the content of a field in 375 456 CDATA sections if necessary. 376 457 … … 379 460 380 461 462 ## Events 463 464 As of version 0.9.1, the plugin uses events at several places, in order to 465 improve to overload and extend the default behavior. 466 467 Here is a list of the supported event names : 468 469 * `sfDoctrineRestGenerator.filter_error_output`: This event is launched in order to filter the error message and enable its customisation 470 * `sfDoctrineRestGenerator.filter_results`: This event is launched in order to filter the query result array (add, remove or changes some keys of it). Note that you can achieve the same thing by using the `object_additional_fields` parameter in the `generator.yml` 471 * `sfDoctrineRestGenerator.get.pre`: This event gets fired at the very beginning of a request (at the beginning of `executeIndex()`) 472 473 381 474 ## Whishlist 382 * 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. 475 476 If you use the plugin and want to help me improve it, you could consider 477 picking one of the following topics: 478 479 * possibility to nest the embed_relations parameter (and not limit it at one level only) 480 * possibility to disable events notification / filtering (performance) 481 * more serializers ([BSON](http://bsonspec.org/) or RDF 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. 482 * possibility to generate client libraries (sfDoctrineRestClientGenerator ?) 483 * possibility to generate unit tests 484 * possibility to generate API documentation 485 * document authentication solutions 383 486 * all the possible feedback! 384 487 … … 386 489 ## Contribute to the plugin, ask for help 387 490 388 Please ask for help on how to use the plugin on Symfony's users mailing list.491 Please ask for help on how to use the plugin on symfony's users mailing list. 389 492 You can also send me a mail directly : xavier@lacot.org. 390 493 … … 398 501 ## Changelog 399 502 503 ### version 0.9.2 - 2010-07-01 504 505 * Added events (thanks to Matthew Penrice) 506 * Added a default_format parameter (thanks to Matthew Penrice) 507 * Added PUT support 508 * Switched to json as default serializer (faster and less verbose) 509 * Improved the documentation 510 511 512 ### version 0.9.1 - 2010-05-14 513 514 Fixed a typo in the previous release 515 516 400 517 ### version 0.9 - 2010-05-14 401 518 402 Added a jsonserializer.519 Added a JSON serializer. 403 520 404 521 plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/configuration.php
r26226 r30080 11 11 abstract class Base<?php echo ucfirst($this->getModuleName()) ?>GeneratorConfiguration extends sfDoctrineRestGeneratorConfiguration 12 12 { 13 public function getAdditionalParams() 14 { 15 return <?php echo $this->asPhp(isset($this->config['get']['additional_params']) ? $this->config['get']['additional_params'] : array()) ?>; 16 <?php unset($this->config['get']['additional_params']) ?> 17 } 18 19 public function getDefaultFormat() 20 { 21 return <?php echo $this->asPhp(isset($this->config['get']['default_format']) ? $this->config['get']['default_format'] : 'json') ?>; 22 <?php unset($this->config['get']['default_format']) ?> 23 } 24 13 25 public function getDisplay() 14 26 { plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/createAction.php
r29536 r30080 20 20 if (!in_array($format, <?php var_export($this->configuration->getValue('default.formats_enabled', array('json', 'xml'))) ?>)) 21 21 { 22 $format = ' xml';22 $format = '<?php echo $this->configuration->getValue('get.default_format') ?>'; 23 23 } 24 24 25 25 $this->getResponse()->setStatusCode(406); 26 $error = array(array('message' => $e->getMessage()));27 26 $serializer = sfResourceSerializer::getInstance($format); 28 27 $this->getResponse()->setContentType($serializer->getContentType()); 29 $this->output = $serializer->serialize($error, 'error'); 28 $error = $e->getMessage(); 29 30 // event filter to enable customisation of the error message. 31 $result = $this->dispatcher->filter( 32 new sfEvent($this, 'sfDoctrineRestGenerator.filter_error_output'), 33 $error 34 )->getReturnValue(); 35 36 if ($error === $result) 37 { 38 $error = array(array('message' => $error)); 39 $this->output = $serializer->serialize($error, 'error'); 40 } 41 else 42 { 43 $this->output = $serializer->serialize($result); 44 } 45 30 46 $this->setTemplate('index'); 31 47 return sfView::SUCCESS; plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/getCreateValidators.php
r26209 r30080 1 1 /** 2 2 * Returns the list of validators for a create request. 3 * @return array 3 * @return array an array of validators 4 4 */ 5 5 public function getCreateValidators() plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/getIndexValidators.php
r26338 r30080 1 1 /** 2 2 * Returns the list of validators for a get request. 3 * @return array 3 * @return array an array of validators 4 4 */ 5 5 public function getIndexValidators() … … 29 29 $validators['sort_order'] = new sfValidatorChoice(array('choices' => array('asc', 'desc'), 'required' => false)); 30 30 <?php endif; ?> 31 <?php $additional_params = $this->configuration->getValue('get.additional_params'); ?> 32 <?php if ($additional_params): ?> 33 <?php foreach ($additional_params as $param): ?> 34 $validators['<?php echo $param; ?>'] = new sfValidatorPass(array('required' => false)); 35 <?php endforeach; ?> 36 <?php endif; ?> 31 37 32 38 return $validators; plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php
r29559 r30080 8 8 $this->forward404Unless($request->isMethod(sfRequest::GET)); 9 9 $params = $request->getParameterHolder()->getAll(); 10 $format = isset($params['sf_format']) ? $params['sf_format'] : 'xml'; 10 11 // notify an event before the action's body starts 12 $this->dispatcher->notify(new sfEvent($this, 'sfDoctrineRestGenerator.get.pre', array('params' => $params))); 13 14 $format = isset($params['sf_format']) ? $params['sf_format'] : '<?php echo $this->configuration->getValue('get.default_format') ?>'; 11 15 $request->setRequestFormat('html'); 12 16 13 17 if (!in_array($format, <?php var_export($this->configuration->getValue('default.formats_enabled', array('json', 'xml'))) ?>)) 14 18 { 15 $format = ' xml';19 $format = '<?php echo $this->configuration->getValue('get.default_format') ?>'; 16 20 } 17 21 … … 20 24 unset($params['action']); 21 25 26 $additional_params = <?php var_export($this->configuration->getValue('get.additional_params', array())); ?>; 27 22 28 foreach ($params as $name => $value) 23 29 { 24 if (!$value )30 if (!$value || in_array($name, $additional_params)) 25 31 { 26 32 unset($params[$name]); … … 35 41 { 36 42 $this->getResponse()->setStatusCode(406); 37 $error = array(array('message' => $e->getMessage()));38 43 $serializer = sfResourceSerializer::getInstance($format); 39 44 $this->getResponse()->setContentType($serializer->getContentType()); 40 $this->output = $serializer->serialize($error, 'error'); 45 $error = $e->getMessage(); 46 47 // event filter to enable customisation of the error message. 48 $result = $this->dispatcher->filter( 49 new sfEvent($this, 'sfDoctrineRestGenerator.filter_error_output'), 50 $error 51 )->getReturnValue(); 52 53 if ($error === $result) 54 { 55 $error = array(array('message' => $error)); 56 $this->output = $serializer->serialize($error, 'error'); 57 } 58 else 59 { 60 $this->output = $serializer->serialize($result); 61 } 62 41 63 return sfView::SUCCESS; 42 64 } … … 66 88 <?php foreach ($global_additional_fields as $field): ?> 67 89 68 $this->embed Additional<?php echo $field ?>($params);90 $this->embedGlobalAdditional<?php echo $field ?>($params); 69 91 <?php endforeach; ?> 70 92 plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php
r29472 r30080 3 3 if ($force || !isset($this->_payload_array)) 4 4 { 5 $format = $this->getRequest()->getParameter('sf_format' );5 $format = $this->getRequest()->getParameter('sf_format', '<?php echo $this->configuration->getValue('get.default_format') ?>'); 6 6 7 7 if (!in_array($format, <?php var_export($this->configuration->getValue('default.formats_enabled', array('json', 'xml'))) ?>)) 8 8 { 9 $format = ' xml';9 $format = '<?php echo $this->configuration->getValue('get.default_format') ?>'; 10 10 } 11 11 … … 21 21 if (!isset($payload_array) || !$payload_array) 22 22 { 23 throw new sfException( 'Could not load payload, obviously not a valid XML!');23 throw new sfException(sprintf('Could not parse payload, obviously not a valid %s data!', $format)); 24 24 } 25 25 plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/query.php
r26226 r30080 2 2 * Executes the query for selecting a collection of objects, eventually 3 3 * along with related objects 4 * @param array $parsm an array of criterions for the selection 4 * 5 * @param array $params an array of criterions for the selection 5 6 */ 6 7 public function query($params) … … 127 128 } 128 129 129 $this->objects = $q->execute(array(), Doctrine::HYDRATE_ARRAY); 130 $this->objects = $this->dispatcher->filter( 131 new sfEvent( 132 $this, 133 'sfDoctrineRestGenerator.filter_results', 134 array() 135 ), 136 $q->execute(array(), Doctrine::HYDRATE_ARRAY) 137 )->getReturnValue(); 130 138 } plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/queryAdditionnal.php
r26209 r30080 4 4 5 5 /** 6 * Loads related ob ect to the currently selected objects6 * Loads related object to the currently selected objects 7 7 */ 8 8 public function embedManyToMany<?php echo $embed_relation ?>() … … 14 14 <?php foreach ($object_additional_fields as $field): ?> 15 15 16 public function embedAdditional<?php echo $field ?>($item, $params) 17 { 18 } 16 /** 17 * Allows to embed an additional field "<?php echo $field ?>" in each item 18 * of the resultset 19 * 20 * @param $item the index of an item in the resultset 21 * @param $params the filtered params of the request 22 */ 23 // public function embedAdditional<?php echo $field ?>($item, $params) 24 // { 25 // $array = $this->objects[$item]; 26 // put your code here, in order to change the content of $array 27 // ... 28 // $this->objects[$item] = $array; 29 // } 19 30 <?php endforeach; ?><?php $global_additional_fields = $this->configuration->getValue('get.global_additional_fields'); ?> 20 31 <?php foreach ($global_additional_fields as $field): ?> 21 32 22 public function embedAdditional<?php echo $field ?>($items, $params) 23 { 24 } 33 /** 34 * Allows to embed an additional field "<?php echo $field ?>" at the root 35 * level of the resultset 36 * 37 * @param $items the whole resultset 38 * @param $params the filtered params of the request 39 */ 40 // public function embedGlobalAdditional<?php echo $field ?>($params) 41 // { 42 // $array = $this->objects; 43 // put your code here, in order to change the content of $array 44 // ... 45 // $this->objects = $array; 46 // } 25 47 <?php endforeach; ?> plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/validateCreate.php
r28995 r30080 1 1 /** 2 * Applies the creation validators to the XML posted to the service 3 * @param string $xml A XML string 2 * Applies the creation validators to the payload posted to the service 3 * 4 * @param string $payload A payload string 4 5 */ 5 public function validateCreate($ xml)6 public function validateCreate($payload) 6 7 { 7 8 $validators = $this->getCreateValidators(); 8 $params = $this->parsePayload($xml); 9 $unused = array_keys($validators); 10 11 foreach ($params as $name => $value) 12 { 13 if (!isset($validators[$name])) 14 { 15 throw new sfException(sprintf('Could not validate extra field "%s"', $name)); 16 } 17 else 18 { 19 $validators[$name]->clean($value); 20 unset($unused[array_search($name, $unused, true)]); 21 } 22 } 23 24 // are non given values required? 25 foreach ($unused as $name) 26 { 27 try 28 { 29 $validators[$name]->clean(null); 30 } 31 catch (Exception $e) 32 { 33 throw new sfException(sprintf('Could not validate field "%s": %s', $name, $e->getMessage())); 34 } 35 } 9 $params = $this->parsePayload($payload); 10 $this->validate($params, $validators); 36 11 } plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/parts/validateIndex.php
r28995 r30080 1 1 /** 2 * Applies the get validators to the XML posted to the service 2 * Applies the get validators to the constraint parameters passed to the webservice 3 * 3 4 * @param array $params An array of criterions used for the selection 4 5 */ … … 6 7 { 7 8 $validators = $this->getIndexValidators(); 8 $unused = array_keys($validators); 9 10 foreach ($params as $name => $value) 11 { 12 if (!isset($validators[$name])) 13 { 14 throw new sfException(sprintf('Could not validate extra field "%s"', $name)); 15 } 16 else 17 { 18 $validators[$name]->clean($value); 19 unset($unused[array_search($name, $unused, true)]); 20 } 21 } 22 23 // are non given values required? 24 foreach ($unused as $name) 25 { 26 try 27 { 28 $validators[$name]->clean(null); 29 } 30 catch (Exception $e) 31 { 32 throw new sfException(sprintf('Could not validate field "%s": %s', $name, $e->getMessage())); 33 } 34 } 9 $this->validate($params, $validators); 35 10 } plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml
r29469 r30080 6 6 config: 7 7 default: 8 # fields: # list here the fields.8 # fields: # list here the fields. 9 9 # created_at: { date_format: 'Y-m-d\TH:i:s', tag_name: 'created' } # for instance 10 10 # formats_enabled: [ xml, json ] # enabled formats 11 11 # separator: ',' # separator used for multiple filters 12 12 get: 13 # additional_params: [] # list here additionnal params names, which are not object properties 14 # default_format: json # the default format of the response. If not set, will default to json. accepted values are "xml" or "json" 13 15 # display: [] # list here fields to render in the response 14 16 # embed_relations: [] # list here relations to embed in the response plugins/sfDoctrineRestGeneratorPlugin/trunk/data/generator/sfDoctrineRestGenerator/default/template/actions/actions.class.php
r26209 r30080 13 13 14 14 { 15 p rotected$model = '<?php echo $this->getModelClass() ?>';15 public $model = '<?php echo $this->getModelClass() ?>'; 16 16 17 17 <?php include dirname(__FILE__).'/../../parts/createAction.php' ?> … … 27 27 <?php include dirname(__FILE__).'/../../parts/getIndexValidators.php' ?> 28 28 29 <?php include dirname(__FILE__).'/../../parts/getUpdateValidators.php' ?> 30 29 31 <?php include dirname(__FILE__).'/../../parts/indexAction.php' ?> 30 32 … … 34 36 <?php include dirname(__FILE__).'/../../parts/queryAdditionnal.php' ?> 35 37 38 <?php include dirname(__FILE__).'/../../parts/updateAction.php' ?> 39 36 40 <?php include dirname(__FILE__).'/../../parts/updateObjectFromRequest.php' ?> 41 42 <?php include dirname(__FILE__).'/../../parts/validate.php' ?> 37 43 38 44 <?php include dirname(__FILE__).'/../../parts/validateCreate.php' ?> 39 45 40 46 <?php include dirname(__FILE__).'/../../parts/validateIndex.php' ?> 47 48 <?php include dirname(__FILE__).'/../../parts/validateUpdate.php' ?> 41 49 } plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/generator/sfDoctrineRestGeneratorConfiguration.class.php
r26226 r30080 22 22 ), 23 23 'get' => array( 24 'additional_params' => $this->getAdditionalParams(), 25 'default_format' => $this->getDefaultFormat(), 24 26 'display' => $this->getDisplay(), 25 27 'embed_relations' => $this->getEmbedRelations(), plugins/sfDoctrineRestGeneratorPlugin/trunk/lib/task/sfDoctrineRestGenerateModuleTask.class.php
r26336 r30080 59 59 options: 60 60 model: %s 61 actions: [ create, list, delete ]61 actions: [ create, delete, list, update ] 62 62 module: %s 63 column: id63 column: %s 64 64 format: xml 65 65 66 66 67 67 EOF 68 , $model, $model, $module ).$content;68 , $model, $model, $module, $primaryKey).$content; 69 69 70 70 $this->logSection('file+', $routing); plugins/sfDoctrineRestGeneratorPlugin/trunk/package.xml
r29473 r30080 1 <?xml version="1.0" encoding=" utf-8"?>2 <package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.4.1" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">3 <name>sfDoctrineRestGeneratorPlugin</name>4 <channel>plugins.symfony-project.org</channel>5 <summary>This plugin permits to generate REST modules bound to Doctrine models.</summary>6 <description>This plugin permits to generate REST modules bound to Doctrine models. It1 <?xml version="1.0" encoding="UTF-8"?> 2 <package packagerversion="1.9.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd"> 3 <name>sfDoctrineRestGeneratorPlugin</name> 4 <channel>plugins.symfony-project.org</channel> 5 <summary>This plugin permits to generate REST modules bound to Doctrine models.</summary> 6 <description>This plugin permits to generate REST modules bound to Doctrine models. It 7 7 allows to easily create REST webservices, and provides an extensible framework 8 8 for data exchange. Here are some key features : 9 9 10 * REST module generation "à la admin-generator"10 * REST module generation "à la admin-generator" 11 11 * easy-to-customize generator.yml configuration file 12 * validation of the parameters passed to the service using symfony validators 13 * serialization as XML or JSON feeds 12 14 * possibility to embed related models 13 15 * possibility to embed extra fields 14 * validation of the GET and POST constraints using Symfony validators 15 * ability to limit the number of results, with/out pagination 16 * ability to limit the number of results, with ou without pagination 16 17 * support for constraints unions (ie., http://api.example.org/city?city_id=12,13,14) 17 * abstract and replaceable objects serialization</description> 18 <lead> 19 <name>Xavier Lacot</name> 20 <user>xavier</user> 21 <email>xavier@lacot.org</email> 22 <active>yes</active> 23 </lead> 24 <date>2010-05-14</date> 25 <time>18:23:12</time> 26 <version> 27 <release>0.9.1</release> 28 <api>0.9.1</api> 29 </version> 30 <stability> 31 <release>beta</release> 32 <api>beta</api> 33 </stability> 34 <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> 35 <notes>-</notes> 36 <contents> 37 <dir baseinstalldir="." name="/"> 38 <dir name="data"> 39 <dir name="generator"> 40 <dir name="sfDoctrineRestGenerator"> 41 <dir name="default"> 42 <dir name="parts"> 43 <file name="configuration.php" role="data"/> 44 <file name="createAction.php" role="data"/> 45 <file name="createObject.php" role="data"/> 46 <file name="deleteAction.php" role="data"/> 47 <file name="doSave.php" role="data"/> 48 <file name="fieldsConfiguration.php" role="data"/> 49 <file name="getCreateValidators.php" role="data"/> 50 <file name="getIndexValidators.php" role="data"/> 51 <file name="indexAction.php" role="data"/> 52 <file name="paginationConfiguration.php" role="data"/> 53 <file name="parsePayload.php" role="data"/> 54 <file name="query.php" role="data"/> 55 <file name="queryAdditionnal.php" role="data"/> 56 <file name="sortConfiguration.php" role="data"/> 57 <file name="updateObjectFromRequest.php" role="data"/> 58 <file name="validateCreate.php" role="data"/> 59 <file name="validateIndex.php" role="data"/> 60 </dir> 61 <dir name="skeleton"> 62 <dir name="actions"> 63 <file name="actions.class.php" role="data"/> 64 </dir> 65 <dir name="config"> 66 <file name="generator.yml" role="data"/> 67 <file name="view.yml" role="data"/> 68 </dir> 69 <dir name="lib"> 70 <file name="configuration.php" role="data"/> 71 </dir> 72 <dir name="templates"></dir> 73 </dir> 74 <dir name="template"> 75 <dir name="actions"> 76 <file name="actions.class.php" role="data"/> 77 </dir> 78 <dir name="config"></dir> 79 <dir name="templates"> 80 <file name="indexSuccess.php" role="data"/> 81 </dir> 82 </dir> 83 </dir> 84 </dir> 85 </dir> 86 </dir> 87 <dir name="lib"> 88 <dir name="generator"> 89 <file name="sfDoctrineRestGenerator.class.php" role="data"/> 90 <file name="sfDoctrineRestGeneratorConfiguration.class.php" role="data"/> 91 </dir> 92 <dir name="serializer"> 93 <file name="sfResourceSerializer.class.php" role="data"/> 94 <file name="sfResourceSerializerJson.class.php" role="data"/> 95 <file name="sfResourceSerializerXml.class.php" role="data"/> 96 </dir> 97 <dir name="task"> 98 <file name="sfDoctrineRestGenerateModuleTask.class.php" role="data"/> 99 </dir> 100 </dir> 101 <file name="LICENSE" role="data"/> 102 <file name="README" role="data"/> 103 </dir> 104 </contents> 105 <dependencies> 106 <required> 107 <php> 108 <min>5.2.4</min> 109 </php> 110 <pearinstaller> 111 <min>1.4.1</min> 112 </pearinstaller> 113 <package> 114 <name>symfony</name> 115 <channel>pear.symfony-project.com</channel> 116 <min>1.3.0</min> 117 <max>2.0.0</max> 118 <exclude>2.0.0</exclude> 119 </package> 120 </required> 121 </dependencies> 122 <phprelease></phprelease> 123 <changelog> 18 * hookable through events and filters 19 * abstract and replaceable objects serialization 20 * full HTTP support (GET, POST, PUT, DELETE)</description> 21 <lead> 22 <name>Xavier Lacot</name> 23 <user>xavier</user> 24 <email>xavier@lacot.org</email> 25 <active>yes</active> 26 </lead> 27 <date>2010-07-01</date> 28 <time>02:29:15</time> 29 <version> 30 <release>0.9.2</release> 31 <api>0.9.2</api> 32 </version> 33 <stability> 34 <release>beta</release> 35 <api>beta</api> 36 </stability> 37 <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> 38 <notes> 39 * Added events (thanks to Matthew Penrice) 40 * Added a default_format parameter (thanks to Matthew Penrice) 41 * Added PUT support 42 * Switched to json as default serializer (faster and less verbose) 43 * Improved the documentation 44 </notes> 45 <contents> 46 <dir baseinstalldir="." name="/"> 47 <file baseinstalldir="." md5sum="f72ebe8f0d391716256e00bf9306abeb" name="data/generator/sfDoctrineRestGenerator/default/parts/configuration.php" role="data" /> 48 <file baseinstalldir="." md5sum="12286407c2708190ce5891f274b8ed4d" name="data/generator/sfDoctrineRestGenerator/default/parts/createAction.php" role="data" /> 49 <file baseinstalldir="." md5sum="fc2f9a8e6dccedff99431815e16f4535" name="data/generator/sfDoctrineRestGenerator/default/parts/createObject.php" role="data" /> 50 <file baseinstalldir="." md5sum="e80ea704c1b5fed090b98e8adff45a6d" name="data/generator/sfDoctrineRestGenerator/default/parts/deleteAction.php" role="data" /> 51 <file baseinstalldir="." md5sum="8e10d6281c78d41b25aed781b7b9a0f4" name="data/generator/sfDoctrineRestGenerator/default/parts/doSave.php" role="data" /> 52 <file baseinstalldir="." md5sum="212381b5b690aa04888a3b0592dc98fe" name="data/generator/sfDoctrineRestGenerator/default/parts/fieldsConfiguration.php" role="data" /> 53 <file baseinstalldir="." md5sum="18538d45efe61438cb09b5b875b9ef0f" name="data/generator/sfDoctrineRestGenerator/default/parts/getCreateValidators.php" role="data" /> 54 <file baseinstalldir="." md5sum="e238fd6343fd47ef621da9e044304b23" name="data/generator/sfDoctrineRestGenerator/default/parts/getIndexValidators.php" role="data" /> 55 <file baseinstalldir="." md5sum="5f15869bb09c4f77cdb1bde10cab3f07" name="data/generator/sfDoctrineRestGenerator/default/parts/getUpdateValidators.php" role="php" /> 56 <file baseinstalldir="." md5sum="b17e0a85e3d1e3d28961e611c44bc34f" name="data/generator/sfDoctrineRestGenerator/default/parts/indexAction.php" role="data" /> 57 <file baseinstalldir="." md5sum="68b6c6bf924ee6e437067e41c8b0db3d" name="data/generator/sfDoctrineRestGenerator/default/parts/paginationConfiguration.php" role="data" /> 58 <file baseinstalldir="." md5sum="dbb027d32b3271ef43dcb21bcef84fd5" name="data/generator/sfDoctrineRestGenerator/default/parts/parsePayload.php" role="data" /> 59 <file baseinstalldir="." md5sum="959326712c513c268f45f846f791c41d" name="data/generator/sfDoctrineRestGenerator/default/parts/query.php" role="data" /> 60 <file baseinstalldir="." md5sum="b65e16ffe94186c5d62640f526283fdb" name="data/generator/sfDoctrineRestGenerator/default/parts/queryAdditionnal.php" role="data" /> 61 <file baseinstalldir="." md5sum="8831eef0b65854b08de5a84c6b7887d2" name="data/generator/sfDoctrineRestGenerator/default/parts/sortConfiguration.php" role="data" /> 62 <file baseinstalldir="." md5sum="e01abb2ca9197d3b4b0746d9571786bc" name="data/generator/sfDoctrineRestGenerator/default/parts/updateAction.php" role="php" /> 63 <file baseinstalldir="." md5sum="89f8383000964ee620afa2e8226ac900" name="data/generator/sfDoctrineRestGenerator/default/parts/updateObjectFromRequest.php" role="data" /> 64 <file baseinstalldir="." md5sum="c14129f5f3006d8b1f72a03ad2fe7f9e" name="data/generator/sfDoctrineRestGenerator/default/parts/validate.php" role="php" /> 65 <file baseinstalldir="." md5sum="63c0c245f2ff815b317cf6d39d6fac6e" name="data/generator/sfDoctrineRestGenerator/default/parts/validateCreate.php" role="data" /> 66 <file baseinstalldir="." md5sum="09c9158f962ca6af45b1c5fdd0929f4c" name="data/generator/sfDoctrineRestGenerator/default/parts/validateIndex.php" role="data" /> 67 <file baseinstalldir="." md5sum="dc1e971d03413449994512a52a7e8221" name="data/generator/sfDoctrineRestGenerator/default/parts/validateUpdate.php" role="php" /> 68 <file baseinstalldir="." md5sum="fa0dc415bd38a12d41b4b29bd672b9ba" name="data/generator/sfDoctrineRestGenerator/default/skeleton/actions/actions.class.php" role="data" /> 69 <file baseinstalldir="." md5sum="ab54a4734964fbd38bca5aa6460e3285" name="data/generator/sfDoctrineRestGenerator/default/skeleton/config/generator.yml" role="data" /> 70 <file baseinstalldir="." md5sum="bf5f38d67568d73b8de7db565df839fd" name="data/generator/sfDoctrineRestGenerator/default/skeleton/config/view.yml" role="data" /> 71 <file baseinstalldir="." md5sum="5557288884e6a517bfb9b3176aa08567" name="data/generator/sfDoctrineRestGenerator/default/skeleton/lib/configuration.php" role="data" /> 72 <file baseinstalldir="." md5sum="571067e0d001cd630d9db7e6ae000fc2" name="data/generator/sfDoctrineRestGenerator/default/template/actions/actions.class.php" role="data" /> 73 <file baseinstalldir="." md5sum="9ea0d70a8d800ef4c3ebaf8027dcfdc3" name="data/generator/sfDoctrineRestGenerator/default/template/templates/indexSuccess.php" role="data" /> 74 <file baseinstalldir="." md5sum="70104ec7ef554b2e465b0161e3d6423e" name="lib/generator/sfDoctrineRestGenerator.class.php" role="data" /> 75 <file baseinstalldir="." md5sum="0bcc4d9f5ece25d0924d6483ec83112a" name="lib/generator/sfDoctrineRestGeneratorConfiguration.class.php" role="data" /> 76 <file baseinstalldir="." md5sum="d838617c91f6707a74a161f0cc5fc4fe" name="lib/serializer/sfResourceSerializer.class.php" role="data" /> 77 <file baseinstalldir="." md5sum="40a5a9dc54af40db49806e79d7314571" name="lib/serializer/sfResourceSerializerJson.class.php" role="data" /> 78 <file baseinstalldir="." md5sum="e793c3af427c1aa22b7ee33459fc9284" name="lib/serializer/sfResourceSerializerXml.class.php" role="data" /> 79 <file baseinstalldir="." md5sum="cab84c1da056bd2b0713271f69afd9de" name="lib/task/sfDoctrineRestGenerateModuleTask.class.php" role="data" /> 80 <file baseinstalldir="." md5sum="42e5bbfed0992e1aa954a1b91282d5d7" name="LICENSE" role="data" /> 81 <file baseinstalldir="." md5sum="5c51849f8551c90bb2d25029bd6c176a" name="README" role="data" /> 82 </dir> 83 </contents> 84 <dependencies> 85 <required> 86 <php> 87 <min>5.2.4</min> 88 </php> 89 <pearinstaller> 90 <min>1.4.1</min> 91 </pearinstaller> 92 <package> 93 <name>symfony</name> 94 <channel>pear.symfony-project.com</channel> 95 <min>1.3.0</min> 96 <max>2.0.0</max> 97 <exclude>2.0.0</exclude> 98 </package> 99 </required> 100 </dependencies> 101 <phprelease /> 102 <changelog> 124 103 <release> 125 104 <version> 126 <release>0. 9.1</release>127 <api>0. 9.1</api>105 <release>0.8.0</release> 106 <api>0.8.0</api> 128 107 </version> 129 108 <stability> … … 131 110 <api>beta</api> 132 111 </stability> 133 <date>2010-05- 14</date>112 <date>2010-05-09</date> 134 113 <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> 135 114 <notes> 136 * fixed a typo in the previous release 115 * REST module generation "à la admin-generator" 116 * easy-to-customize generator.yml configuration file 117 * possibility to embed related models 118 * possibility to embed extra fields 119 * validation of the GET and POST constraints using Symfony validators 120 * ability to limit the number of results, with/out pagination 121 * support for constraints unions (ie., http://api.example.org/city?city_id=12,13,14) 122 * abstract and replaceable objects serialization 137 123 </notes> 138 124 </release> … … 149 135 <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> 150 136 <notes> 151 * added a JSON serializer137 * added a JSON serializer 152 138 </notes> 153 139 </release> 154 140 <release> 155 141 <version> 156 <release>0. 8.0</release>157 <api>0. 8.0</api>142 <release>0.9.1</release> 143 <api>0.9.1</api> 158 144 </version> 159 145 <stability> … … 161 147 <api>beta</api> 162 148 </stability> 163 <date>2010-05- 09</date>149 <date>2010-05-14</date> 164 150 <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> 165 151 <notes> 166 * REST module generation "à la admin-generator" 167 * easy-to-customize generator.yml configuration file 168 * possibility to embed related models 169 * possibility to embed extra fields 170 * validation of the GET and POST constraints using Symfony validators 171 * ability to limit the number of results, with/out pagination 172 * support for constraints unions (ie., http://api.example.org/city?city_id=12,13,14) 173 * abstract and replaceable objects serialization 152 * fixed a typo in the previous release 153 </notes> 154 </release> 155 <release> 156 <version> 157 <release>0.9.2</release> 158 <api>0.9.2</api> 159 </version> 160 <stability> 161 <release>beta</release> 162 <api>beta</api> 163 </stability> 164 <date>2010-07-01</date> 165 <license uri="http://www.opensource.org/licenses/mit-license.html">MIT</license> 166 <notes> 167 * Added events (thanks to Matthew Penrice) 168 * Added a default_format parameter (thanks to Matthew Penrice) 169 * Added PUT support 170 * Switched to json as default serializer (faster and less verbose) 171 * Improved the documentation 174 172 </notes> 175 173 </release>