Symfony 3 Ajax call routing issue - php

I'm setting up a simple Ajax call in one of my forms. When a user enters characters in a field, the following Ajax call is activated:
self.modify = function (input_field) {
if ($(input_field).val().length > 5) {
$.post("{{path('get_bio_control_sample')}}", {sample_number: $(input_field).val()},
function (response) {
if (response.code == 100 && response.success) {
alert(response.sample_number);
}
}, "json");
}
};
Which is meant to access the following controller action:
class BioControlController extends Controller {
/**
* #Route("/bio_control/sample", name="get_bio_control_sample")
*/
public function getBioControlSampleAction(Request $request){
$sample_number = $request->query->get('sample_number');
$response = array("code" => 100, "success" => true, "sample_number" => $sample_number, "sample_data" => "test");
return new JsonResponse($response);
}
}
However, when the call is activated JS returns the error:
http://127.0.0.1:8000/omics_experiment/%7B%7Bpath('get_bio_control_sample')%7D%7D 404 (Not Found)
I'm accessing the Ajax call from omics_experiment/new (which is in the OmicsExperimentController) and using the route /bio_control/sample (as shown by the annotation), but it's not working. Can someone explain what I'm doing wrong?
I used this question as a template, the fact I'm using Symfony 3 might mean there are syntactic errors.

I just had to do this recently. I'm no expert on Symfony either, but since I just did this I may be able to help. Using Symfony is not really much different than doing it with a static URL. The main thing is to make sure that your controller and route are set up properly and working without AJAX, then you just need to use the path set in your route for the .post call.
And what makes it worse, is that it's really hard to test this type of interaction. Even your twig includes can cause it to fail if they are set up wrong.
Looking at your code again I think this may be the problem. Change this
$.post("{{path('get_bio_control_sample')}}", {sample_number:
to this
$.post("/bio_control/sample", {sample_number:
Because I think the way you have it is only good for twig templates, so if Symfony is not looking at your JQuery file like it does a twig template, then, it's not going to understand how to get the route.

Related

Symfony2 RedirectResponse message

I have problem with redirect to another website. When I redirected I see message: "Redirecting to...". Why? Really I can't redirect to site without problem?
I see:
Is it possible to change the default redirect message in Symfony?
My code:
/**
* #Route("/project/{url}/{link}/", name="page_show")
* #Template("base.html.twig")
*/
public function pageAction($link, $url) {
if ($link == '...') {
$redrect = new RedirectResponse('http://...');
return $redrect;
}
Maybe I'm Idiot and don't see solution...
I'm not sure you can combine #Template("base.html.twig") with a redirect response. Try to remove the #template annotation and do a render of base.html.twig in the end of your action :
/**
* #Route("/project/{url}/{link}/", name="page_show")
*/
public function pageAction($link, $url) {
if ($link == '...') {
$redrect = new RedirectResponse('http://...');
return $redrect;
}
// Maybe add the proper path "BundleName:DirectoryName:base.html.twig"
return $this->render('base.html.twig');
}
Read closely
First, create your template 301.html.twig into your Acme/FooBundle/Resources/views/Error/ with the content you want.
Here:
Is it possible to change the default redirect message in Symfony?
Redirect to Another web site:
public function pageAction(Request $request)
{
return $this->redirect('https://google.com');
}
If this is happening in the development environment, then you have set the intercept_redirects configuration option to true. Set it to false as explained in: http://symfony.com/doc/current/reference/configuration/web_profiler.html
If this is happening in the production environment, the reason is that RedirectResponse has some hardcoded HTML content to do the redirection. See these lines of code: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/HttpFoundation/RedirectResponse.php#L86-L96
During 1 second, you see the Redirecting to ... message. Changing this message is possible, but it requires you a lot of effort. Everything is explained here: Is it possible to change the default redirect message in Symfony?
Update: in this discussion in the Symfony repository there is more information about this. The redirect should be instantaneous because it should use the information provided in the response headers. If something wrong happens, then the hardcoded HTML content is used. So you probably need to debug why the response is not getting the right redirect headers.
Answer to your question is in official Symfony book.
http://symfony.com/doc/current/book/controller.html#redirecting
public function pageAction()
{
return $this->redirect('http://stackoverflow.com');
}
Unless you are really keen to redirect using the Symfony' RedirectResponse class, you can always relay on the old good PHP:
function redirectUrl($url, $replace=true, $status=302){
header("Location : ".$url, $replace, $status);
exit();
}
// usage example
redirectUrl("http://www.google.com");
This not only works like a charm but is extremely fast in comparison with Symfony's internal function because there is only one call + die/exit.
Read more about the PHP's header function.
However, since this approach is totally decoupled from the framework, the Symfony profiler won't be able to intercept your redirect so the developer toolbar won't notice/show this redirect. It depends what you want.

Laravel distincted script mechanics call

I am pretty much beginner in programming. Since few weeks I've been using Laravel framework. So far, I was using ajax and redirects to reach the functions in controller through Routes. Someone told me that it is wrong to use redirects and so many ajaxes in Views. So how do I call these functions and all mechanics in a proper way then? I read the documentation not for the first time but I still dont get it. Could someone explain it to me a little bit please?
This is an example how do I use views with controller.
viewfile.blade.php:
$.ajax({
type: "POST",
url: "/ineedthisfunction",
data: {
},
success: function(msg) {
alert(msg);
},
error: function(error) {
alert('error');
}
});
routes:
Route::post('/ineedthisfunction', 'Controller#thisfunction');
controller:
public function thisfunction(){
return "some returned value from script";
}
I am doing this everytime I need to use any php code. Or I am writing it inside of views. They tell me both are wrong. What do I do then?
Sometimes instead of ajax i just do: "header("location:/ineedthisfunction"); But i think it is horrible idea to.
You mentioned redirects in your question, but I don't see any redirects in your controller method. In general, if you're going to make an AJAX call then sending a redirect response isn't going to do you any good. The browser itself isn't going to receive the redirect and navigate the user to the new page, your Javascript callbacks are going to be triggered with a status code of 301 (or 302, depending). Taken that way, redirecting in response to an AJAX request just doesn't make any sense.
You have a chance in your controller method to make a choice, however, on what to return. Is the request an AJAX request? Then return something. If not, then you can easily return your redirect:
use Illuminate\Http\Request;
// ...
public function thisFunction(Request $request)
{
if($request->wantsJson()) {
// Return data to ajax request
return response()->json(['key' => 'value']);
}
return redirect()->to('/some/url');
}
Without some more context of what you're trying to accomplish I'm afraid I can't be more specific.

Preventing error pages caching when using Zend_Cache_Backend_Static

We're currently running an app that caches pages to static html files using Zend_Cache_Backend_Static. This works really well, except that our cache is getting filled with hundreds of empty files and folders when incorrect urls are requested. Is there any way to prevent a page being cached if an Exception is being thrown? I was surprised to discover that this wasn't standard behaviour.
I've done a little digging and the ZF code that actually deals with saving out the static html pages is as follows in Zend_Cache_Frontend_Capture:
public function _flush($data) {
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of _flush() without a start()');
}
if ($this->_extension) {
$this->save(serialize(array($data, $this->_extension)), $id, $this->_tags);
} else {
$this->save($data, $id, $this->_tags);
}
return $data;
}
This function is the output_callback for ob_start. I've tried getting hold of the response object to test for status but it doesn't seem to work inside _flush.
$response = Zend_Controller_Front::getInstance()->getResponse();
if($response->getStatus() == '200') {
// do the save as normal
}
else {
// do nothing
return false;
}
My only other thought was to test the length of $data, only caching if strlen($data) > 0 seems to work but it doesn't feel robust enough.
Update:
Unfortunately by the time we hit the ErrorController the static page has already been written to the cache, so disabling the cache at that point won't work. However it is possible to remove the page based on $_SERVER['REQUEST_URI'], which is what is used as an id when the page is first written. This line can be added to the start of errorAction in the ErrorController:
$this->_helper->cache->removePage($_SERVER['REQUEST_URI'], true);
It works nicely, but I'd prefer not to write the page in the first place!
From further experimentation the problem is not down to standard Zend Framework exceptions that cause 404s (ie. Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE, Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER, Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION) but to my custom exceptions. This is now really obvious now that I think about it, as Zend_Cache_Backend_Static needs to be initialised in the init method of an action controller. Any situation where there is no route, controller or action it won't ever be initialised anyway.
I'm throwing exceptions in existing actions where a user may be querying for a non-existent article. Therefore caching has been enabled in init and the page has been written by the time we hit postDispatch in a Front Controller Plugin (still not sure why this is the case it just is) so I can't cancel at that point. One solution then is to cancel the cache at the point of throwing the exception. The standard method of managing static page caching is using the Zend_Controller_Action_Helper_Cache action helper. I've extended this to add a cancel method like so:
<?php
class Zend_Controller_Action_Helper_PageCache extends Zend_Controller_Action_Helper_Cache {
public function cancel() {
$cache = $this->getCache(Zend_Cache_Manager::PAGECACHE);
$cache->setOption('caching', false);
$cache->getBackend('disable_caching', true);
}
}
My action controller now looks like this:
<?php
class IndexController extends Zend_Controller_Action {
private $_model;
public function init() {
$this->_model = new Model();
// using extended pageCache rather than $this->_helper->cache:
$this->_helper->pageCache(array('index'), array('indexaction'));
}
public function indexAction() {
$alias = $this->_request->getParam('article');
$article = $this->_model->getArticleByAlias($alias);
if(!$article) {
// new cancel method will disable caching
$this->_helper->pageCache->cancel();
throw new Zend_Controller_Action_Exception('Invalid article alias', 404);
}
$this->view->article = $article;
}
}
You should alter your .htaccess file RewriteRules to check for filesizes with option -s
This way if an error should occur when a page is being cached (thus producing a 0 byte file) it won't permanently be stored in the cache.
If you are using the standard ErrorController to handle 404, 500, and unhandled exceptions, and you can get a reference to your cache object from there, you could disable caching from the error handler.
In your error controller (or wherever you would like to cancel caching from), try:
$cache->setOption('caching', false);
When the save() metod of Zend_Cache_Core is called by Zend_Cache_Frontend_Capture::_flush(), it will see the caching option is set to false and it will not actually save the data to the cache and return true.

OO PHP + Ajax without framework

I'm going to write a booking website using php and ajax and I really can't figure how to mix these two tools with a strict object oriented design.
I was used to make a call using ajax to a php web page that returns the right set of values (string, xml, json) in a procedural way.
With object oriented programming how is it supposed to work?
The simplest solution that i can think is to call through ajax a php page that should only instantiate a new object of the right class and then make an echo on the result of a simple call with the data received but this doesn't look very oo...
For example to implement the register function I should make an ajax call to a register.php web page that, in turn, will instantiate a new Registration object r and then simply calls r.register() with the right data.
Is there a better solution to this problem?
I want specify that I can't use any php framework because it's a didactic project and I have this rule that I should respect.
Another specification: I've read a lot of tutorials that describe how to write your own mvc framework but doing this seems to be an overkill for my problem.
Thank you for your help, every idea will be appreciated.
As you already said you don't really need a PHP framework and don't need to build your own MVC implementation
(especially if you are e.g. working with JSON or XML).
Basically you are pretty free on how to do your OO model, so your idea is not necessarily wrong.
Some OO anti patterns I have seen people using in PHP:
Use global variables in classes
Create classes without member
variables resulting in method calls
being the same as in a produral style
Directly accessing $_GET, $_POST etc.
in a class
Echoing html output (imho this should
be done in view templates)
An example for what you might want to do for the registering process processing some $_POST variables
and returning a JSON success message:
<?php
class Registration
{
private $_data;
public function __construct($registrationdata)
{
$this->_data = $registrationdata;
}
public function validate()
{
// ...
}
public function register()
{
// ...
if($this->validate())
return array("registered" => true, "username" => $this->_data["username"],
"message" => "Thank you for registering");
else
return array("registered" => false, "username" => $this->_data["username"],
"message" => "Duplicate username");
}
}
$reg = new Registration($_POST);
echo json_encode($reg->register());
?>
There is no reason to create any classes if all you are doing is calling a couple of unrelated stateless php functions.

Can CakePHP's testAction method survive a redirect call?

I'm starting to write unit tests using the CakePHP framework and SimpleTest. The documentation describes a problem with the testAction method when your controller redirects the browser to another page. There is a hopeful note with a link to a possible fix, but the link is broken.
Has anybody gotten this working? Know how to find where that broken link should point?
I found a discussion of using partial mock objects to override the redirect call, but that doesn't seem to work with the testAction method. I suspect I'd have to somehow register the mock controller with the dispatcher.
Here's a similar question on Google groups.
I got something to work, so I thought I'd post it here. I'm not sure if I'm happy with it yet.
If you want to be able to test a redirect, change this:
$this->redirect(array('action'=>'index'));
to this:
$this->redirect(array('action'=>'index'), null, false);
return 'redirected to index';
Now your test can look something like this:
$data = array(...);
$result = $this->testAction(
'/people/edit/1',
array('method' => 'post', 'data' => $data));
$this->assertEqual(
'redirected to index',
$result);
The problem with the controller's redirect method is that it calls exit() by default, and that exits out of the entire test suite. This version passes false to the redirect method's $exit parameter, and then uses return instead of exit(). The return value is just something for the test case to validate if you like, although it is echoed to the browser along with the redirect header. As long as it's a small message, though, I don't see any problem with that.
There doesn't seem to be any significant code that might execute after the controller method when we call return instead of exit(). A quick test shows that the page behaves normally.

Categories