In my controller I throw a 404 response after an If statement, something like that :
if ($foo) {
$this->getResponse()->setStatusCode(404);
return;
}
Then, I would like to send some variables to my 404 page. In my mind, I want to do something like that :
$this->getResponse()->setVariables(array('foo' => 'bar', 'baz' => 'bop'));
$this->getResponse()->setStatusCode(404);
return;
It's not the good solution, so how I have to do that ?
And after, how to get these variables in my 404 view ?
Thank you
Oh god..
I was so dumb
Solution :
if ($foo) {
$this->getResponse()->setStatusCode(404);
return array('myvar' => 'test');
}
In 404.phtml :
<?php echo $this->myvar; ?>
I've come to this question from Google and my issue was a bit more difficult. Since 404 error could be thrown from absolutely unpredictable url, you can't be sure you catched it in some controller. Controller – is too late to catch 404 error.
The solution in my case was to catch an EVENT_DISPATCH_ERROR and totally rebuild viewModel. Cavern is that layout – is a root viewModel, and content appended into layout by default is another viewModel (child). These points are not such clear described in official docs.
Here is how it can look like in your Module.php:
public function onBootstrap(MvcEvent $event)
{
$app = $event->getParam( 'application' );
$eventManager = $app->getEventManager();
/** attach Front layout for 404 errors */
$eventManager->attach( MvcEvent::EVENT_DISPATCH_ERROR, function( MvcEvent $event ){
/** here you can retrieve anything from your serviceManager */
$serviceManager = $event->getApplication()->getServiceManager();
$someVar = $serviceManager->get( 'Some\Factory' )->getSomeValue();
/** here you redefine layout used to publish an error */
$layout = $serviceManager->get( 'viewManager' )->getViewModel();
$layout->setTemplate( 'layout/start' );
/** here you redefine template used to the error exactly and pass custom variable into ViewModel */
$viewModel = $event->getResult();
$viewModel->setVariables( array( 'someVar' => $someVar ) )
->setTemplate( 'error/404' );
});
}
Related
I want to create a maintenance Page for my cake website by checking a Database Table for a maintenance flag using a sub-function of my AppController "initilize()" method. If the flag is set, i throw my custom MaintenanceException(Currently containing nothing special):
class MaintenanceException extends Exception{
}
To handle it, I implemented a custom App Exception Renderer:
class AppExceptionRenderer extends ExceptionRenderer {
public function maintenance($error)
{
return "MAINTENANCE";
}
}
I am able to see this maintenance Text on my website if I set my DB flag to true, but I could not find any information in cake's error handling documentation (http://book.cakephp.org/3.0/en/development/errors.html) on how I can actually tell the Exception renderer to render view "maintenance" with Template "infopage".
Can I even us that function using the ExceptionRenderer without a custom error controller? And If not, how should a proper ErrorController implementation look like? I already tried this:
class AppExceptionRenderer extends ExceptionRenderer {
protected function _getController(){
return new ErrorController();
}
public function maintenance($error)
{
return $this->_getController()->maintenanceAction();
}
}
together with:
class ErrorController extends Controller {
public function __construct($request = null, $response = null) {
parent::__construct($request, $response);
if (count(Router::extensions()) &&
!isset($this->RequestHandler)
) {
$this->loadComponent('RequestHandler');
}
$eventManager = $this->eventManager();
if (isset($this->Auth)) {
$eventManager->detach($this->Auth);
}
if (isset($this->Security)) {
$eventManager->detach($this->Security);
}
$this->viewPath = 'Error';
}
public function maintenanceAction(){
return $this->render('maintenance','infopage');
}
}
But this only throws NullPointerExceptions and a fatal error. I am really dissapointed by the cake manual as well, because the code examples there are nowhere close to give me an impression of how anything could be done and what functionality I actually have.
Because I had some more time today, I spent an hour digging into the cake Source and found a solution that works well for me (and is propably the way it should be done, altough the cake documentation does not really give a hint):
Step 1: Override the _template(...)-Method of the ExceptionRenderer in your own class. In my case, I copied the Method of the parent and added the following Code at the beginning of the method:
$isMaintenanceException = $exception instanceof MaintenanceException;
if($isMaintenanceException){
$template = 'maintenance';
return $this->template = $template;
}
This tells our Renderer, that the error Template called "maintentance"(which should be located in Folder: /Error) is the Error Page content it should render.
Step 2: The only thing we have to do now (And its is kinda hacky in my opinion, but proposed by the cake documentation in this exact way) is to set the layout param in our template to the name of the base layout we want to render with. So just add the following code on top of your error template:
$this->layout = "infopage";
The error controller I created is actually not even needed with this approach, and I still don't know how the cake error controller actually works. maybe I will dig into this if I have more time, but for the moment.
uploading images has been causing much trouble. I'm always having two problems. First it always fail to upload or unable to find the files when using asset manager when it is there in the folder!! So when my controller says unlink the file, it won't unlink anything. Second, it'll show failed to set unsafe attribute when my rules are set to safe.
Here is my rule:
array('product_image,product_gallery_1, product_gallery_2, product_gallery_3, product_gallery_4, product_gallery_5, product_gallery_6', 'file','types'=>'jpg, jpeg, gif, png','allowEmpty'=>true, 'on'=>'update', 'safe'=>true),
on view I do have
'htmlOptions'=>array('enctype'=>'multipart/form-data'),
Here's a section on update controller. It does upload multiple images:
public function actionUpdate($id)
{
$model=$this->loadModel($id);
$old_img = $model->product_image;
if(isset($_POST['Product']))
{
$model->update_date = time();
$model->product_approval_status = "N";
$t_product_image = $model->product_image;
$model->attributes=$_POST['Product'];
$product_image=CUploadedFile::getInstance($model,'product_image');
$storeid = $model->store_id;
$date = date('mdy');
$rnd = rand(0,9999);
$f_product_image = "{$rnd}-{$date}{$storeid}-{$product_image}";
//main img
if(!empty($product_image))
{
$model->product_image = $f_product_image;
}
else
{
if(file_exists(Yii::app()->basePath.'/images/shop/thumbnail/thumb_'.$model->product_image))
unlink(Yii::app()->basePath.'/images/shop/thumbnail/thumb_'.$old_img);
if(file_exists(Yii::app()->basePath.'/images/shop/product/'.$model->product_image)&& ($old_img !==null))
unlink(Yii::app()->basePath.'/images/shop/thumbnail/'.$old_img);
$model->product_image = $t_product_image;
}
if($model->save())
{
$url = Yii::app()->basePath.'/images/shop/product/';
$thumb = Yii::app()->basePath.'/images/shop/thumbnail/';
if(!empty($product_image))
{
$product_image->saveAs($url.$f_product_image);
$this->createThumb($url.$f_product_image, $thumb.'thumb_' . $f_product_image);
}
$this->redirect(array('submitted'));
}
}
$this->render('update',array(
'model'=>$model,
));
}
The problem is with your current defined scenario
In your model, you specify the attributes safe under the update scenario.
array('product_image, ..., product_gallery_6', ... 'on'=>'update', 'safe'=>true)
Therefore, in your controller, you need to set the scenario.
$model = new MyActiveRecord('update');
Since you are using a function you may not have control over, you can explicitly set this:
$model->scenario = 'update';
Note that your problem might be elsewhere, depending on the operation of loadModule(), because ceratin ActiveRecord scenarios are automatically loaded. See the section 'CActiveRecord scenarios' in the linked page.
I am trying to implement memcache into my application, but I am running into some strange issues. If I run find() when there is no cache, then I get no results found. However, if I run the same query (refresh the page), then I get the results I expect.
Here is my code:
<?php
//Set the models cache service
$di->set('modelsCache', function(){
// Cache data for one day by default
$frontCache = new \Phalcon\Cache\Frontend\Data(array(
"lifetime" => 86400
));
// Memcached connection settings
$cache = new \Phalcon\Cache\Backend\Memcache($frontCache, array(
"host" => "localhost",
"port" => "11211"
));
return $cache;
});
<?php
class VideosController extends IndexController {
public function viewAction() {
/**
* This will always return an array;
* param 0 will always be the int
*/
$params = $this->dispatcher->getParams();
$id = $params[0];
$cacheName = 'videoForView_'.$id;
try {
$video = Videos::findFirst(array(
'id='.$id,
'cache' => array(
'key' => $this->router->getControllerName().'_'.$this->router->getActionName().'_'.$id
)
));
$this->view->setVar('video', $video);
} catch(Exception $e) {
echo '<pre>';
var_dump($e);
exit;
}
}
}
I am under the assumption that the Phalcon Model class would return me a database query, if there is no hit in the memcache server. It seems that the find() does find something and caches it, but it does not return me anything. Am I not understanding how the caching works in Phalcon? Or am I just doing something wrong?
The issue has been resolved. I worked with Andres (one of the developers of Phalcon), helping him resolve the issues I was having. Turns out it was deeper in the code than I would've expected.
The good news is it's resolved, and pushed up to the 0.8.0 branch on phalcon's github! Don't forget to recompile!
I am currently trying to configure a routing option in Symfony2 so /cms will route to /cms/role/view. However, the passing of defaults doesn't seem to work properly.
/src/MyProject/CMSBundle/Resources/config/routing.yml
MyProjectCMS_specific:
pattern: /cms/{page}/{option}
defaults: { _controller: MyProjectCMSBundle:Main:index, page: role, option: view }
requirements:
_method: GET
/src/MyProject/CMSBundle/Controller/MainController.php
<?php
namespace MyProject\CMSBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class MainController extends Controller
{
public function indexAction($page, $option)
{
$response = null;
/* Switch statement that determines the page to be loaded. */
return $response;
}
}
?>
The problem is that when I try to go to `localhost/app_dev.php/cms', it gives me the following error:
Controller "MyProject\CMSBundle\Controller\MainController::indexAction()" requires that you provide a value for the "$page" argument (because there is no default value or because there is a non optional argument after this one).
500 Internal Server Error - RuntimeException
However, if I try to visit localhost/app_dev.php/cms/role or localhost/app_dev.php/cms/role/view, it gives me the correct page. I've tried adding a default route to /cms, but it still gives me the same error. How is this possible and how can I fix this?
Thanks in advance.
I don't know what is the difference between what you wrote and
public function indexAction($page = "role", $option = "view")
but maybe you could try it and tell us.
I'm trying to load, edit and save a record with CakePHP 2.0 but I get a generic error during the save method that don't help me to understand where is the problem.
if I try with debug($this->User->invalidFields()); I get an empty array, but I get false from $this->User->save() condition.
Here is the controller action where I get the error:
public function activate ($code = false) {
if (!empty ($code)) {
// if I printr $user I get the right user
$user = $this->User->find('first', array('activation_key' => $code));
if (!empty($user)) {
$this->User->set(array (
'activation_key' => null,
'active' => 1
));
if ($this->User->save()) {
$this->render('activation_successful');
} else {
// I get this error
$this->set('status', 'Save error message');
$this->set('user_data', $user);
$this->render('activation_fail');
}
debug($this->User->invalidFields());
} else {
$this->set('status', 'Account not found for this key');
$this->render('activation_fail');
}
} else {
$this->set('status', 'Empty key');
$this->render('activation_fail');
}
}
When I try the action test.com/users/activate/hashedkey I get the activation_fail template page with Save error message message.
If I printr the $user var I get the right user from cake's find method.
Where I'm wrong?
I think the problem may be in the way you're querying for the User record. When you do this:
$user = $this->User->find('first', array('activation_key' => $code));
The variable $user is populated with the User record as an array. You check to ensure it's not empty, then proceed; but the problem is that $this->User hasn't been populated. I think if you tried debug($this->User->id) it would be empty. The read() method works the way you're thinking.
You could try using the ID from that $user array to set the Model ID first, like so:
if (!empty($user)) {
$this->User->id = $user['User']['id']; // ensure the Model has the ID to use
$this->User->set(array (
'activation_key' => null,
'active' => 1
));
if ($this->User->save()) {
...
Edit: Well another possible approach is to use the $user array instead of modifying the current model. You said that you get back a valid user if you debug($user), so if that's true you can do something like this:
if (!empty($user)) {
$user['User']['activation_key'] = null;
$user['User']['active'] = 1;
if ($this->User->save($user)) {
...
This method works in the same way as receiving form data from $this->request->data, and is described on the Saving Your Data part of the book.
I'm curious though if there's another part of your setup that's getting in the way. Can other parts of your app write to the database properly? You should also check to make sure you aren't having validation errors, like their example:
<?php
if ($this->Recipe->save($this->request->data)) {
// handle the success.
}
debug($this->Recipe->validationErrors);