Run php function by Ajax - php

I have button on html like this:
<button class="uk-button uk-button-primary uk-modal-close confirm-rules" type="button" onclick="sendStatus('accept_rules')">Rozumiem</button>
and I want to do it when I click on the button, the function in php will be called.
I try do this by ajax like this:
<script type="text/javascript">
function sendStatus(status) {
$.ajax({
method: "POST",
url: "Controllers/Core/Dashboards/Admin/Dashboard.php",
data: { status: status }
}).done(function( msg ) {
alert("Cookie saved:" + msg );
});
}
</script>
The problem is with php file, because it's look like this:
<?php
declare(strict_types=1);
namespace App\Controllers\Core\Dashboards\Admin;
use App\Controllers\Controller;
use App\Core\SessionManagement;
use App\Core\Request;
use App\Core\Cookies;
class AdminDashboard extends Controller
{
private $cookies;
/**
* AdminDashboard constructor.
* #param Cookies $cookies
*/
public function __construct(Cookies $cookies)
{
$this->cookies = $cookies;
}
public function acceptDashboardBox()
{
if ( isset($_POST['status']) )
{
$this->cookies->add( $_POST['status'], 'true', 'time() + (365 * 24 * 60 * 60)');
}
}
/**
*
*/
public function index() : void
{
Controller::renderView('Core/Dashboards/Admin/Dashboard');
}
}
Button must run function acceptDashboardBox() on class AdminDashboard.
How i can do this?

When calling your file Controllers/Core/Dashboards/Admin/Dashboard.php, nothing will happen because nothing calls the function acceptDashboardBox() or anything else in this file.
Please always make sure that your PHP Classes do have the name of the file that you are currently in (PSR-4). The name of your class is AdminDashboard, so call your file AdminDashboard.php to avoid confusion. Also it is common practice to use Event Listeners for click events instead of calling a function onclick=.
To let PHP only call your function acceptDashboardBox() you would need a new endpoint/file that does that same as your function and nothing else.
I would suggest you return a json with a status and catch exceptions that set the status if one occurs to something that indicates an error occurred. You can check the json in your javascript and check if the operation was successful or not. Something like:
{
status: "success"
}
OR
{
status: "failure"
}
would do the deal.

Related

Accessing already set property from the same class returns null

I am trying to display records from query in a table and on button clicked to make an ajax call to download the information in an xml format. The query is executed from method inside a class and the ajax request makes call to a different method inside the same class. The first method fills two private properties inside the class and the second property(the one called through the ajax request) must read the properties and fill the data inside table and make the file downloadable. When I try to read the properties from the same class though I get nulls and the foreach returns an error.
This is my ajax request(downloaderScript.js):
;
$("#downloadBtn").click(function (event) {
event.preventDefault();
event.stopPropagation();
$.ajax({
url: 'allClients.php',
type: 'post',
data: {action: 'downloader'},
complete: function (result) {
console.log(result);
},
error: function () {
console.log('Error');
}
});
});
This is the class from which I call the first and the second methods:
class HttpHandlerClient extends HttpHandlerAbstract
{
private $clientsService;
public $storedClientsHeadings;
public $storedClientsData;
public function viewAllClients()
{
$data = $this->clientsService->getAllClients(clientEntity::class);
if(isset($data)) {
$this->storedClientsHeadings = ["Client Names:", "Delivery Address:", "Phone number:"];
$this->storedClientsData = $data;
$this->render('allClientsView', $data);
}
else
{
$this->redirect('clientAdd');
}
}
public function downloader()
{
header("Content-Type: text/plain");
var_dump($this->storedClientsHeadings);
foreach ($this->storedClientsHeadings as $arrayName)
{
echo implode("\t", $arrayName)."\r\n";
}
/**
* #var clientEntity $clientData
*/
foreach ($this->storedClientsData as $clientData)
{
echo implode("\t", $clientData->getClientName())."\r\n";
echo implode("\t", $clientData->getAddressForDelivery())."\r\n";
echo implode("\t", $clientData->getPhone())."\r\n";
}
$filename = "clients_".date("Y-m-d").".xls";
header("Content-Disposition:attachment; filename=\"$filename\"");
header("Content-Type: application/vnd.ms-excel");
}
And this is the php file that i use between my ajax request and the php class(The file name is: allClients.php, in common.php I make an instance of the class HttpHandlerClient):
require_once 'common.php';
if(isset($_POST['action'])){
$myHttpHandlerClient->downloader();
} elseif (isset($_GET['typer'])) {
$myHttpHandlerClient->viewClientByNumber($_GET['typer']);
} else {
$myHttpHandlerClient->viewAllClients();
}
Sorry if my question is trivial, I even started doubting that after require_once I re-run the code in common.php, making a new instance of HttpHandlerClient and because of this I get nulls in the properties. But when I was reading the documentation in php's site I did not read such a thing. Any help will be appreciated, thanks.
It sounds like what may be happening is that there is a disconnect between the javascript initially loading and then more markup being added to the DOM.
The page loads up which runs your javascript. At this point the JS only knows what is currently on the page.
Your make the first call which changes the DOM. Your javascript does not know about these changes.
You try to reference something that has not been recognized by your initial load of the Javascript.
After you make the call that changes the DOM, you may have to reinitialize your JS to recognize the changes.
Good luck

php - phantomjs alerts

I am not very familiar with javascript and not sure how to handle alerts in php script when using phantomjs.
This is my code:
$this->clickcontrol(Constants::LINK, 'delete', false);
$this->acceptAlert();
So how should I change this to handle alerts in phantomjs
This looks like PHPUnit's PHPUnit_Extensions_Selenium2TestCase.
When faced with this, I have created following function (I put it into a common base test case class myself, but it also can be in your test class):
protected function waitForAlert($expectedText, $timeout = 10000)
{
$this->waitUntil(
function () use ($expectedText) {
if ($this->alertText() == $expectedText) {
return true;
}
},
$timeout
);
$this->acceptAlert();
}
Then in the test itself you can use it as such:
$this->waitForAlert('You need a complete profile');
If there is no alert it will fail after the timeout set
Hope this helps ;)

Ajax polling with Symfony Process component

I am starting a long running task that returns incremental output about the tasks progress with the Symfony Process component.
One of the examples shows how to get real time output and another example shows how to run an asynchronous task.
What I am trying to achieve is sto pass the result of getIncrementalOutput back to the ajax polling function so I can update the front end in real time.
It seems in either case the process->start() is blocking because my ajax call takes a minute to return and by that time the task has finished.
I guess I'm trying to avoid writing the progress to a db or a file and get the output directly from the running PHP task.
Not sure it's possible.
Although I don't fully understand what you want to create, I have written something similar and looking at it might answer your question:
First I created a Command that does the long-running task:
class GenerateCardBarcodesCommand extends Command
{
protected function configure()
{
$this
->setName('app:generate-card-barcodes')
->setDescription('Generate the customer cards with barcodes')
->addArgument('id', InputArgument::REQUIRED, 'id of the Loy/Card entity')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$id = $input->getArgument('id');
// generate stuff and put them in the database
}
}
In the controller the Process is started and there's an ajax action
class CardController extends Controller
{
public function newAction(Request $request)
{
// run command in background to start generating barcodes
// NOTE: unset DYLD_LIBRARY_PATH is a fix for MacOSX develop using MAMP.
// #see http://stackoverflow.com/questions/19008960/phantomjs-on-mac-os-x-works-from-the-command-line-not-via-exec
$process = new Process(sprintf('unset DYLD_LIBRARY_PATH ; php ../../apps/spin/console spin:loy:generate-card-barcodes %d', $entity->getId()));
$process->start();
sleep(1); // wait for process to start
// check for errors and output them through flashbag
if (!$process->isRunning())
if (!$process->isSuccessful())
$this->get('session')->getFlashBag()->add('error', "Oops! The process fininished with an error:".$process->getErrorOutput());
// otherwise assume the process is still running. It's progress will be displayed on the card index
return $this->redirect($this->generateUrl('loy_card'));
}
public function ajaxCreateBarcodesAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $this->getEntity($id);
$count = (int)$em->getRepository('ExtendasSpinBundle:Loy\CustomerCard')->getCount($entity);
return new Response(floor($count / ($entity->getNoCards() / 100)));
}
}
// in the twig template the ajax is retrieved, which is simply a number from 0 to 100, which is used in the jquery ui progressbar.
{{ 'Processing'|trans }}...
<script type="text/javascript">
$(function() {
function pollLatestResponse() {
$.get("{{ path('loy_card_ajax_generate_barcodes', {'id': entity[0].id}) }}").done(function (perc) {
if (perc == 100)
{
clearInterval(pollTimer);
$('#download-{{entity[0].id}}').show();
$('#progress-{{entity[0].id}}').hide();
}
else
{
$('#progress-{{entity[0].id}}').progressbar("value", parseInt(perc));
}
});
}
var pollTimer;
$(document).ready(function () {
$('#progress-{{entity[0].id}}').progressbar({"value": false});
pollTimer = setInterval(pollLatestResponse, 2000);
});
});
</script>

What's the best way to call a php method in zend model using javascript/jQuery

I'm developing a website where i have to communicate with web services. I’m using Ajax calls like this, for instance if I want to call a method called getCustomer(...) I have in my Zend project a module called "customer".
Inside of my controller, I have an action called "jsonAction"
public function jsonAction() {
$this->_helper->viewRenderer->setNoRender();
$server = new Zend_Json_Server();
$server->setClass('Customer_Model_Customer');
$server->handle();
exit;
}
Them in my model I have the function:
/**
* Get Customer
* #param string $customerNr
* #return object
*/
public function getCustomer($customerNr){
/*....*/
}
So I want to call this function using Ajax calls. What i did was something like this:
getCustomer : function(customerNr){
if(customerNr == null)
return;
var request = {};
request.method = "getCustomer";
request.params = {};
request.params.customerNr = customerNr;
request.id = Math.floor(Math.random()*101);
postObject(webServicesURL, JSON.stringify(request), successGetCustomer);
},
Where postObject it’s the Ajax function:
function postObject(url, request, successCallback){
try{
$.ajax({
type: "POST",
dataType: 'json',
url: url,
contentType: "application/x-www-form-urlencoded",
data: request,
xhrFields: {
withCredentials: true
},
success: function(data){
successCallback(data);
},
error: function (data) {
/*Notify error*/
}
});
} catch(ex){
/*erro*/
}
}
My question is, there is another way to do this? a best and elegant way? I'm new in web developing and that’s why i'm asking for your help.
Note: I'm using php Zend framework 1.12, Ember 1.0 and JQuery 1.8
A better approach could have been not to call a single action rather calling different action and let contextswitch to expose various data type you can find a code snippet here
Here is an approach
//put this in your bootstrap
protected function _initContextSwitch()
{
// Initialize contextSwitch helper
Zend_Controller_Action_HelperBroker::addHelper(new Custom_Action_Helper_ContextSwitch());
}
class Custom_Action_Helper_ContextSwitch extends
Zend_Controller_Action_Helper_ContextSwitch
{
public function preDispatch()
{
$actionName = $this->getActionController()->getRequest()->getActionName();
$this
->addActionContext($actionName, 'json')
->initContext();
}
}
Now extend Zend_Controller_Action_Helper_ContextSwitch to make all action to expose json data
Now call every method with query string(format=json) like http://example.com/module/controller/action?format=json this and will expose json data for every action
N.B Remember this is a custom action helper which namespace is Custom
If you're using Ember.js, then you should probably be using ember-data, Ember's data persistence component.
I suggest that you read the emberjs.com guides. Using Ember.js isn't something to be taken lightly and requires the adherence to conventions and standards. You need to significantly rethink your current approach.
ember-data implements a client-side RESTFUL API interface. Just like on the server, you should be specifying Models on the client. Ember.js is a framework, not a library. Use it!
You can also check if a request is ajax like this (in your controller):
$this->_request->isXmlHttpRequest()
With this you can call any action, do what is needed, and then, depending on the value you get from the request check, you either just let the view render or, in case of an AJAX call, print out a json string
public function dosomethingAction(){
// do something ...
$this->view->data = $data = array(
'param1' => 'v1'
'param2' => 'v2'
);
if($this->_request->isXmlHttpRequest()){
$this->getHelper('json')->sendJson($data);
}
}

filter methods in a controller

I want to create a filter for my add, update, and delete actions in my controllers to automatically check if they
were called in a POST, as opposed to GET or some other method
and have the pageInstanceIDs which I set in the forms on my views
protects against xss
protects against double submission of a form
from submit button double click
from back button pressed after a submision
from a url being saved or bookmarked
Currently I extended \lithium\action\Controller using an AppController and have my add, update, and delete actions defined in there.
I also have a boolean function in my AppController that checks if the appropriate pageInstanceIDs are in session or not.
Below is my code:
public function isNotPostBack() {
// pull in the session
$pageInstanceIDs = Session::read('pageInstanceIDs');
$pageInstanceID = uniqid('', true);
$this->set(compact('pageInstanceID'));
$pageInstanceIDs[] = $pageInstanceID;
Session::write('pageInstanceIDs', $pageInstanceIDs);
// checks if this is a save operation
if ($this->request->data){
$pageInstanceIDs = Session::read('pageInstanceIDs');
$pageIDIndex = array_search($this->request->data['pageInstanceID'], $pageInstanceIDs);
if ($pageIDIndex !== false) {
// remove the key
unset($pageInstanceIDs[$pageIDIndex]);
Session::write('pageInstanceIDs', $pageInstanceIDs);
return true;
}
else
return false;
} else {
return true;
}
}
public function add() {
if (!$this->request->is('post') && exist($this->request->data())) {
$msg = "Add can only be called with http:post.";
throw new DispatchException($msg);
}
}
Then in my controllers I inherit from AppController and implement the action like so:
public function add() {
parent::add();
if (parent::isNotPostBack()){
//do work
}
return $this->render(array('layout' => false));
}
which will ensure that the form used a POST and was not double submitted (back button or click happy users). This also helps protect against XSS.
I'm aware there is a plugin for this, but I want to implement this as a filter so that my controller methods are cleaner. Implented this way, the only code in my actions are the //do work portion and the return statement.
You should probably start with a filter on lithium\action\Dispatcher::run() here is some pseudo code. Can't help too much without seeing your parent::isNotPostBack() method but this should get you on the right track.
<?php
use lithium\action\Dispatcher;
Dispatcher::applyFilter('run', function($self, $params, $chain) {
$request = $params['request'];
// Request method is in $request->method
// Post data is in $request->data
if($not_your_conditions) {
return new Response(); // set up your custom response
}
return $chain->next($self, $params, $chain); // to continue on the path of execution
});
First of all, use the integrated CSRF (XSRF) protection.
The RequestToken class creates cryptographically-secure tokens and keys that can be used to validate the authenticity of client requests.
— http://li3.me/docs/lithium/security/validation/RequestToken
Check the CSRF token this way:
if ($this->request->data && !RequestToken::check($this->request)) {
/* do your stuff */
}
You can even check the HTTP method used via is()
$this->request->is('post');
The problem of filters (for that use case) is that they are very generic. So if you don't want to write all your actions as filterable code (which might be painful and overkill), you'll have to find a way to define which method blocks what and filter the Dispatcher::_call.
For CSRF protection, I use something similar to greut's suggestion.
I have this in my extensions/action/Controller.php
protected function _init() {
parent::_init();
if ($this->request->is('post') ||
$this->request->is('put') ||
$this->request->is('delete')) {
//on add, update and delete, if the security token exists, we will verify the token
if ('' != Session::read('security.token') && !RequestToken::check($this->request)) {
RequestToken::get(array('regenerate' => true));
throw new DispatchException('There was an error submitting the form.');
}
}
}
Of course, this means you'd have to also add the following to the top of your file:
use \lithium\storage\Session;
use lithium\security\validation\RequestToken;
use lithium\action\DispatchException;
With this, I don't have to repeatedly check for CSRF.
I implemented something similar in a recent project by subclassing \lithium\action\Controller as app\controllers\ApplicationController (abstract) and applying filters to invokeMethod(), as that's how the dispatcher invokes the action methods. Here's the pertinent chunk:
namespace app\controllers;
class ApplicationController extends \lithium\action\Controller {
/**
* Essential because you cannot invoke `parent::invokeMethod()` from within the closure passed to `_filter()`... But it makes me sad.
*
* #see \lithium\action\Controller::invokeMethod()
*
* #param string $method to be invoked with $arguments
* #param array $arguments to pass to $method
*/
public function _invokeMethod($method, array $arguments = array()) {
return parent::invokeMethod($method, $arguments);
}
/**
* Overridden to make action methods filterable with `applyFilter()`
*
* #see \lithium\action\Controller::invokeMethod()
* #see \lithium\core\Object::applyFilter()
*
* #param string $method to be invoked with $arguments
* #param array $arguments to pass to $method
*/
public function invokeMethod($method, array $arguments = array()) {
return $this->_filter(__METHOD__, compact('method', 'arguments'), function($self, $params){
return $self->_invokeMethod($params['method'], $params['arguments']);
});
}
}
Then you can use applyFilter() inside of _init() to run filters on your method. Instead of checking $method in every filter, you can opt to change _filter(__METHOD__, . . .) to _filter($method, . . .), but we chose to keep the more generic filter.

Categories