CakePHP: Is there a easy way to send custom status code and send serialized vars in controller? - cakephp

I'm building a restful API in a controller. I want to respond to GET resources that do not exist with a 404 status response and send a message in JSON. Like this:
public function view($id = null)
$this->request->allowMethod(['get']);
try {
$pessoa = $this->Users->get($id);
} catch (RecordNotFoundException $e){
$this->set(['message'=>'User not found']);
return $response->withStatus(404);
}
$this->set(compact('users'));
}
But it does not returns the message. I guess this 'return' interferes on the variable definitions flow.

I think you use Cakephp 3.x
See Response section on CookBook.
And try it:
$this->response = $this->response->withStatus(404);

Related

Setting a header in CakePHP (MVC)

I'm trying to integrate PayPal's IPN code into CakePHP 3.
namespace App\Controller;
use PayPal\Api\PaypalIPN;
class IpnController extends AppController
{
public function index()
{
$this->autoRender = false;
$ipn = new PayPalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header("HTTP/1.1 200 OK");
}
}
This is failing to validate on PayPal's end and I'm suspecting it has to do with setting the headers in the controller view.
Is there a way to set the header properly in CakePHP's controller.
I had this code running stand alone (in just a php file) and it seemed to work just fine.
You should not output any data in your controller action - that means you should not use echo, header() or any function or construct that would return anything to browser. If you do, you will encounter a "headers already sent" error.
If you want to set headers, you should use withHeader() or withAddedHeader() methods of Cake\Http\Response.
For status codes, you also have withStatus() method:
$response = $this->response;
$response = $response->withStatus(200,"OK");
return $response; // returning response will stop controller from rendering a view.
More about setting headers can be found in docs:
Setting response headers in CakePHP 3
Cake\Http\Response::withStatus()
Maybe that's not very Cakish, but actually one can send headers this way - it just have to be followed by die; or exit; to prevent app from further response processing.
Anyway, for sure your problem is not associated with headers. IPN seems to doesn't work properly with Paypal Sandbox. Maybe you should try it other way with ApiContext class?

Call a GET in a Rest Api and send POST to give informations to the Rest Api

I'm currently using Symfony with FosRestBundle to create an Api.
In symfony I would like to catch a request from the client to give back some informations. (So a get methode).
This is my code who permit the communication between the api and the client.
Api Side :
public function getPropertiesAction(Request $request){
$properties = $this->getDoctrine()->getManager()->getRepository('ApiBundle:Achats')->findAll();
if(null == $properties){
throw $this->createNotFoundException();
}
$data = findPropertiesInside($properties, $request);
return $data;
}
Client side :
angular.module('googleMapApp')
.service('PropertiesData', function ($http) {
this.fetch = function(url, polygone, callback, errorCallback) {
$http.post(url,{data: polygone}).then(callback,errorCallback);
};
});
So when i do that the api return error 405 (Method Not Allowed)
Exception from Symfomy is No route found for "POST /api/properties": Method Not Allowed (Allow: GET, HEAD)
Is there a way to send post json informations from the client to the api and the api return the good properties?
You cannot pass a request body when using HTTP GET. You should pass the data in the url, either using the path or the query string.
Change your client side to $http.get(urlWithData).then...

CakePHP: Redirect to login from custom component

In a custom component I am making API calls. If the API call returns 403 I want to logout the user and redirect to the login. With the following code I get a response object without knowing if the response is a redirect or if the response is containing the data of the request. Besides get I have also other methods implemented in the Component so that I have at the end over 50 times a call to the RestAPIComponent.
Calling the RestAPIComponent
public function view($id)
{
$resource = $this->__getSingularResourceName();
$$resource = $this->RestApi->get($id)->json;
$this->set(compact($resource));
}
RestAPIComponent
public function get($id = null, array $query = [], $action = null)
{
$path = (is_null($id) === false) ? $id : '';
$response = $this->_http->get($path . '/' . $action, $query, $this->_getAuthHeader());
return $this->_handleResponse($response);
}
private function _handleResponse(Response $response)
{
if ($response->statusCode() == 403) {
$this->Cookie->delete(TOKEN);
$this->Cookie->delete(USER);
$controller = $this->_registry->getController();
return $controller->redirect($controller->Auth->logout());
} else {
return $response;
}
}
There may be following reasons behind it, getting the 403 error using auth component --
1.It is possible to get a 403 via code. Check this out from the CakePHP docs (http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#handling-unauthenticated-requests): If authenticator returns null, AuthComponent redirects user to login action. If it’s an ajax request and AuthComponent::$ajaxLogin is specified that element is rendered else a 403 http status code is returned.
2.Multiple Ajax calls shouldn't be the causing factor of a 403 error.
3.The standard routing is handled by CakePHP itself. If you need some different routing, you should configure this in routes.php. I would say using .htaccess is only for a really extreme routing need and should be a last resort.
4.Yes that could be a cause, since you would no longer be logged in, thus get Auth 403s
For more detail -- you could visit the link Common reasons behind 403 errors

Proper server response for Backbone.js

I am implementing Backbone.js with Codeigniter, and having a hard time receiving a proper response from Codeigniter upon a Ajax call. I was doing a #Create, which led to #save, and then #set, right at there, it breaks and couldn't find the ID in the format I returned the data.
For testing purpose, I'm echo-ing
'[{"id":"100"}]'
right back to the browswer, still it couldn't find it.
Anyone aware of a Backbone/Codeigniter(or similar) RESTful implementation example?
You need to return 200 response code or it would not pass as good response.
I built few apps with Backbone/CI combo and it is much easier if you use Phil Sturgeon's REST implementation for CodeIgniter
Than you controller that is located at url example.com/api/user and directory applications/controllers/api/user.php would look something like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
include APPPATH.'core/REST_Controller.php'; // MUST HAVE THIS LINE!!!
class User extends REST_Controller {
// update user
public function index_put() // prefix http verbs with index_
{
$this->load->model('Administration');
if($this->Administration->update_user($this->request->body)){ // MUST USE request->body
$this->response(NULL, 200); // this is how you return response with success code
return;
}
$this->response(NULL, 400); // this is how you return response with error code
}
// create user
public function index_post()
{
$this->load->model('Administration');
$new_id = $this->Administration->add_user($this->request->body);
if($new_id){
$this->response(array('id' => $new_id), 200); // return json to client (you must set json to default response format in app/config/rest.php
return;
}
$this->response(NULL, 400);
}
// deleting user
public function index_delete($id)
{
$this->load->model('Administration');
if($this->Administration->delete_user($id)){
$this->response(NULL, 200);
return;
}
$this->response(NULL, 400);
}
}
It will help you to return proper responses.
TIP: Also whatever you return to client will be set to model attributes. E.g. when creating user if you return only:
'[{"id":"100"}]'
model will be assigned id 100. But if you return:
'[{"id":"100", "date_created":"20-aug-2011", "created_by": "Admin", "random": "lfsdlkfskl"}]'
all this key value pairs will be set to user model (I added this just for clarity, since it confused me in start)
IMPORTANT: this is for CI 2.0+ if you are using 1.7.x REST implementation is a tiny bit different that concerns directory structure

Can I make CakePHP return a suitable status code based on certain conditions?

This question is slightly related to my old post Dealing with Alias URLs in CakePHP
After much thought, I am exploring the option of having a custom 404 script in my Cake App, that is reached when a URL does not map to any controllers/actions. This script would check $this->here and look it up in a database of redirects. If a match is found it would track a specific 'promo' code and redirect.
I'm thinking status codes. Can I make my script return a suitable status code based on certain conditions? For example:
URL matches a redirect - return a 301
URL really does not have a destination - return a 404.
Can I do this?
EDIT:
What about this? Anyone see any problems with it? I put it in app_controller.
function appError($method, $params) {
//do clever stuff here
}
This should work. Assuming you redirect 404's at a LegacyUrls::map() controller action. The code needs to be stored in app/app_error.php:
<?php
class AppError extends ErrorHandler{
function error404($params) {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('/legacy_urls/map', array('broken-url' => '/'.$params['url']));
exit;
}
function missingController($params) {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('/legacy_urls/map', array('broken-url' => '/'.$params['url']));
exit;
}
}
?>
Good luck!
I've always created app\views\errors\missing_action.ctp and app\views\errors\missing_controller.ctp
Cake will automatically display one of those views when a url does not map out to a controller or its methods.
Unless there is a certain need for the error codes that you did not give, this would work perfectly!
I'd like to augment felixge's answer.
This version outputs a 404 error to the browser:
class AppError extends ErrorHandler
{
function _outputMessage($template)
{
if ($template === 'error404') {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('legacy_urls/map', array('broken-url' => '/'.$params['url']));
return;
}
parent::_outputMessage($template);
}
}

Resources