Here's what I propose for our API validation, which comes almost entirely from Dingo.
For a store route (eg ListingsLocationsController::store()
), we'd throw a StoreResourceFailedException
:
# app/controllers/ListingsLocationsController.php
public function store($listingId) {
$input = Input::all();
$input['listing_id'] = $listingId;
$location = new Location($input);
if ($location->isValid() && $location->save()) {
//do save stuff
}
else {
throw new Dingo\Api\Exception\StoreResourceFailedException('Could not create new location.', $location->getErrors());
}
}
Then, on the app side, in the EatWellGuide_LocationService
, we'd catch a Guzzle ClientErrorResponseException
so PHP doesn't freak out (additionally, we could catch a Guzzle ServerErrorReponseException
, but I'm not sure we'll need to):
#craft/plugins/eatwellguide/services/EatWellGuide_LocationService.php
public function saveLocation($attr) {
$client = new \Guzzle\Http\Client();
$url = $this->getLocationUrl($attr['listing_id']);
try {
$request = $client->post($url, array(), $attr);
$response = $client->send($request);
return $response;
}
catch (\Guzzle\Http\Exception\ClientErrorResponseException $e) {
return $e->getResponse();
}
}
Then, in our controller, we need only check that the response was solid. If it wasn't, we pass along the errors as well as the message returned from the API:
#craft/plugins/eatwellguide/controllers/EatWellGuide_LocationsController.php
public function actionSaveLocation() {
/* ... */
$request = craft()->eatWellGuide_location->saveLocation($attr);
if ($request && $request->isSuccessful()) {
$this->redirectToPostedUrl();
return true;
} else {
//Log::info('Received a ' . $request->getStatusCode() . ' from Locations::save')
$response = json_decode($request->getBody(true), true);
$args = array('data' => $attr,
'errors' => $response['errors']);
craft()->userSession->setError(Craft::t($response['message']));
craft()->urlManager->setRouteVariables($args);
//continue to render existing template
}
And in the template, which is used for creating or editing:
#craft/plugins/eatwellguide/templates/locations/_form.html
{{ forms.textField({
label: 'Location name' | t | title,
required: true,
name: "location[name]",
value: location ? location["name"] : data["name"],
errors: errors ? errors["name"] : null,
}) }}