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.
Related
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.
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.
In PHP/Kohana, I have controller action method which does some processing. When it is finished, I want to send it to another controller, e.g.:
public function action_import_csv()
{
Kohana_Import_Driver_Csv::process_files_from_csv_to_mysql($this->import_directory);
//url::redirect(Route::get('backend_application')->uri()); //undefined method URL::redirect()
//redirect(Route::get('backend_application')->uri(), null); //undefined function
}
According to this documentation at least the first redirect should work. I'm using Kohana 3.
How can I send execution from this controller action method to a new controller/action?
Addendum
For some reason, url::redirect is not available, here is the code completion I get for url:::
#bharath, I tried url::current() and got this error:
The problem is that you are looking at the Kohana 2 docs. Go to the kohana homepage and find the correct docs. Also, for some reason, everyone is giving you Kohana 2 answers even though you stated you're working with 3.
To redirect, do this from the context of a controller:
$this->request->redirect($something);
$something could be:
controller
controller/action
http://url.com
Here are the api docs for the redirect method (note that this uses url::site to parse the url; you may want to look at the source of that method too.
i am not very sure but i think you can simple use the redirect() function passing in the other controller you want to send to with any parameters
example
redirect(controllername/method)
Shouldn't that be :
url::redirect('controller/method');
And if it doesn't work, you probably had some output before calling the redirect (you'll probably get the "Headers already sent" error when that is the case).
In a PHP MVC framework, how can I cleanly and elegantly exit from the current controller/action, but continue normal script execution?
For example, let's say my framework normally follows this outline:
Map URL to Controller/Action
Instantiate Controller, call Action (capturing output)
Do stuff
Render View
At end of Action method, continue normal operation
Process output if necessary
Send output to browser
Now, let's say I want to stop "normal" execution somewhere in the "Do Stuff" step to, say, render a different view, or do a header redirect, and I want to stop processing the rest of the body of the Action, but continue onto the "Process output" step
How can I achieve this the best way? My only ideas are:
//in controller
protected function redirect($url) {
header("Location: $url");
exit();
}
but this entirely skips the rest of the framework's execution, and dumps whatever was in the output buffer straight to the user. An alternative:
//in dispatcher
call_user_func_array(array($controller,$action),$params);
afterwards:
...
//in controller
protected function redirect($url) {
header("Location: $url");
goto afterwards;
}
However, this makes me twitch and goes against everything I've learned, especially because the label it's referencing is in another file completely.
So, is there any other way to achieve this?
Note: The redirect example probably should use the exit() way, because we're just redirecting to another page anyway and don't care about output. I'm looking for a general-use solution.
In your Action method, you can collect all of your output in a string rather than printing it out. Print it out only at the end of the method. If you need to redirect or bail out, then you haven't output anything yet and you can either redirect or return from the method.
Perhaps you could write a custom exception to represent a "Stop normal execution in the 'Do Stuff'" step? It's messy... but it would work.
you need to abstract much more things. dont just output inside a action! dont set headers as there can go so much wrong before. have different handlers. response handler. handle respons and act depending what you respond. dont just output inside actions. if you have errors throw exceptions catch them with a exceptionhadler and so on.
basic controller action
public function view(int $user_id): ResponseHandler {
$this->validate($user_id); //throws exception
if (1 == 2) throw new ControllerInvalidArgumentException();
$view = new View('nameof view');
return new ResponseHandler($view);
}
just have a look at existing frameworks they have very good implemntations of design patterns like laravel or symfony. not sure what you try just dont write your own framework. if you want to learn read and learn from others if you understand whyt they do you will know how to do.
How could I send additional view parameters after I have done a redirect (e.g. $this->_redirect->gotoSimple();)?
For example, let's say I have an Edit action which will redirect the user to an Error action handler and I would like to be able to send custom, detailed error messages to its view. To illustrate it clearer, the flow would be:
At the Edit view (say, http://localhost/product/edit), the user submits something nasty
At editAction(), a fail check triggers a redirect to my Error view/action handler (so that my URL would read like http://localhost/error/index)
The Error/index.phtml takes a "errorMessage" view variable to display the custom error message, and editAction() needs a means to pass in some value to that "errorMessage" view variable
A quick code snippet would probably look like:
public function editAction() {
//DO THINGS...
// Upon failure
if($fail) {
$this->_redirector->gotoUrl('/error/index');
//TODO: I need to be able to do something like
// $errorView->errorMessage = "Generic error";
}
}
Any solutions, or even other better ways of achieving this, is greatly appreciated.
Don't use gotoURL() for internal redirects. Use gotoSimple(). I takes up to 4 parameters:
gotoSimple($action,
$controller = null,
$module = null,
array $params = array())
In your case it's going to be:
$this->_redirector->gotoSimple('index',
'error',
null,
array('errorMessage'=>$errMsg));
See Redirector Zend_Controller_Action_Helper for details.
I have not seen anywhere that an action (editAction) accesses another action's view (errorView). for the special case of error handling, my idea is using Exceptions. you throw different exceptions for different bad situations, and in your error handler action, you can decide what to show to user based on the exception type:
// file: ProductContorller.php
public function editAction() {
// some code
if ($badThing) {
throw new Exception('describe the bad thing',$errorCode);
}
if ($badThing2) {
throw new Exception('describe the other bad thing',$errorCode2);
}
}
// file: ErrorController.php
public function errorAction() {
$error = $this->_getParam('error_handler');
$exception = $error->exception; // the original Exception object thrown by some code
$code = $exception->getCode();
switch ($code ) {
// decide different things for different errors
}
}
for more information about error handling, the Zend Framework quick start is a great tutorial.
for other situations, you can use some messaging mechanism to communicate between these 2 actions. using flashMessenger action helper is the first thing comes into my mind:
// file: ProductContorller.php
public function editAction() {
// some code
if ($badThing) {
$this->_helper->flashMessenger->addMessage('error1');
$this->_redirect('error');
}
if ($badThing2) {
$this->_helper->flashMessenger->addMessage('error2');
$this->_redirect('error');
}
}
// file: ErrorController.php
public function errorAction() {
$errors = $this->_helper->flashmessenger->getMessages();
if ( in_array('error1',$errors) ) {
// do something
} // elseif ( ...
}
although remember that flashMessenger uses sessions, so sessions and most likely cookies are going to be involved in this messaging process.
The standard way of doing this is with a session-based store of a message you wish to display. It's common enough that there is a view-based helper, FlashMessenger.
The FlashMessenger helper allows you
to pass messages that the user may
need to see on the next request. To
accomplish this, FlashMessenger uses
Zend_Session_Namespace to store
messages for future or next request
retrieval. It is generally a good idea
that if you plan on using Zend_Session
or Zend_Session_Namespace, that you
initialize with Zend_Session::start()
in your bootstrap file. (See the
Zend_Session documentation for more
details on its usage.)
go through this link.. it explains how can we set view variables before _redirect
http://www.rmauger.co.uk/2009/06/creating-simple-extendible-crud-using-zend-framework/
I'll add this to give some more info on how the FlashMessenger class works ( I had some issues figuring it out).
I read somewhere that a session should be started in Bootstrap.php using
Zend_Session::start();
..but my code worked without that, so I suspect sessions are already started.
We're in a controller-object and an action-method is being called. Then something happens, like an insert or an edit into the database, anything really.
We now set one or more messages. I use the following syntax.
$this->_helper->FlashMessenger("Message in a bottle.");
Which is exactly the same as using
$this->_helper->FlashMessenger->addMessage("Message in a bottle.");
This sets a message in the session, you can check that directly by calling
print_r($this->_helper->FlashMessenger->getMessages());
die();
Now there's a redirect to a new url (so a new request basically), inside the controller+action that is handling the request we'll add the messages to the view like so:
$this->view->flashMessages = $this->_helper->FlashMessenger->getMessages();
We now have a choice of where to output these messages. We can do this inside a view that "belongs to" a certain controller, so that could be
views/scripts/index/index.phtml
The drawback here is that you'd have to add the code outputting the messages to every viewscript that uses it. That's not very DRY.
In my eyes a superior solution is the following. Output these messages at in the file where you define the basic layout of your application. That's probably
layouts/scripts/index.phtml
I wrote the following code there.
<?php if( isset($this->flashMessages) && !empty($this->flashMessages) ){ ?>
<ul id="messages">
<?php foreach( $this->flashMessages as $message ){?>
<li>
<?php echo $message;?>
</li>
<?php } ?>
</ul>
<?php } ?>