Symfony2 : Handling error on a single controller - web-services

I made a controller to provide some webservices in JSON and i would like to provide some errors informations when Symfony throw an exception ( Error 500 ) , how can i write such a thing ?
The main purpose of the webservice is to update informations in Symfony DB provided by the caller in POST values.
in my controller i return response in JSON and i would like to handle Symfony exception ( like when the values provided or not fitting the schema designed ) to return details informations about errors .
i thought about making a test of every values but it would be a long time to write and not e easy code to read or using a try / catch system , but i think Symfony already provide such a function .
What do you think ?
Thx :)

I think you should use an EventListener to catch errors and return the proper response.
You can place it inside your SomethingBundle/EventListener folder and also you need to define a service in order to be loaded by Symfony.
More info: Event Listener
I hope I helped you, if you think I might be wrong, let me know. Good luck!
EDIT
If you only want to catch the errors inside a specific controller (for example) a controller called Webservice inside your SomethingBundle, you must check it before doing anything:
public function onKernelException(GetResponseForExceptionEvent $event)
{
$request = $event->getRequest();
if($this->getBundle($request) == "Something" && $this->getController($request) == "Webservice")
{
// Do your magic
//...
}
}
private function getBundle(Request $request)
{
$pattern = "#([a-zA-Z]*)Bundle#";
$matches = array();
preg_match($pattern, $request->get('_controller'), $matches);
return (count($matches)) ? $matches[0] : null;
}
private function getController(Request $request)
{
$pattern = "#Controller\\\([a-zA-Z]*)Controller#";
$matches = array();
preg_match($pattern, $request->get('_controller'), $matches);
return (count($matches)) ? $matches[1] : null;
}
DANGER This code is not tested, is only an approach for you to build your own code. But, if I have something wrong on it, tell me. I'd like to keep my examples clean.

Use JsonResponse Symfony class in sandbox:
use Symfony\Component\HttpFoundation\JsonResponse;
$data = array(); // array of returned response, which encode to JSON
$data['error_message'] = 'Bad request or your other error...');
$response = new JsonResponse($data, 500); // 500 - response status
return $response;

Related

Mock Middleware for route testing in Laravel

I am trying to write some unit tests to ensure my routes are not accidentally rewritten. I found already an answer to check whether a correct controller is assigned to particular route here.
However I would like to check as well that correct middlewares are assigned to route. I tried similar approach with
$tmp = new CorsService;
$corsMiddleware = Mockery::mock('Barryvdh\Cors\HandleCors[handle]', array($tmp))
->shouldReceive('handle')->once()
->andReturnUsing(function($request, Closure $next) {
return $next($request);
});
\App::instance('Barryvdh\Cors\HandleCors', $corsMiddleware);
For some reason the test is not picking this up. I am assuming that is because middleware instances are not stored using App::instance.
What am I doing wrong?
So I have found out there are 2 issues with above code
You can not chain ->shouldReceive directly with return value of Mockery::mock
there is missing \ from Closure
Working example:
$tmp = new CorsService;
$corsMiddleware = Mockery::mock('Barryvdh\Cors\HandleCors[handle]', array($tmp));
$corsMiddleware->shouldReceive('handle')->once()
->andReturnUsing(function($request, \Closure $next) {
return $next($request);
});
\App::instance('Barryvdh\Cors\HandleCors', $corsMiddleware);
Don't forget to to use ->getMock() at the end, if you are going to chain things like ->shouldReceive directly to your Mock object:
$corsMiddleware = Mockery::mock('Barryvdh\Cors\HandleCors[handle]', array($tmp))
->shouldReceive('handle')->once()
->andReturnUsing(function($request, Closure $next) {
return $next($request);
})
->getMock();
Try to get routes and check their middlewares
// Get Routes
foreach (Route::getRoutes() as $route) {
$middleware = $route->gatherMiddleware();
$name = $route->getName();
\Log::debug($name.'--');
\Log::debug($middleware);
}

Symfony3 and PHP 7 return type decleration for Doctrine Repository methods

I really like PHP's return type declarations, and I want to use it on Symfony 3.
All controller methods should return a Response object, no problem there. But in Doctrine repositories though, Doctrine might return an Entity object, or null.
Consider this example:
You have created a simple Post entity.
You have created a custom findByName method in PostRepository:
PostRepository.php
public function findByName($name) : Post
{
$qb = $this->createQueryBuilder('p')
->where('p.name = :name')
->setParameter('name', $name);
$post = $qb->getQuery()->getOneOrNullResult();
return (null === $post) ? new Post() : $post;
}
You call this method from a controller, like this:
DefaultController.php
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('AppBundle:Post');
try {
$post = $repository->findByName('test');
} catch (\TypeError $e) {
$post = new Post();
}
return new Response(dump($post));
}
I am aware trying to catch exception won't execute because findByName() always returns a Post object.
My question is, where should we handle the exception? According to this answer, it is better to throw an exception. Should we ensure repository method does not throw an exception at all by using this:
$post = $qb->getQuery()->getOneOrNullResult();
return (null === $post) ? new Post() : $post;
or let PHP throw a TypeError exception and let controller handle it?
Doctrine, throws exceptions for getOneOrNullResult() and getSingleResult() methods as described here.
If this scenario doesn't make sense because it's better to let your controller handle the exception and return a "not found" page because post doesn't exist like this:
return $this->createNotFoundException();
Scenario #2
Post exists in the database, and another repository method is called, getApprovedComments(), no comments are returned, we're expecting an ArrayCollection but we get an array. This will throw PHP's TypeError exception.
I think code is going to be full of try/catch blocks. Is it ok to handle this kind of exceptions at a higher level to have less try/catch blocks in code?
At a second thought this is not the best solution, because code should be flexible enough to catch every TypeError exception and take proper action on how to render the page.

Test JSON-returning controller method without MissingViewError

I am testing a Controller method that has only a JSON view. My method runs as expected, but the test method only returns "MissingViewException". Is there a solution to avoiding this exception in the unit test (besides inserting an empty file at View/People/map_leads.ctp)?
PeopleController.php
public function mapLeads($territory_id = null) {
$leads = $this->Person->getPeople([
'territory_id' => $territory_id
]);
$this->set('leads', $leads);
}
AppController.php
public $components = ['RequestHandler'];
routes.php
Router::parseExtensions('json');
PeopleControllerTest.php
public function testMapLeads() {
$id = 40;
$result = $this->testAction('/people/mapLeads/' . $id, array('return' => 'vars'));
}
View/People/json/map_leads.ctp exists and is properly utilized by CakePHP; it is only the test that wants to see View/People/map_leads.ctp.
I checked at CakePHP: calling testAction to a json-returning method causes missing view exception reminding about adding RequestHandler to $components. This does not resolve the exception.
You aren't issuing a JSON request/accessing a JSON endpoint, as neither your request URL does contain the .json extension, nor does your request send an appropriate Accept header (I don't remember whether the latter is possible with the 2.x controller test case class at all).
Use the .json extension and you should be good.
$this->testAction('/people/mapLeads/' . $id . '.json', array('return' => 'vars'));
Write this code inside your action.
$this->autoLayout = false;
$this->autoRender = false;
$this->response->type('application/javascript');

SoapClient does not recognize a function I am seeing in WSDL

I have a simple webservice in symfony2 that is working perfectly. I have added a new method, however, strangely, that method is not recognized, even when I see it in the WSDL definition.
Please load: WSDL definition
Method is called GetHoliday
The controller that executes that method is the following:
public function getHolidayAction() {
date_default_timezone_set('America/Santiago');
$request = $this->getRequest();
$client = new \SoapClient('http://' . $request->getHttpHost() . $request->getScriptName() . '/feriados?wsdl');
$year = $request->get('year');
$month = $request->get('month');
$day = $request->get('day');
$types = $client->__getFunctions();
var_dump($types);
die();
$result = $client->GetHoliday('8cd4c502f69b5606a8bef291deaac1ba83bb7727', 'cl', $year, $month, $day);
echo $result;
die();
}
After the call to __getFunctions call, GetHoliday method is missing.
If you want to see the __getFunctions response, please load online site
Enter any date in the input field. The response will appear in red.
The most curious thing, is that this works in my development machine which also has RedHat operating system (my hosting is HostGator).
Any help will be appreciated,
Finally, the problem was that the WSDL was being cached.
To make the first test, I used
$client = new \SoapClient('http://' . $request->getHttpHost() . $request->getScriptName() . '/feriados?wsdl', array('cache_wsdl' => WSDL_CACHE_NONE) );
To instantiate SoapClient. That way, it worked. so to get rid of WSDL_CACHE_NONE parameter, I deleted all files that start with wsdl in /tmp folder.
Regards,
Jaime

Rest API Web Service - iOS

Its my first time to use web service in iOS.
REST was my first choice and I use code igniter to form it.
I have my Controller:
require APPPATH.'/libraries/REST_Controller.php';
class Sample extends REST_Controller
{
function example_get()
{
$this->load->helper('arh');
$this->load->model('users');
$users_array = array();
$users = $this->users->get_all_users();
foreach($users as $user){
$new_array = array(
'id'=>$user->id ,
'name'=>$user->name,
'age'=>$user->age,
);
array_push( $users_array, $new_array);
}
$data['users'] = $users_array;
if($data)
{
$this->response($data, 200);
}
}
function user_put()
{
$this->load->model('users');
$this->users->insertAUser();
$message = array('message' => 'ADDED!');
$this->response($message, 200);
}
}
, using my web browser, accessing the URL http://localhost:8888/restApi/index.php/sample/example/format/json really works fine and gives this output:
{"users":[{"id":"1","name":"Porcopio","age":"99"},{"id":"2","name":"Name1","age":"24"},{"id":"3","name":"Porcopio","age":"99"},{"id":"4","name":"Porcopio","age":"99"},{"id":"5","name":"Luna","age":"99"}]}
, this gives me a great output using RKRequest by RestKit in my app.
The problem goes with the put method. This URL :
http://localhost:8888/restApi/index.php/sample/user
always give me an error like this:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<xml>
<status/>
<error>Unknown method.</error>
This is my Users model
<?php
class Users extends CI_Model {
function __construct()
{
parent::__construct();
}
function get_all_users()
{
$this->load->database();
$query = $this->db->get('users');
return $query->result();
}
function insertAUser(){
$this->load->database();
$data = array('name'=> "Sample Name", 'age'=>"99");
$this->db->insert('users', $data);
}
}
?>
What is the work around for my _put method why am I not inserting anything?
Thanks all!
Unless you set the method to PUT or POST, your web server is not going to treat it as such. When you enter URLs in a browser bar, that is almost always a GET request. You might try to use curl like
curl -X POST -d #filename http://your.url.path/whatever
Another link would be: https://superuser.com/questions/149329/what-is-the-curl-command-line-syntax-to-do-a-post-request
So you should be able to do a PUT similarly (perhaps with no data). Not really sure if this should be iOS tagged though :)
I got this problem by using Firefox plug in rest Client.
I just have to indicate the headers and the body to make put and post work.