I'm trying to create a game with symfony in which there are warriors. Each warrior has a level. To understand jquery and ajax which i'm new with, i want to create a simple button which when clicked use jquery ajax to get the warrior id and make him lvl up. Here is the level up method controller :
public function warriorLevelUpAction(Warrior $warrior){
$warrior->levelUp();
return $this->render('StormbladesWarriorBundle:Warrior:homepage.html.twig', array(
'warrior' => $warrior
));
}
Here is my Jquery ajax method
$('#cpt').click(function() {
$.ajax({
url: "/stormblades/web/app_dev.php/warriors/levelUp/"+{{ warrior.id }},
error: function(xhr, error){
console.debug(xhr);
console.debug(error);
}
});
And here is my routing :
stormblades_warrior_leveluppage:
path: /warriors/levelUp/{id}
defaults: { _controller: StormbladesWarriorBundle:Warrior:warriorLevelUp }
requirements:
id: \d+
Obviously, this doesn't work, i got a beautiful error 500. Any help and suggestion on what's wrong would be appreciate.
A couple of things stand out to me.
Firstly, your warriorLevelUpAction function requires a warrior object, but in the request you are only passing an id. Therefore, you require an extra step to get the warrior by it's ID then level up. For example:
public function warriorLevelUpAction($id){
$warrior = $this->getDoctrine()
->getRepository('StormbladesWarriorBundle:Warrior')
->find($id);
$warrior->levelUp();
return $this->render('StormbladesWarriorBundle:Warrior:homepage.html.twig', array(
'warrior' => $warrior
));
}
Secondly, if you are only ever going to call this function through AJAX, then you could just return a HTTP 200 Status OK, rather then render homepage.html.twig. You don't have to but, I just find it more efficient. Something like this should be fine:
$response = new Response(Response::HTTP_OK);
return $response;
Lastly, in your AJAX code, the url should be: "/warriors/levelUp/"+{{ warrior.id }}, unless there is a specific reson you are using the full path. This path will work in both development and production, whereas your current code will always run in Debug Mode.
everything said above +....
allow POST in your route through the method : POST attribute like this ( probably the reason of the 500)
defaults : ......
requirements:
_method: POST
As jrmck said , in your controller, either return a Reponse object or
return $this->container->get('templating')->renderResponse('..:page.html.twig',
array( 'var' => $var ));
If you can, use FOSJSRoutingBundle (symfony routes for javascript). Calling routes by URL is not that great if you change of adress or anything. https://github.com/FriendsOfSymfony/FOSJsRoutingBundle.
Or also
url: "{{ path('my_route_php")}}",
Related
I am creating a project and I want to have a demo for users to test but they will have access to the admin area. I want to prevent any form with post method from working. I did that with Javascript by preventing the default methods.
I was wondering if there a better way to do so, in case the Javascript never loaded.
I was going to work with the view and the controller but its hassle when the project is big, doing it with a middleware is the best thing to go with in my opinion but I still couldn't reach out its logic. What would you guys recommend the logic should look like?
Consider the #Flash answer, it's a good idea. Another way could be changing the method in controller. For example if you have a store method in ExampleController that saves/process the form, comment the lines inside the method like this:
public function store(Request $request)
{
/*
$request->validate([
'name' => 'required',
'display' => 'required',
]);
$category = new Category();
$category->parent_id = $request->parent_id;
$category->name = $request->name;
$category->display = $request->display;
$category->save();
return redirect()->route('category.add');
*/
}
Create a dummy user in your database and have a middleware in place(if you did not have it before).
Save the demo user ID in a config file, let's say config/app.php.
When someone visits your demo site, ask them to login and provide them the demo user credentials.
Create a session after the login(which you would anyway) with that user and whenever a post or any request that would affect the database is made, check like below-
Middleware Code:
if(Auth::user()->id === config('app.dummy_user_id'){
if($request->getMethod() === 'GET' || $request->getMethod() === 'OPTIONS'){
// for OPTIONS, you would play with the headers which I leave to you to edit
return $next($request);
}else{
return redirect()->back();
}
}
// your further processing
return $next($request);
I'm not so much of a framework fan but I have been made to use it because I am working on a project that others may edit later.
I am using the CodeIgniter framework (I'm kinda new on it).
I am using jquery $.post(url, function() {}) to asynchronously call a login parser that is in the root directory under a folder called php-parser I realized this folder does not make use of any of the CodeIgniter's ready made class. I decided to move the folder php-parser into application/libraries but when I tried to use jQuery to call it referencing the full path /application/libraries/php-parser/the-script.php, it return a 403 forbidden error
What do you think I can do? Some people said I could make the script a controller but here is what is going on, It's a popup modal login page. From any page if you click the login / register button, the modal pops up, how can I make a controller and a model for that (if I'm to follow that procedure).
Added: I put the modal content at the end of the footer which is included on all pages, how do I get to create a controller for that kind of modal? Any help!
When dealing with MVC (at least the way you are using it) you have three parts:
The Model - in this case this is the code which interacts with your database.
The View - the code which formats the data you are sending back to the browser
The Controller - the code which connects the two together and might have some business logic in it.
You also have some routing code which maps a URL onto the right controller for that URL.
Browsers (and other clients) only interact with web servers through URLs.
So you absolutely need to have a Controller set up to handle the request from the browser.
If you are doing this the quick and dirty way, then your controller will just get the username and password from the POST request, check it against the database with the model, and then squirt either "Success!" or "Fail!" into the view (which is probably best written as something that returns JSON formatted back to the browser).
If you are being sensibly robust about this then the view will have logic something along the lines of:
Does the browser explicitly include JSON in the accept header?
If so, send back a bit of JSON saying "success" or "failure" (or true / false, or whatever makes sense for you).
Does it not? Then either return a "Sorry, you failed to login!" HTML document or a redirect back to the page they came from (so it will reload in the logged in state).
That way, if the JavaScript fails for any reason, the plain HTML form which was progressively enhanced with the Ajax JavaScript will still function. (NB: You have to write it that way!).
jQuery will automatically include a JSON friendly Accept header if you say dataType: "json" in the Ajax options.
Yes, you will need to put your file inside the libraries folder(if the class is separate from codeigniter or is shared among many controllers, if not a Model would suffice), then create a controller for it.
class Ajax_Controller extends CI_Controller
{
public $statusCode = 200;
public $response = array();
public function __construct()
{
parent::__construct();
if(!$this->is_ajax_request()){
return; // direct access not allowed
}
$this->response = array(
'error' => false,
'text' => "",
'fields' => array()
);
}
public function sendResponse()
{
return $this->output
->set_status_header($this->statusCode)
->set_content_type('application/json')
->set_output(json_encode($this->response));
}
}
class Auth extends Ajax_Controller
{
public function __construct()
{
parent::__construct();
$this->load->library('php-parser/script', 'authentication');
}
public function login()
{
if(!$this->form_validation->run()){
$this->response = array(
'error' => true,
'text' => "The form has some errors",
'fields' => array(
'username' => form_error('username'),
'password' => form_error('password')
)
);
return $this->sendResponse();
}
$username= $this->input->post('username');
$password= $this->input->post('password');
if(!$this->authentication->login($username, $password)){
$this->response = array(
'error' => true,
'text' => "incorrect username/password combination",
'fields' => array()
);
$this->statusCode = 401;
return $this->sendResponse();
}
}
}
Working with Yii framework 2.0, I have an AJAX GET jQuery script that points to a function in a controller class.
$.get('localhost/website/index', {param: 'xxxx'}, function(returnedData){
// some code here.....
}, 'json');
In the controller class I have a method as following that handles the AJAX GET request.
public function actionIndex() {
$getParam = $_GET['param'];
// echo $getParam is: 'xxxx'.
// some other code here....
echo json_encode(array());
}
Everything works fine when executing this AJAX GET jQuery script. But if I visit the link localhost/website/index manually on the web browser, I get the following error.
PHP Notice - ErrorException
Undefined index: param
// the code snippet is also being shown.....
I don't want any users to see this error in case they know this link and visit this link by accident or on purpose. If I use
if($_GET['param']){...}
I still get the error message on the browser. How can I solve that?
You can check, that the request is an ajax request with isAjax:
$request = Yii::$app->request;
if ($request->isAjax) {...}
Or you can check that the request is POST or GET
if (Yii::$app->request->isPost) {...}
if (Yii::$app->request->isGet) {...}
And always use isset() as well! :)
easy way:
if (isset($_GET['param'])) {
...
}
right way:
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
) {
//...
}
So, I am running into a 403 forbidden error in a JavaScript call I am making in Yii. I am using XAMPP and I'm not exactly sure what the problem is. This is my first time using JavaScript/jQuery in Yii - so I don't know if there is something obvious that I should change.
A lot of posts have talked about using .htaccess - but I'm not entirely sure how that works, or where I would put that file.
Here is the call in my view
<script>
function getBalance(){
$.get("protected/views/account/balance.php", "", function(data){
alert(data);
});
}
getBalance();
</script>
And the page balance.php simply has the number 7000 (to test with). However, it is denied with 403 (Forbidden). Thank you for any help you can provide!
In Yii, you cannot call the PHP files directly like that. You have to set up an action in the controller like this:
protected/controllers/CustomController.php
<?php
class CustomController extends Controller {
public function balanceAction() {
// Return a string
echo "7000";
// or, render a view file.
// This example will render protected/views/custom/index.php
$this->render('index');
}
then the access control filter and rules in the controller has to be set to allow that new action you just created,
<?php
class CustomController extends Controller {
public function filters() {
return array(
'accessControl',
);
}
public function accessRules() {
return array(
array('allow',
// add the action name in lowercase in this array
// (without the word 'action')
'actions' => array('balance'),
'users' => array('*'),
),
// deny all other actions
array('deny',
'users' => array('*'),
),
);
}
and then in your ajax call or hyperlinks, you will need to call the file using a URL that should look like "controllerName/actionName", in the example above, I would be using "custom/balance"
$.get("custom/balance", function(){ });
Anyone can tell me what I'm doing wrong?
I am creating a simple system to get people in and out of user groups and for that purpose I am using Dojo and Perl. (If I could have it my way it would be PHP but I am not the boss.)
At the moment I only use three files, one for Perl, one for JavaScript and one for CSS styles.
The start of the CGI script routes to different functions as follows:
if ($search = $cgi->param('psearch')) {
dbConnect();
jsonSearchPersons($search);
dbDisconnect();
} elsif ($user_id = $cgi->param('person')){
dbConnect();
create_form($user_id);
dbDisconnect();
} elsif ($user_id = $cgi->param('saveuser')) {
save_user();
} else {
mainPage();
};
...
sub save_user {
print $cgi->header(-type=>'text/plain',-charset=>'utf-8');
print("success");
}
The problem I have now is when I want to save the new groups for the user though an Ajax call (a call to this URL: users.cgi?saveuser=xx). This should (in my point of view) be a POST call, so I made this and tried to append the resulting HTML/text in a <div> but it didn't work:
dojo.xhr.post({
url: "/cgi-bin/users.cgi?saveuser="+user_id,
content: {
new_groups: group_ids.toString()
},
load: function(html_content){
var element = document.getElementById("test_area");
element.innerHTML = html_content;
},
error: function(){
alert("An error has occured during the save of new user groups.");
}
});
When I do it with dojo.xhr.get(); it works fine, but when I do it with the POST it's like it jumps over that part of the if statement and just appends the mainPage() function. Is there something basic I don't understand between Dojo and Perl? Do I have to set up the pages so it will accept a POST call? Or what am I doing wrong?
NOTE: This is the first "system" I have made though Dojo and Perl. (I'm normally a PHP/jQuery kind of guy who makes everything UI by hand, so I'm kinda new to it.)
Try adding the saveuser-parameter to the content-object of dojo.xhrPost instead of passing it in the url.
You're trying to pass the saveuser-parameter as GET and the other as POST, maybe that confuses your serverside part.
Try it like that:
dojo.xhr.post({
url: "/cgi-bin/users.cgi",
content: {
new_groups: group_ids.toString(),
saveuser: user_id
},
load: function(html_content){
var element = document.getElementById("test_area");
element.innerHTML = html_content;
},
error: function(){
alert("An error has occured during the save of new user groups.");
}
});
Found a solution.
The problem was my javascript. When posting to a perl script you use $cgi=new CGI; and all that. This takes both GET and POST variables and validates them. In my javascript/dojo code, i then used an url with GET vars and then made a POST as well. This meant perl could not find out (or was mixing) the two variable types. So when i changed my ajax code (as below) it worked, since $cgi->param('saveuser') both fetches GET and POST of "saveuser" (no change to the perl was needed):
dojo.xhr.post({
url: "/cgi-bin/users.cgi",
content: {
saveuser: user_id,
new_groups: group_ids.toString()
},
load: function(html_content){
var element = document.getElementById("test_area");
element.innerHTML = html_content;
},
error: function(){
alert("An error has occured during the save of new user groups.");
}
});
Kinda wack bug, but im glad since it works great now :D
Line 675 of CGI.pm :
# Some people want to have their cake and eat it too!
# Uncomment this line to have the contents of the query string
# APPENDED to the POST data.
# $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
Made me laugh !