POST Slim Route not working - javascript

I'm using Slim for development. All my GET routes are working just fine, but whenever I use POST, I get "unexpected result". Please have a look at how I've implemented slim and that "unexpected error".
index-routes.php (index root file)
<?php
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim(array(
'debug' => true
));
require_once 'site-index.php';
require_once 'routes/default-routes.php';
$app->contentType('application/json');
$app->run();
?>
routes/default-routes.php
<?php
$app->post('/login',function(){
echo 'AllHailSuccess!';
})
?>
origin of POST request called via AJAX
function try1()
{
var value1 = "afsfesa";
API.call('/login','text','POST',function(data){console.log(data)},{var1:value1});
}
AJAX Call API
var API = {
call:function(url,returnType,reqType,callback,data){
var data = (!!data) ? data : {};
var callback = (!!callback) ? callback : function(){};
$.ajax({
dataType: returnType,
type:reqType,
crossDomain: true,
xhrFields: { withCredentials: true },
url: url,
data:data,
success:callback,
error:function(data){
console.log("Error!");
console.log(data);
}
});
}
}
"Unexpected error": When I execute try1(), THE POST ROUTE DOES GETS EXECUTED SUCCESSFULLY but the contents (The entire code in plain-text) of site-index.php (Which I called in root index-routes.php file) also gets logged along with it. The reason why I imported site-index.php in the first place, is because it acts like a "main stage" for my site. It's the only page I want to load and user navigates within it.
I want to know:
Why I'm getting this type of output?
Is my approach alright? I think importing my main-stage file from index- routes is causing this. Is there any other way of doing this?
Any help is appreciated. Thank you.

Your Slim calls are going to return anything that is displayed on the page.
There are a few ways to work around this:
Nest all of your page renders inside the route and don't render full pages for AJAX routes.
Modify your AJAX calls to search the returned DOM to find the relevant information.
In your example shown, AllHailSuccess! will be displayed after all of the content in site-index.php
Many people use templating software to render their pages and then use a service to render their page via the template. For more basic sites, I would recommend you create a simple service to display content.
Here's a simple example of a Viewer class I use in my project(s)
class Viewer {
/**
* Display the specified filename using the main template
* #param string $filepath The full path of the file to display
*/
public function display($filepath) {
//set a default value for $body so the template doesn't get angry when $body is not assigned.
$body = "";
if (file_exists($filepath)) {
$body = get_include_contents($filepath);
} else {
//You want to also return a HTTP Status Code 404 here.
$body = get_include_contents('404.html');
}
//render the page in the layout
include('layout.php');
}
}
/**
* Gets the contents of a file and 'pre-renders' it.
* Basically, this is an include() that saves the output to variable instead of displaying it.
*/
function get_include_contents($filepath, $params = array()) {
if (is_file($filepath)) {
ob_start();
include $filepath;
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
return false;
}
Your routes that you want to display the page layout to the user should look something like this now:
$app->get('/', function() {
(new Viewer())->display('home.html');
});
This is by no means a comprehensive solution because it does not address proper HTTP status codes and files are referenced directly in your code which can get messy, but it's a good starting point and its quick to mock something like this up.
If you want to continue in this direction, I would recommend you take a look at the Slim v2 Response Documentation and create a class that constructs and returns Response objects. This would give you much more flexibility and power to set HTTP status codes and HTTP Return headers.
I highly recommend checking out Slim v3 Responses as well because Slim 3 uses PSR-7 Response objects which are standard across multiple frameworks.

Related

Understanding Ajax requests to update page content when SQL Query Response changes

I am writing a page update which works with PHP to read a SQL database the page echo's the contents in a div section 'track_data'. yet it doesn't do this update idk
I have JavaScript script which I dont really fully understand and hopeful someone could explain its principally the check response section I think is failing ? :
in my PHP page :
<script type="text/javascript">
function InitReload() {
new Ajax.PeriodicalUpdater('track_data', 'fetch_sql.php', {
method: 'get', frequency: 60, decay: 1});
}
</script>
Thanks for looking and hopefully someone undersstands this and can put a smile on my face for the second time today :)
Steps to fix
Thanks for the suggestions of syntax errors. I haven't really got very far with this here are the changes you suggested which I have changed but I still think there is something wrong with last function as it doesn't update div section.
Code in JS file
// Start Clock refresh
// uses new new Ajax.PeriodicalUpdater(
// in main fetch file to trigger the auto update of the page.
// Written by Denise Rose
var gUpdateDiv;
var gContentURL;
var gcheckInterval;
var gcheckURL = "";
var gCurrentCheck ="";
_fetchUpdater('track_data','/fetch_sql.php','/fetch_sql.php',8000);
function _fetchUpdater(updateDiv,contentURL,checkURL,checkInterval)
{
gUpdateDiv = updateDiv;
gContentURL = contentURL;
gcheckInterval = checkInterval;
gcheckURL = checkURL;
setTimeout('check();',gCheckInterval);
}
//Called by _fetchUpdater every (n) seconds determins if content should be updated.
function check()
{
new Ajax.Request(gContentUrl,{method:'get', onSuccess:'checkResponse'});
setTimeout('check();',gCheckInterval);
}
// looks for the response and determines if the div should be updated.
function checkResponse(transport)
{
var content = transport.response.Text;
if(gCurrentCheck != content) {
gCurrentCheck = content;
new Ajax.Request(gContentUrl, {method: 'get',onSuccess:function t() {
$(gUpdateDiv).innerHTML = t.responseText; /*t.response.json()*/}
});
}
}
This is the bit I dont understand
function checkResponse(transport)
{
var content = transport.response.Text;
if(gCurrentCheck != content) {
gCurrentCheck = content;
new Ajax.Request(gContentUrl, {method: 'get',onSuccess:function t() {
$(gUpdateDiv).innerHTML = t.response.json();/*t.responseText;*/}
});
}
}
Method and Issues
What is transport here and what is t? if it stores the contents of the body text from the second in gCurrentCheck and compares to transport version content then why doesn't it update if its different please which it is if the SQL has created a different page?
I did find this https://api.jquery.com/jquery.ajaxtransport/
First Answer not using Ajax
I was given a neat and JS version as an answer, which is not really what I was looking for. I was hopeful to get the one working with one with Ajax but I appreciate your efforts is very kind. I just really wanted to send a refresh to the div area so that the PHP rebuilt the page from the SQL.
I might have been missing the MIT javascript http://www.prototypejs.org/ lol but I dont think it was.
Just to help:
AJAX stands for Asynchronous JavaScript And XML. In a nutshell, it is the use of the XMLHttpRequest object to communicate with servers. It can send and receive information in various formats, including JSON, XML, HTML, and text files. ... Make requests to the server without reloading the page.
Researching
I found this Update div with the result of an Ajax-call but it did not really explain as the OP was using PHP like me not HTML. The answer was given:
$.ajax({
url: 'http://dowmian.com/xs1/getcam.php',
type: 'GET',
data: {id: <?php echo $cam_id; ?>},
success: function(responseText){
$('#update-div').html(responseText);
},
error: function(responseText){
}
});
I dont think above it answered posters question or mine as ajax is a server based push how is this relevant? as if its PHP driven the needs a refresh at server to refresh the contents not to provide new html. It is this refresh I am not interested in to re-copy PHP code elsewhere in JS as its already in my PHP. Does that make more sense?
Update
I did find a bracket missing and a set of single quotes inserted by editor. Which I have updated above but there was no significant change.
Cheers Nicolas . I am still hopeful that someone knows about Ajax as it sits underneath these technologies. I have a server side PHP file that I was hoping to use AJAX to pull just the PHP from the section it was pointing to an gUpdateDiv . As its derived from the server and created on the fly from SQL. I dont see how your answer would help push this data back in to the from the server . The $(gUpdateDiv).innerHTML was supposed to be acted upon not the whole page . What I am unsure of is how a trigger from this can update timer just this $(gUpdateDiv).innerHTML . I am also not aware if a server based refresh would do this or if the transport id provided from the file would be able to deliver just that . I think I am missing something a vital part that I dont have or have grasped yet. The reason there is two timers is effectively it checks the same file at a different point in time as its created by PHP it might be different from the first if it is i.e. the SQL data has changed, I want this to update this $(gUpdateDiv).innerHTML with the data which it compared it to the second 'Get' in the second request. It sounds, simple in practice but have got stuck comparing two versions and insuring second version gets used .
Further update placing an alert in the Javascript file did not pop up like it does here https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_alert however the same alert in the initiating PHP worked fine and created the alert. called the same function from the main PHP nd the alert occurred so the JavaScript is running next visit F12 on the page to see if there is any warnings or errors. Ok after adding JQuery which I thought I had added this started working however It is not doing what i Expected it to do. As the contained both text and graphics created by PHP I expected this all to be updated The graphics are not the text is any ideas? .
Further to the image problems I placed an extra line to update the image however I used this too in PHP
<script type="text/javascript">
//initpage() ;
function updateArtworkDisplay() {
document.querySelector('#np_track_artwork').src = 'images/nowplaying_artwork_2.png?' + new Date().getTime();
}
</Script>
But it didnt work to update the image in php?
<div id='outer_img'><img id='#np_track_artwork' src='/images/nowplaying_artwork_2.png' alt='Playing track artwork' width='200' height='200'></div>
in js change
/ looks for the response and determines if the div should be updated.
function checkResponse(transport)
{
var content = transport.response.Text;
if(gCurrentCheck != content) {
gCurrentCheck = content;
new Ajax.Request(gContentUrl, {method: 'get',onSuccess:function t() {
$(gUpdateDiv).innerHTML = t.responseText; /*t.response.json()*/}
});
updateArtworkDisplay(); // fire up the redraw in php file.
}
}
Nearly there it does almost what it needs to apart from the redraw which is not happening
// Start Clock refresh
// uses new new Ajax.PeriodicalUpdater(
// in main fetch file to trigger the auto update of the page.
// Written by Denise Rose
var gUpdateDiv="";
var gContentURL="";
var gcheckInterval=0;
var gcheckURL = "";
var gCurrentCheck ="";
_fetchUpdater('track_data','/fetch_sql.php','/fetch_sql.php',8000);
function _fetchUpdater(updateDiv,contentURL,checkURL,checkInterval)
{
gUpdateDiv = updateDiv;
gContentURL = contentURL;
gcheckInterval = checkInterval;
gCheckURL = checkURL;
setTimeout('check();',gcheckInterval);
}
//Called by _fetchUpdater every (n) seconds determins if content should be updated.
function check()
{
new Ajax.Request(gCheckURL,{method:'get', onSuccess:'CheckResponse()'});
setTimeout('check();',gcheckInterval);
}
// looks for the response and determines if the div should be updated.
function checkResponse(transport)
{
var content = transport.response.Text;
if(gCurrentCheck != content) {
gCurrentCheck = content;
new Ajax.Request(gContentUrl, {method: 'get',onSuccess:function t() {
$(gUpdateDiv).innerHTML = t.responseText; /*t.response.json()*/}
});
$time = new Date().getTime();
new Ajax.Request('outer_img', {method: 'get',onSuccess:function s() {
$('outer_img').innerHTML = "<img id='#np_track_artwork' src='/images/nowplaying_artwork_2.png?t='"+$time+" alt='Playing track artwork' width='200' height='200'>"}
});
}
}
GIVEN UP WITH THIS PLEASE DELETE MY PERSONAL INFORMATION AND POSTSript-fetch-async-await/

Working with $_POST from ajax in symfony controller

I'm beginner to symfony.
I have a twig template with 2 buttons that calls an external .js that executes an ajax call.
Button 1 calls function 'delete', and this is the js code:
var path = $("#abc").attr("data-path");
/*grabs it from some div in the twig template.. <div id="abc" data-path="{{path('delete')}}"></div>*/
function delete(n){
$.ajax({
type: "POST",
url: path,
data: {id : n},
"success":function(data){
alert('ok');
}
});
}
Button 2 calls function 'edit' which is the same code except that the 'url' goes to another 'action', and the 'data' is not a json, (it is data: formData)
Routing.yml for function delete is:
delete:
pattern: /delete
defaults: {_controller: TPMainBundle:Default:delete }
And this is the controller action:
public function deleteAction()
{
$id = $_POST['id'];
/*other code to work with doctrine making queries to delete from database*/
}
(The js code is from a webpage done without symfony and it works fine)
I was told the right way to retrieve the POST in the action, reglardless it was whether a json or formData, was using the same that I used in PHP:
$id = $_POST['id'];
Here, I have 2 problems.
First, I don't know if this is correct because it doesn't work.
Second, I don't know how can I know if i'm retrieving the POST OK !!
When I did this without symfony, I checked if I was getting the POST with the command 'fwrite', because the ajax went to a PHP file instead of an Action, and then with the command fwrite I created a .txt file with the output of an echo to see if the $_POST was recovered or not.
But here in symfony I don't know how to check it, so I'm driving myself crazy.. trying to implement the solutions I read without being sure if they work..
and with the extra problem that since I'm newbie for me it's a bit confusing trying to install some external bundles for debug. Please help
The correct approach for acessing post or get params is using Symfony's Request object. You can pass it as an argument of a controller action, or retrieve it from the controller directly. Here's two examples:
public function deleteAction(Request $request)
{
if ($request->isMethod('POST')) {
$id = $request->get('id');
}
}
Without passing the Request as a parameter:
public function deleteAction()
{
if ($this->getRequest()->isMethod('POST')) {
$id = $this->getRequest()->get('id');
}
}
Extra tip for people who comes from PHP and doesn't know how to check if they are retrieving the POST or not: - send it to a .php
public function deleteAction($request)
{
$id = SOME RETRIEVED CODE YOU AREN'T SURE YOU ARE RETRIEVING THE RIGHT WAY;
/*you can send this variable to a view, symfony allows you to use .php files but you have to name their extension as html.php not just .php*/
return $this->render('TPMainBundle:Default:test.html.php', array('id' => $id));
}
And then, in that view:
<?php
echo $id;
$myfile = fopen("somename.txt", "w") or die("Unable to open file!");
$txt = 'Id is: '.$id;
fwrite($myfile, $txt);
fclose($myfile);
This will generate a .txt
So, you can open the .txt and check if you have recovered the DATA or not!
The file will be located inside the 'web' folder..
The other tips is to check the 'app/log/dev.log' thanks #Zain Saqer
In Symfony you get your POST data from the current Request object (That's how we do it in Symfony), one way to get the current Request object is by adding $request variable as first parameter in your action function.
Your action function could be like this:
public function deleteAction(Request $request)
{
//check if our POST var is there
if($request->request->has('id')){
//it's there
$id = $request->request->get('id');
/*other code to work with doctrine making queries to delete from database*/
}else{
//it's not there!
}
}
Regarding installing third party bundle, use Composer to do this task for you, and don't forget to add the class path of the installed bundle to $bundles array in AppKernal class. Follow this link to know how to do this.

Why am I getting this Internal Server Error in the Laravel Framework?

I have come across a situation that doesn't make much sense to me. Just as some background information, I'm using the Laravel framework. The page in question calls a query when the page is requested using Laravel's '->with('var', $array)' syntax. This query (which I will post later) works perfectly fine on page load, and successfully inserts dummy data I fed it.
I call this same query via an Ajax $.post using jQuery, on click of a button. However, when I do this $.post and call this query, I get an Internal Server Error every time. Everything is exactly the same, information passed included; the only difference seems to be whether or not it is called on page load or via the $.post.
Here is the error:
Below is the code that performs the query on page load:
routes.php sends the HTTP get request to a file called AppController.php
routes.php
AppController.php
The page is then made with the following array acquired from DeviceCheckoutController.php
Which then goes to DeviceCheckout.php
I am able to echo $test on the page, and it returns the ID of a new row every time the page is reloaded (which obviously mean the 'insertGetId' query worked). However, I hooked this query up to the page load just to test. What I really want to happen is on click of a button. Here is the code for that:
$("#checkoutFormbox").on('click', '#checkoutButton', function() {
var checkoutInformation = Object();
var accessories = [];
var counter = 0;
var deviceName = checkoutDeviceTable.cell(0, 0).data();
$(".accessoryCheckbox").each(function() {
//add accessory ID's to this list of only accessories selected to be checked out
if($(this).val() == "1")
{
accessories[counter] = $(this).data('id') + " ";
}
counter++;
});
checkoutInformation['deviceID'] = $(".removeButton").val(); //deviceID was previously stored in the remove button's value when the add button was clicked
checkoutInformation['outBy'] = '';
checkoutInformation['outNotes'] = $("#checkOutDeviceNotes").val();
checkoutInformation['idOfAccessories'] = 2;
checkoutInformation['dueDate'] = $("#dueDate").val();
if($("#studentIdButton").hasClass('active'))
{
checkoutInformation['renterID'] = 0;
checkoutInformation['emplid'] = 1778884;
console.log(checkoutInformation);
$.post("http://xxx.xxx.xxx.xxx/testing/public/apps/devicecheckout-checkoutdevices", {type: "checkoutDeviceForStudent", checkoutInformation: checkoutInformation}, function(returnedData) {
alert(returnedData);
});
}
});
Which is also then routed to AppController.php, specifically to the 'checkoutDeviceForStudent' part of the switch statement:
And then back to that query that is shown previously in DeviceCheckout.php
Finally, here is my DB structure for reference:
Any explanation as for why this would be happening? Also, any Laravel or other general best practice tips would be greatly appreciated as I'm inexperienced in usage of this framework and programming overall.
Sorry for such a long post, I hope there is enough information to diagnose this problem. Let me know if I need to include anything else.
Edit: Included picture of error at the top of the page.
Everything is exactly the same, information passed included
No, it isn't. If it was exactly the same you wouldn't be getting the error you're getting.
These sorts of issues are too difficult to solve by taking guesses at what the problem might be. You need to
Setup your system so Laravel's logging errors to the laravel.log file
Setup you PHP system so errors Laravel can't handled are logged to your webserver's error log (and/or PHP's error log)
Put Laravel in debug mode so errors are output the the screen, and the view the output of your ajax request via Firebug or Chrome
Once you have the actual PHP error it's usually pretty easy to see what's different about the request you think is the same, and address the issue.
I found a resolution to my problem after some advice from a friend; much easier than I anticipated and much easier than any solution that has been offered to me here or other places.
Essentially, what I needed to do was place a try, catch clause in my model function, and then if an exception is encountered I store that in a variable, return it, and use console.log() to view the exception. Here is an example to emulate my point:
public function getUserFullname($userID)
{
try
{
$myResult = DB::connection('myDatabase')->table('TheCoolestTable')->select('fullName')->where('userID', '=', $userID)->get();
return $myResult;
}
catch(Exception $e)
{
$errorMessage = 'Caught exception: ' . $e->getMessage();
return $errorMessage;
}
}
And then on the View (or wherever your model function returns to), simply console.log() the output of your POST. This will display the results of the successful query, or the results of the Exception if it encountered one as opposed to an unhelpful Internal Server Error 500 message.

ZF2 jQuery datepickers not working in ajax dialogs

Some actions on my zend framework 2 web application open via a dialog. I use this method when processing an action that is called with ajax:
/**
* Display content only on ajax call.
* #param \Zend\Mvc\MvcEvent $e
*/
public function onDispatch(\Zend\Mvc\MvcEvent $e)
{
$app = $e->getParam('application');
$layout = $app->getMvcEvent()->getViewModel();
if($app->getRequest()->isXmlHttpRequest()) {
$controller = $e->getTarget();
$controller->layout('application/ajax/ajax');
$layout->setTerminal(true);
}
}
The problem is that the datetime pickers of jquery do not seem to work. Because this HTML gets added dynamically to the page.
I think a solution might be to modify this onDispatch method so it also re-includes some of the JS-files. Or is there a better way? I just thought that adding the JS-files hard-coded into my ajax.phtml file would also work.
But again, i would like to know if there is a better approach exists, like reloading the js on the page or something.
Yeah, one way is to add the scripts to your ajax.phtml.
Something I did a while ago is to send the required scripts as a response header:
$requiredScripts = array(
'/some/js/file.js',
'/another/js/file.js'
);
$this->getResponse()->getHeaders()
->addHeaderLine('x-scripts: ' . json_encode($requiredScripts));
Then in your js:
// globally listen for the ajax-requests
$(document).ajaxSuccess(function(res, status, xhr) {
var requiredScripts = xhr.getResponseHeader("x-scripts");
if (requiredScripts) {
jQuery.each(requiredScripts, function(index, scriptSrc) {
jQuery.getScript(scriptSrc);
});
}
});

Trying to pull xml / json

Im having issues using trying to pull the first 15 words out of the file from the API. I have tried both as an XML and JSON and still seem to be getting this error:
XMLHttpRequest cannot load
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Im using the We feel fine API.
Here is my code:
<script type="text/javascript">
(function() {
var WeFeelAPI = "http://api.wefeelfine.org:8080/ShowFeelings?display=json&returnfields=feeling,conditions&limit=15";
$.getJSON( WeFeelAPI,function (json){
var feel = json.results[15];
console.log('Our feelings : ', feel);
});
})();
</script>
Any help would be appreciated i'm very new to all this, thanks
Reading up on the We Feel Fine APIs, it doesn't seem like they support JSONP, or even JSON from what I can see.
The issue preventing you from calling it is known as the Same Origin Policy. It prevents a domain from making an illegal request to another domain because of the security concerns it poses. You can read on it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript
JSONP (JSON with Padding) is a way for sites to work around it by loading the response a an external script that then triggers a callback function to validate the response content. This actual provides good info on SOP and JSONP: http://www.codeproject.com/Articles/42641/JSON-to-JSONP-Bypass-Same-Origin-Policy.
Unfortunately, the API you're using doesn't look to support JSONP so it would require the proxy approach. There is a clever/creative/maybe hackish(opinion) approach using something called Yahoo Query Language (YQL). YQL allows you to perform a x-domain request by using Yahoo's query service as the "proxy." You pass a request with a SQL-like query to it and Yahoo handles the JSONP approach. You can read about that here: http://developer.yahoo.com/yql/ (sorry for all the reading.)
And now for some code to demonstrate this. Note the QUERY being used to retrieve your XML and the fact that it must be encoded for URI use:
(function () {
var url = 'http://api.wefeelfine.org:8080/ShowFeelings?display=xml&returnfields=feeling,conditions&limit=15'
// using yahoo query
var query = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from xml where url="' + url + '"') +
'&format=json&callback=?';
// make request via YQL and show data
$.getJSON( query, function(data) {
console.log(data);
// yql returns "results" in "query" from data
console.log(data.query.results);
});
})();
Play with the fiddle: http://jsfiddle.net/Ty3y2/
This same approach can actually be used to load HTML, and in fact is probably used for that more. The key is "select * from xml where..." which tells it to select everything inside the XML element found at the requested URL. Remember that XML data has a XML element at the root. Most times you will see this as "select * from html where..." because a typical web request returns HTML which is a HTML element at the root.
I have used this approach for a couple projects, though most of mine use a proxy via PHP or C#. However, I have had good success with this and it's useful when you don't want/need to put together a proxy for it.
Here's a simple PHP proxy you can run along-side your page with the JavaScript
<?php
// Saved as ShowFeelings-proxy.php
$options = array_merge($_GET, ['display' => 'xml']);
// if you don't have PHP 5.4+, you need to use the legacy array literal syntax, eg
// array('display' => 'xml')
$uri = 'http://api.wefeelfine.org:8080/ShowFeelings?' . http_build_query($options);
$xml = simplexml_load_file($uri);
// assuming you'd rather work with JSON (I know I would)
$data = [];
foreach ($xml->feeling as $feeling) {
$entry = [];
foreach ($feeling->attributes() as $attr => $val) {
$entry[$attr] = (string) $val;
}
$data[] = (object) $entry;
}
header('Content-type: application/json');
echo json_encode($data);
exit;
Then in your JavaScript...
+function($) {
var url = 'ShowFeelings-proxy.php',
options = {
'returnfields': 'feeling,conditions',
'limit': 15
};
$.getJSON(url, options, function(data) {
var feeling = data[14]; // array is zero-based
console.log(feeling);
});
}(jQuery);

Categories

Resources