Testing Ajax Request in Cakephp 2.0 - ajax

I have an action in my controller which does something only if the request is an XmlHttpRequest, like this:
function myAction() {
if( $this->request->is('ajax') ) {
doSomething();
}
}
What would a TestCase for this action look like? Is there a way to mock up the CakeRequest instance to appear as an Ajax request?

I don't know if it is a good way or not, but adding
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
at the top of the test method will do the job. In this case we send data as Ajax so not need to check any more.

we use a trick to solve ajax unit test for cake2.0
as cake supoprts .json extention, we create a function in AppModel to cheat ajax call. like
public function isAjax() {
return $this->request->isAjax() || $this->request->ext == 'json';
}
Then in controller, instead of calling $this->request->isAjax(), $this->isAjax() is used.
When testing action with ajax call, we simply add suffix .json to the action call, For example,
$this->testAction('/users/register');
This might not be the ultimate solution for ajax call test, but could be a workaround

Related

How to load a CodeIgniter view in $promise->then() in a controller?

In my CodeIgniter 2 controller I call a model method which returns a ReactPHP promise, and I want to load a CodeIgniter view in the function called by that promise's ->then() method. How can I do this? What happens instead is the controller method returns nothing, so I get a blank page in the browser.
Here is a simplified example illustrating what I'm trying to do:
class My_class extends My_Controller {
function my_method() {
$this->my_model->returns_a_promise()->then(function ($data) {
// How can I pass the promise's resolved value to the template here?
// It seems this never gets called, because my_method() returns
// before we get here. :(
$this->load->view('my_view', $data);
});
}
}
Is there any way to tell the controller method not to send output to the browser until after the promise has resolved?
I'm not sure what are you trying to do but if you want to stop view from outputting and return it as a string then output it with echo yourself you can do this:
$view = this->load->view('my_view', $data, TRUE);
Now you have the view as a var string you can use it to do what you are trying to do.
It turns out the code in my original question does work. So the question is the answer. But the reason it wasn't working for me was that returns_a_promise() was not returning a resolved promise, so ->then() was not called and the view was not rendered. In order to make it return a resolved promise, I had to call $deferred->resolve(); in the code that returned the promise.
The upshot of this is that this code example demonstrates it is possible to run asynchronous PHP (via ReactPHP in this case) in CodeIgniter controller methods. My particular use case is to run many database queries concurrently in the CodeIgniter model.
try this:
function my_method() {
$data = array();
$data['promise'] =$this->my_model->returns_a_promise();
$data['view'] = 'my_view';
$this->load->view('my_view', $data);
}

Separate AJAX controller vs current controller?

I have a question more regarding style and organization that anything else. I often find myself having a single page (controller) that requires multiple ajax calls. Rather than creating a separate controller just for the AJAX calls because that would mean more controllers I just do the following:
class Management extends MY_Controller
{
public function __construct()
{
parent::__construct();
$this->protect->protect();
if ($this->uri->segment(2, 0) !== 0 && !$this->input->is_ajax_request()) {
exit('No direct script access allowed');
}
}
public function index()
{
$this->load->model('management_model');
$data['row_config'] = $this->management_model->getConfigRows();
$data['row_users'] = $this->management_model->getUsers();
$data['roles'] = $this->management_model->getRoles();
$this->tpl->head();
$this->load->view('management/scripts');
$this->tpl->body();
if ($this->messages->hasMessages()) {
$this->output->append_output($this->messages->display());
}
$this->load->view('management/manage', $data);
$this->load->view('management/current_users', $data);
$this->load->view('management/modals', $data);
$this->tpl->footer();
}
public function get_user_details()
{
$user = new \Auth\ASUser($_POST['userId']);
echo json_encode($user->getAll());
}
public function delete_user()
{
$user = new \Auth\ASUser($_POST['userId']);
$user->deleteUser(true);
}
As the index is the only page where I actually need to render a proper view, and the rest are ajax calls I just check the URI segment to see if something other than the index exists and then check if its an ajax request.
Is this bad practice? Should I separate the AJAX calls and the view controller?
Honestly, i don't think that there is a pattern on where you should add your ajax functions, especially in Codeigniter which is loosely coupled for most of it's structure.
In my opinion you should ask yourself the below, in order to find where you should place your ajax calls.
Are the returned data from the ajax call, related to the Controller i am already?
Will i ever use again the same method/functionality in another Controller or somewhere else?
Do i need the already defined constructor of the Controller, which i think i should place the ajax call?
Do i count on the DRY principle of software development?
Is my code flexible, reusable, etc.?
Each project has it's own philosophy and workflow. The design pattern and the data structure that you will decide you will follow, will solve most of your questions in your coding-style.
Your question is asking an opinion which is contrary to Stack Overflow's SOP. But I'll offer my opinion anyway.
Is this bad practice? I don't think so. That said, why make a controller larger than it needs to be? If your Ajax is handling the full CRUD functionality for some page then the controller could be quite large. You might be better served by a separate controller.
An Ajax call is a distinct request to the server - essentially the same as directing the browser to a separate page on some other browser tab. Why not make that request to a controller that is dedicated to Ajax? It could be argued that such a controller produces better "Separation of Concerns". That is good practice.
There is one technique to make certain this controller is only used when requested by an ajax call. A couple lines of code in the controller will make the determination.
class Some_ajax_handler extends CI_Controller
{
public function __construct()
{
if(!is_ajax()){
show_404();
}
parent :: __construct();
//if needed, do the rest of your construct here
}
public function get_user_details()
{
$user = new \Auth\ASUser($_POST['userId']);
echo json_encode($user->getAll());
}
}
The call to show_404(); ends with a call to exit() so you don't need a return; statement or else block in the controller. You can be confident that any method that gets called on this controller is indeed an ajax request.
On the other hand, if a controller's view uses Ajax to get the contents for a select input, or some other simple GET call, then creating a separate controller seems like overkill.
BTW, there is a CI library simplifying Ajax calls HERE that you might find interesting.
The one criticism I offer isn't about ajax but about your use of new which is contrary to the "Codeigniter way" for loading and utilizing other classes (libraries). But I guess that's a different topic.

How to have a dynamic controller in Laravel

I'm trying to call dynamic popup views in which I need to pass the data through the controller, I want the controller to be dynamic which will access the particular function and make the view accordingly. Basically i'm looking for something like this:
Route::post('/popup/{id}', 'PopupController#{$id}');
So basically suppose when it is called like this: mydomain.com/popup/id1, it should call PopupController#id1.
Help me out with this.
You need a method that will fire the appropriate function
Route::post('/popup/{id}', 'PopupController#dispatch');
In PopupController
public function dispatch($id)
{
return $this->$id()
}
then if your $id is someFunction you need to make sure your controller has function someFunction() method
I suggest instead of writing a dynamic route or controller use switch case in controller action.
e.g.
Route::post('/popup/{id}', 'PopupController#action');
In Controller
public function action($id)
{
switch($id)
{
case 1: ...
case 2: ...
}
}

Laravel 4: Responding to AJAX requests from controller

I'm trying to generate ajax specific responses from my controllers by using the Request::ajax() method, which is working just fine. The only problem is that the way I have it set up right now isn't really a nice looking solution.
My controller:
class HomeController extends BaseController {
protected $layout = 'layouts/main';
public function __construct()
{
$this->beforeFilter('auth');
}
public function getIndex()
{
$view = View::make('content.home.index');
if(Request::ajax()) return $view; //For ajax calls we only want to return the content to be placed inside our container, without the layout
$this->layout->menu = 'content.menu';
$this->layout->content = $view;
}
}
So right now, for every method I define within my controllers I need to add the code snippet that checks for an AJAX request and returns a single view if the statement returns true.
This leads to my question that is probably more PHP related than it is to the framework;
Is there a way of executing my AJAX check on every method call, without actually placing it inside the method? Or is there some other solution to keep my code DRY?
Thanks in advance!
PS: This is my first post on stackoverflow, so feel free to correct me if I made any mistakes
Create a new barebone layout named 'layouts/ajax' (or any name you like).
<?php echo $content ?>
In your Base controller, override this setupLayout() function.
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$layout = Request::ajax() ? 'layouts/ajax' : $this->layout;
$this->layout = View::make($layout);
}
}
Change your getIndex() function to this.
public function getIndex()
{
$view = View::make('content.home.index');
$this->layout->menu = 'content.menu';
$this->layout->content = $view;
}
Now non-ajax requests will be rendered using layout set in the controller, where as ajax requests will receive whatever set to $this->layout->content.
Note : Controller will neglect the layout setup in setupLayout(), if the called method returns truthy value. So this method will not work for functions like below.
public function getIndex()
{
return View::make('content.home.index');
}
You could just change the layout property, in the constructor, if it's an ajax request:
public function __construct()
{
$this->beforeFilter('auth');
if(Request::ajax()) {
$this->layout = '';
}
}
If it doesn't work try setting it to NULL instead.
Why would you return a VIEW via ajax? Are you using it to create a SPA? If so there are better ways. I'm generally against returning HTML via AJAX.
The route I'd go in your position is probably opposite of how you're doing it. Render the view no matter what, if the request is ajax, pass the extra data back and have JS render the data on the page. That's essentially how most Javascript MVC frameworks function.
Sorry if I am totally missing the point here, just going on an assumption of your end goal with the info you provided.

Debugging Ajax requests in a Symfony environment

Not sure if SFDebug is any help in this situation. I am making an ajax post using jQuery. Which retrieves JSON data in my action URL and then makes a call to the Model method that executes the action. The part until my action URL, and the jQuery call to it work fine. With the data transmitted from the client to the server well received and no errors being made.
It is the part where it calls the method on the Model that is failing. My jQuery method looks like this:
$.post(url, jsonData, function(servermsg) { console.log(servermsg); }) ;
My server action is like this
public function executeMyAjaxRequest(sfWebRequest $request)
{
if($request->isXmlHttpRequest())
{
// process whatever
$servermsg = Doctrine_Core::getTable('table')->addDataToTable($dataArray);
return $this->renderText($servermsg);
}
return false;
}
The method of concern in the Table.class.php file looks like this:
public function addDataToTable($dataArray)
{
// process $dataArray and retrieve the necessary data
$data = new Data();
$data->field = $dataArray['field'];
.
.
.
$data->save();
return $data->id ;
}
The method fails up here in the model, when renderText in the action is returned and logged into the console, it returns the HTMl for SFDEBUG. Which indicates that it failed.
If this was not an Ajax call, I could debug it by seeing what the model method spat out, but this is a little tedious with Ajax in the mix.
Not looking for exact answers here, but more on how I can approach debugging ajax requests in a symfony environment, so if there are suggestions on how I can debug this, that would be great.
You must send cookie with session ide key via ajax
(Assuming you have XDEBUG configured on the server)
In order to trigger a debug session by an AJAX request you have to somehow make that request to send additional URL parameter XDEBUG_SESSION_START=1. For your example:
$.post(url + '?XDEBUG_SESSION_START=1', jsonData, function(servermsg) { console.log(servermsg); }) ;
You can also trigger it via cookie, but appending URL parameter usually easier.

Resources