Cakephp jquery debug info inside the ajax response - cakephp

I have a cakephp code that works with the database to search a given card id number and return the balance. the jquery code looks like this.
function subm(event){
$.ajax({
type: "POST",
//contentType: "application/json; charset=utf-8",
dataType:'json',
url:"\/balances\/balance",
data:$("#button_check_balance").closest("form").serialize(),
cache: false,
beforeSend:function(){
$("#loadingDiv").show(1000);
},
success:function (data, textStatus,xhr) {
$("#loadingDivision").hide(1000);
alert("balance is "+data.balance);
return false;
},
//failure: function(msg){alert(msg);},
error: function(xhr, ajaxOptions, thrownError){
$("#loadingDivision").hide(1000);
alert("readyState: "+xhr.readyState+"\nstatus: "+xhr.status);
console.log(xhr.responseText);
},
/*complete: function(){
alert("complete");
},*/
});
I have the balancesController and balance.ctp files in place and controller logic looks like this.
function balance() {
$message = "";
$error = "";
$this->layout = 'ajax'; //layout should be ajax based on
Configure::write('debug', 0);
//gets the submitted card number
$card_id = $this->data['balances']['cardId']; //entered card id of the emp
if (!empty($this->data)) {
$this->header('Content-Type: application/json');
try {
$card = $this->Card->getBalance($card_id);
} catch (Exception $e) {
$error = "balance not available";
$resp = json_encode(array('error' => $error));
echo $resp;
exit;
}
if ($this->RequestHandler->isAjax()) {
$this->autoRender = $this->layout = false;
$resp = json_encode(array('cardData' => $cardObj);
echo $resp;
exit;
}
}
}
th problem that I have is - when a balance not available error is occurred "I AM GETTING THE CAKE DEBUG INFOMATION IN MY AJAX RESPONSE."
eg - when I try to access xhr object inside error function on $.ajax event
using "xhr.responseText" I am getting the long output consisting of
<pre class="cake-debug">.......... and at the end of this ONLY I get the error that I have encoded into json.
{"error":"error...."}
I have used Configure::write('debug', 1); and Configure::write('debug', 0); without any luck.as u can see I used Configure::write('debug', 0); in the top of my controller function as well..
please advice me resolve this issue. all your input is very highly appreciated.

If you're getting the debug message that means you have an error in your code and you should fix it instead of hiding it. Read the error message (or paste it here) to find out and fix the problem
You're using a throw/catch. Cake usually does not use exceptions to handle errors, unless you've specifically coded your model to throw exceptions, your error state won't be captured. Possibly $card is just returning false.
Please paste your error here, or on pastebin if it's really long.

Related

CakePHP 2.5.3 Status 500 - View file is missing when using JsonView _serialize

I'm trying to send a simple AJAX request from my view, and I'm using cakePHP's JSON view to do so, but I'm unable to get _serialize to prevent the controller from seeking a ctp file--I consistently get a "Status 500: view file ... is missing" error. I've read the docs and several similar questions on stackoverflow, and I can't see what I'm missing.
I've added the requesthandler to my initialize function in AppController:
public function initialize() {
$this->loadComponent('RequestHandler');
}
enabled extensions:
Router::parseExtensions('json');
require CAKE . 'Config' . DS . 'routes.php';
I've added the component to my controller:
class StudentsController extends AppController {
public $name = 'Students';
public $components = array('RequestHandler');
The only thing that seems to change it is when I add the following code to AppController's beforeFilter method--just renders the word "null":
$this->RequestHandler->renderAs($this, 'json');
$this->response->type('application/json');
$this->set('_serialize', true);
This is my controller method:
public function set_rating() {
$this->autoLayout = false;
$this->autoRender = false;
$this->response->type('application/json');
$studentID = (int) $this->request->data['studentID'];
$rating = (int) $this->request->data['rating'];
$this->Student->id = $studentID;
if($this->Student->saveField('rating', $rating)) {
$this->set('success', 1);
}
else{
$this->set('success', 0);
}
$this->set("_serialize", array("success"));
}
and the Ajax request:
$.ajax({
url: '<?php echo $this->webroot . $this->params["controller"]; ?>/set_rating.json',
type: "POST",
dataType: "json",
data: {studentID: text, rating: value},
success: function(response) {
if(response['success'] == 1){
manageFlashMessage('alert-success', 'Rating saved.');
}
else {
manageFlashMessage('alert-danger', 'Sorry, something went wrong');
}
},
error: function (xhr, status, error) {
console.log(xhr.status);
console.log(xhr.responseText);
console.log(status);
}
});
I can't see what I'm missing! Any ideas?
I had the same error message in a similar context; In my case, it was due to the fact that the method I was trying to call didn't get through the isAuthorized function. As such, it was redirected to another method, which was not intended to be viewed in json format, and that's how the "Status 500: view file ... is missing" error message came about.
I simply had to add the appropriate exception for my json method within the isAuthorized function and that fixed it.
To debug these types of errors, one can try to access the url directly instead through an ajax call, because then the corresponding permission error message will be shown.

CakePHP add action returning json

I have some questions on how I can improve this "add action" (method) in "controller":
1st: I'm using the add action only if post request. It's correct ?
2nd: This action doesn't have views ($this->autoRender = false;). It's correct ?
3rd: I set a response .json file to this action but I didn't change on routes to routing .json files (the file will be return when access localhost:8765/users/add). It's correct ?
4th: I'm using Enums(handmade) to store messages that will returned to user. It's correct ?
5th: I'm using an object to store the fields of message (that will returned to user), that object will be serialized and returned like this:
$this->response->body(json_encode($response)); // It's correct ?
Controller code:
public function add()
{
$this->autoRender = false;
$this->response->type('json');
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->data);
if ($this->Users->save($user)) {
$this->Auth->setUser($user->toArray());
$response = new ResponseMessage();
$response->code = CodeEnum::USER_ADDED;
$response->name = NameEnum::USER_ADDED;
$response->type = TypeMessageEnum::SUCCESS;
$this->response->body(json_encode($response));
} else {
$response = new ResponseMessage();
$response->code = CodeEnum::USER_NOT_ADDED;
$response->name = NameEnum::USER_NOT_ADDED;
$response->type = TypeMessageEnum::ERROR;
$this->response->body(json_encode($response));
}
}
}
[UPDATE]
I put this on my controller:
$this->set('response', $response);
$this->set('_serialize', ['response']);
but return this json:
{response: {code: 1, name: "Login efetuado com sucesso.", message: null, type: "Sucesso"}}
but must be returned only:
{code: 1, name: "Login efetuado com sucesso.", message: null, type: "Sucesso"}
1st: I'm using the add action only if post request. It's correct ?
Yes
2nd: This action doesn't have views ($this->autoRender = false;). It's correct ?
Not really. Instead of setting json string to response body in controller you should use JsonView which does the job for you.
3rd: I set a response .json file to this action but I didn't change on routes to routing .json files (the file will be return when access localhost:8765/users/add). It's correct ?
That's fine. Using URL ending in not .json is not necessary. But you should set Accept header in request to application/json.
4th: I'm using Enums(handmade) to store messages that will returned to user. It's correct ?
That's fine. You could check out this enum plugin.
5th: I'm using an object to store the fields of message (that will returned to user), that object will be serialized and returned like this:
As stated above better to use JsonView.

Backbone collection.create not creating the model locally

I gave up finally. I have struggling to get this one to work but no luck. I simply have a collection.create call like this:
var createData = {
full_name : full_name,
email : email,
role_id : role_id
};
var that = this;
app.collections.teamMembers.create(createData,{
wait: true,
success : function(){
log("in success")
},
error : function(a,b,c){
log("in error")
}
})
The server is PHP and it returns the result like this:
header('Content-type: application/json');
echo json_encode(array(
"data" => $data,
"meta" => $meta
));
In the above, the $data is actually the array("attr"=>"val", ...) which matches exactly how the model for this collection is defined.
The problem is that since I am not returning directly a JSON object similar to the original model, but using namespacing (data/meta), I use model.parse on the model like this:
parse : function(response){
log(response, "inside model parse, this is the response from server")
return response.data;
},
ISSUE: The model doesn't get created on the client end. No 'add' event is fired. I am also using the wait:true option.
However, the model gets created on the local if:
- I don't use wait:true
- I use wait true but return the exact JSON model from server, with no name spacing.
I WANT to use wait:true as well as namespacing. Please help :(
Finally I was able to fix it, I was overriding backbone collections and models in my bootstrap to have a loading state which I am not using anyway. So I commented out that whole code. Now it works fine. this was the code in my bootstrap that I commented out:
// OVERRIDINGS AND SETTINGS
//----------------------
// Adding close method to all views
Backbone.View.prototype.close = function() {
if (this.onClose) {
this.onClose();
}
_.each(this.childViews, function(childView){
childView.close();
delete childView;
})
this.remove();
this.unbind();
};
// Adding loading state to every model and collection
Backbone.Collection.prototype.loading = false;
Backbone.Model.prototype.isLoading = false;
// Set isLoading to true when fetch starts
var oldFetch = Backbone.Collection.prototype.fetch;
Backbone.Collection.prototype.fetch = function(options) {
this.isLoading = true;
oldFetch.call(this, options);
}
Backbone.Model.prototype.fetch = function(options) {
this.isLoading = true;
oldFetch.call(this, options);
}
// Turn off isLoading when reset
Backbone.Collection.prototype.on('reset', function(){
this.isLoading = false;
})
Backbone.Model.prototype.on('reset', function(){
this.isLoading = false;
})

How to send ajax response to Jquery from CakePhp?

I have this script in a view:
<script type="text/javascript">
$(document).ready(function() {
$("#addbrand").click(function() {
$.ajax({
url : '../brands/add',
data : {
name : "test",
shortname : "tst"
},
dataType : 'json',
success : function(html, textStatus) {
alert('Success ' + textStatus + html);
},
error : function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + errorThrown);
}
});
});
});</script>
And in add controller I have these lines:
... else if($this->request->is('ajax')){
if ($this->Brand->save($this->request->query)) {
// How to send feedback!?
}else{
// How to send feedback!?
}
$this->autoRender = false;
exit();
}
When I click addbrand, Ajax operation runs successfully and a I can see the added row in database, but I don't know how to send an error or success message to the user. I've read several tutorials but none of them were about cakephp2.0 while Everything is changed in 2.x.
I've also read JSON and XML views but unfortunately I didn't understand anything!!!
I need to send a status code. If the status was OK then I ought to to send an array of Strings (brand names actually) and if status is not OK I should send a string that explains why the operation is not completed successfully.
I'd be most grateful if anybody can help me. Thanks
Update:
I changed the code. I used CakeResponse() and now my action is like this:
if($this->RequestHandler->isAjax()){
if ($this->Brand->save($this->request->query)) {
return new CakeResponse(array('body'=> json_encode(array('val'=>'test ok')),'status'=>200));
}else{
return new CakeResponse(array('body'=> json_encode(array('val'=>'test not ok')),'status'=>500));
}
}
Using CakeResponse I can handle the possible responses in Jquery well.
$("#addbrand").click(function() {
$.ajax({
url : '../brands/add',
data : {
name : "test",
shortname : "tst"
},
dataType : 'json',
success : function(data) {
alert("The brand has been saved");
},
error : function(data) {
alert("Eorror occured");
},
complete : function(data) {
alert($.parseJSON(data.responseText).val);
}
});
});
Although it seems to me that everything is working now and I can send several variables through the Ajax between client and server in JSON format, I need to know if it's a standard way of sending Ajax responses in CakePHP or not? Is there any other simpler way for doing this?
The following lines of code do exactly whatever return new CakeResponse(array('body'=> json_encode(array('val'=>'test ok')),'status'=>200)); does in my question:
$this->set('val','test ok');
$this->set('_serialize',array('val'));
$this->response->statusCode(200);
Remember that you need to do two important things:
Add Router::parseExtensions('json'); to App/Config/routs.php.
Add var $components = array("RequestHandler"); to your controller.
I think this way is better because you don't need to return anything. In previous solution we had to return cakeresponse object and this, sits uneasy with the nature of actions.
You should use the JSON views with route extensions:
Firstly you need to set up route extensions. This is generally done with:
Router::parseExtensions('json'); // In App/Config/routes.php
This will enable Router to handle the 'json' extension and to know how to handle a request like:
www.example.com/people/index.json
if($this->RequestHandler->isAjax()){
if ($this->Brand->save($this->request->query)) {
//Logic for success
} else {
//Logic for save failure
}
}
At this point you have the ability to choose between using the data views with the serialize key or using a data view with view files (copyed from the CakeBook):
<?php
// Controller code
class PostsController extends AppController {
public function index() {
$this->set(compact('posts', 'comments'));
}
}
// View code - app/View/Posts/json/index.ctp
foreach ($posts as &$post) {
unset($post['Post']['generated_html']);
}
echo json_encode(compact('posts', 'comments'));
Notice that the view is located under .../Views/Posts/json/...
You can have multiple extensions in the router so you can return and handle all kinds of contents - after all it is all just data representation.
Cheers!

Cake returned the time consumed in data lookup in JQuery Alert Box

When I was doing some self-learning on JQuery Ajax in Cakephp,
I found out some strange behaviour in the JQuery Alert Box.
Here are a few lines of code of the JQuery Ajax I used:
$(document).ready(function(){
$(document).change(function(){
var usr = $("#data\\[User\\]\\[name\\]").val();
$.post{"http://www.mywebsite.com/controllers/action/",
usr,
function(msg){alert(msg);}
}
});
});
The Alert box shows me a message returned from the Action:
Helloworld <!--0.656s-->
I am not sure why the number of time consumption was displayed in the Alert box,
since it was not in my code as follows:
function action($data=null){
$this->autoRender = false;
$result2=$this->__avail($data);
if($result2==1)
{return "OK";}
else
{return "NOT";}
}
CakePHP rteurned some extra information in the Alert box.
Later I altered a single line of code and tried out this instead,
and the time consumption was not displayed on screen then:
$(document).ready(function(){
$(document).change(function(){
var usr = $("#data\\[User\\]\\[name\\]").val();
$.post{"http://www.mywebsite.com/controllers/action/",
usr,
function(msg){$("#username").append('<span>'+msg+</span'>);}
}
});
});
This is normal. CakePHP usually inserts a timestamp for every views. Just add Configure::write('debug', 0) to the first line of your action to avoid the timestamp from being inserted.
So your action should look something like this:
function action($data=null){
Configure::write('debug', 0)
$this->autoRender = false;
$result2=$this->__avail($data);
if($result2==1) {return "OK";}
else {return "NOT";}
}
If your action is being for an Ajax request as well as a normal Http request:
function action($data=null){
if($this->RequestHandler->isAjax()) {
Configure::write('debug', 0)
$this->autoRender = false;
$result2=$this->__avail($data);
if($result2==1) {return "OK";}
else {return "NOT";}
} else {
//Not Ajax Request.
}
}
Also make sure to add RequestHandler to the components variable in your AppController as well.
var $components = array('RequestHandler', . . . . . . );

Resources