Slim framework: Display an error page using Twig - error-handling

I would like to display a custom view (using twig view) on production when there's something going wrong with my slim3 application.
I read the documentation concerning error handling but I cannot get the handler to display a twig view.
So this is working (displaying the error message in my browser):
if ('development' !== $container->get('settings')['environment']) {
$container['errorHandler'] = function($c) {
return function ($request, $response, $exception) use ($c) {
$c->get('logger')->critical("An error occured", [$exception->getMessage()]);
return $response->write('An error occurred (message: "' . $exception->getMessage(). '").');
};
};
}
but this is not working, ie. it's not displaying the view using the template (instead I get a blank page in my browser):
if ('development' !== $container->get('settings')['environment']) {
$container['errorHandler'] = function($c) {
return function ($request, $response, $exception) use ($c) {
$exceptionMessage = $exception->getMessage();
$settings = $c->get('settings');
$view = $c->get('view');
$data = [
'app' => $settings['app'],
'title' => 'Error',
'exceptionMessage' => $exceptionMessage
];
$c->get('logger')->critical("An error occured", [$exception->getMessage()]);
return $view->render($response, '500.twig', $data);
};
};
}
I really don't get why it's not working. Any ideas?

The error handler cannot catch all errors. PHP Fatal errors and syntax errors it will not catch because of the way PHP deals with Fatal/Parsing errors. Unfortunately there is no way to deal with those types of errors in PHP. An example could be a syntax error or out of memory error. Neither is recoverable

Just to add an observation,
to make twig render anything usually you echo $view->render ...

Related

How can I bind to an array on my input using Vuetify/Vue.js?

I am using Vuetify.js on a project and everything is working very well. I am trying to add some custom error messages to my username input. For example, if a user trying to sign in is not found - I want to display that message.
I am able to pass a single value using :error-messages="errors.myMessage. Works great!
However, I'd like to set multiple values to that error message. For example, if:
The user is not found
The user does not have permission
???
Here is what I am doing that works:
...
type="email"
:error-messages="errors.userNotFoundException"
v-model="form.username"
...
According to the Vuetifyjs docs, I can pass a string or an array to :error-messages. Looking through the playground, I've tried this:
...
type="email"
:error-messages="[errors.userNotFoundException, errors.notAuthorizedException]"
v-model="form.username"
...
However, when the page renders, the username field is showing as invalid & no errors are showing. Ideally, I'd like to show different messages based on the error that is returned on the same input. An array make sense here...
To set the values, I am doing this based on my Axios response:
data() {
return {
errors: {
notAuthorizedException: '',
userNotFoundException: '',
},
},
...
.catch(error => {
console.log("error: ", error);
if (error.code === 'NotAuthorizedException') {
this.errors.userNotFoundException = error.message;
}
...
What is the correct way to show multiple message(s) for the same input? Thank you for any suggestions!
I believe a single error message is the way to go. You can simply change it based on what the axios error is.
type="email"
:error-messages="loginError"
js:
data() {
return {
loginError: ''
}
},
...
.catch(error => {
console.log("error: ", error);
this.loginError = error;
...

Vue.js error: Cannot read property 'filter' of undefined

Im building an app to consume a json and list it with a search filter input and other stuffs
I've already tried to create the function but didnt work
{
produtoFiltrado:function()
{
var self=this;
return this.produtos.filter(function(cust){
return cust.nome.toLowerCase().indexOf(self.search.toLowerCase())>=0;
});
}
}
Its showing this error: Cannot read property 'filter' of undefined
Here is the codesandbox url:
https://codesandbox.io/s/vue-template-7iev3?fontsize=14
I've fixed with the declaration of array
produtos: [ { all-stuffs-here } ]
The brackets were missing
But now its showing this error:
Cannot read property 'search' of undefined

Pouchdb query() leaving out documents on emit()

For some reason my filter is not working correctly. It was working fine a moment ago and then for some reason it stopped returning all of the templates and only started returning one of them.
Why might it be returning it twice but only giving me one?
I have the following code:
export async function testMe() {
const company_id = await AsyncStorage.getItem('company_id');
const device_db = new PouchDB(company_id, {});
device_db.query(function(doc, emit){
console.log(doc.type, doc._id, doc._rev);
if(doc.type == 'template') {
emit(doc._id, doc);
}
}).then((result) => {
console.log("Returned", result);
})
}
What is unexpectedly happening is this is what gets returned:
template template_1 18-5918af4c5370d9755d0bb8b6dcb21ea1
template template_2 19-8191dec49dfa8c1a2f03d752a193f09e
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
undefined "dpbcab6843-2cdf-4d4c-87ae-286dcddaac22" "2-8f03f3127771dadd3c8f7beb3e827982"
undefined "dpdc6f6cd0-6c6d-4974-a166-b848a0217af4" "2-0eec1a8d925641aa8bf30e058e6515e7"
undefined "dpe1573a70-a281-4e15-a997-82d8bf8fabfa" "2-d3bbcb81344f61cc94459610695c6670"
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
You can ignore the undefined, but what I am trying to show is look at what gets returned twice:
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
In the Returned console.log(), this is the only thing that gets returned (the last template_3 piece of data, totally ignoring the other templates even though they are both type template):
{"total_rows":6,"offset":0,"rows":[{"key":"template_3","id":"template_3","value":{..}}]}
Edit
It's getting even weirder. I just opened template_2 and did a save (in Cloudant) and synced it with my device to update the _rev and now I get:
template template_1 18-5918af4c5370d9755d0bb8b6dcb21ea1
template template_2 20-c549fe868735ef0099b80f6668af611c
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
undefined "dpbcab6843-2cdf-4d4c-87ae-286dcddaac22" "2-8f03f3127771dadd3c8f7beb3e827982"
undefined "dpdc6f6cd0-6c6d-4974-a166-b848a0217af4" "2-0eec1a8d925641aa8bf30e058e6515e7"
undefined "dpe1573a70-a281-4e15-a997-82d8bf8fabfa" "2-d3bbcb81344f61cc94459610695c6670"
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
template template_2 20-c549fe868735ef0099b80f6668af611c
Which returns (leaving out template_3):
{"total_rows":6,"offset":0,"rows":[{"key":"template_2","id":"template_2","value":{..}}]}
Edit 2
I added:
.catch((err) => {
console.log(err);
})
And get this: {"status":409,"name":"conflict","message":"Document update conflict","error":true}
However, I do the following an all _conflict arrays are empty:
device_db.allDocs({conflicts: true})
.then((data) => {
for (let d of data.rows) {
console.log(d.doc._conflicts);
}
});
I believe temporary queries like this should have a key, otherwise the query would not know what documents you want to select. The example from the PouchDb docs is
db.query(function (doc, emit) {
emit(doc.name);
}, {key: 'foo'}).then(function (result) {
// found docs with name === 'foo'
}).catch(function (err) {
// handle any errors
});
so that documents with a "name" field equal to "foo" are returned by the query. In your query the key appears to be undefined. This might explain the odd results you are getting?

"Controller method not found." Laravel error. How can I figure out what method was called that it couldn't find?

I started using Laravel a month ago. Trying to make a page with one form on it and I keep getting a "Controller method not found." error. There is only one form on the page and that method is being called fine and making the query that I want. It does redirect to the same page with that form, /dashboard/edit/module.
It would be awesome if I could see what method is not being found or where it is in my code. Any ideas how I can do this? Someone mentioned App::error or messing with Log::error in global.php but I can't get any more information shown.
Edit:
I found that the form action is only being found if I upload a video to the form. Other then that it gives me the same error. Here is the controller method of this form. The page with this form is /dashboard/edit/module and I would like to reload that page after this runs.
public function postSection(){
$path = public_path() . "/videos/";
$filename = uniqid() . '.mp4';
$file_path = $path . $filename;
$moduleID = Input::get('moduleID');
if(!Input::hasFile('video')){
return Redirect::back()->with('error', 'Must enter a valid video file.');
}else{
try {
Input::file('video')->move($path, $filename);
$section = New Section;
$section->module_id = $moduleID;
$section->video = $file_path;
$section->save();
//I was trying to use this instead of View::make to stop form resubmission
//return Redirect::to('/dashboard/edit/module')->with('moduleID', $moduleID);
return View::make('forms.editMod')->with('moduleID', $moduleID);
}catch ( Exception $e){
return Redirect::back()->with('error', 'Unable to save the video file.');
}
}
}
Edit: And my routes.php
//Route for the home page
Route::get('/', function(){ return View::make('home'); });
//Controllers
Route::controller('dashboard/edit', "ContentController");
Route::controller('user', "UserController");
Route::group(array('before'=> 'auth|dash'), function(){
//dashboard home
Route::get('/dashboard', function(){ return View::make('dashboard');});
//dashboard subs
Route::get('dashboard/modules', function(){ return View::make('forms.module');});
Route::get('dashboard/users', function(){ return View::make('users');});
Route::get('dashboard/reporting', function(){ return View::make('reporting');});
//user pages
Route::get('dashboard/register', function(){ return View::make('forms.register');});
Route::post('dashboard/edit/user', array('before'=>'csrfajax', function(){
$id = Input::get('userID');
$user = User::find($id);
return View::make('forms.editUser')->with('user', $user);
}));
});
And the form...
{{ Form::open(array('files' => true, 'action' => 'ContentController#postSection', 'id' => 'sectionform')) }}
<fieldset>
{{ Form::label('Video (mp4)') }}
{{ Form::hidden('moduleID', $module->id)}}
{{ Form::file('video', array('id' => 'video', 'class' => 'form-control')) }}<br>
{{ Form::submit('Save') }}
</fieldset>
{{ Form::close() }}
In routes.php, to reach this method you're using Route::controller, which results in RESTful routing. If the browser's HTTP request used the POST action, you'd correctly be routed to public function postSection(){}. But if the HTTP request used GET, which is the default for web browsing, especially when no data is being submitted by the browser, Laravel would be looking for a method called public function getSection(){}. This would explain why when you're uploading something (i.e. using POST), you reach the page, but otherwise you don't.
See the official documentation for the full low-down on implicit routing: http://laravel.com/docs/controllers#implicit-controllers

why using viewSimple renderer in Phalcon corrupts main renderer

First I declare simple view like this:
$di->set('viewSimple', function() {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
".volt" => 'volt'
));
return $view;
});
then to generate html email, I use it as following:
public function renderHTMLEmail($template_name, $template_params) {
$content = $this->viewSimple->render("emails/$template_name", $template_params);
return $this->viewSimple->render("emails/master", array( 'content' => $content) );
}
My emails are being generated just fine, but whenever I call my renderHTMLEmail function actual page rendering is somehow corrupted and page appears totally blank (I have to use redirect as workaround). This is a mystery to me as main view renderer is completely different object. Can I prevent this?
Or does anybody have recommended method of generating arbitrary pieces of html outside of main view rendering process which would not interfere with it? There is couple of similar questions on SO, but none of solutions work. They either don't generate my email or they corrupt main view.
Found a solution, when registering the "\Phalcon\Mvc\View\Simple" component into the DI container make sure to use a new volt instance otherwise it will join up with the application's \Phalcon\Mvc\View volt instance somehow. This is what lot (https://stackoverflow.com/users/1672165/lot) was suggesting in the comments.
Code sample:
public function getTemplate($name, $params)
{
$parameters = array_merge(array(
'publicUrl' => $this->getDI()->getApp()->url->host . $this->getDI()->getApp()->url->baseUri
), $params);
$app = $this->getDI()->getApp();
$this->getDI()->set('simpleView', function() use ($app) {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir(APP_DIR . $app->application->viewsDir);
$view->registerEngines(array(
".volt" => function ($view, $di) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$volt->setOptions(array(
'compiledPath' => APP_DIR . '/cache/volt/',
'compiledSeparator' => '_',
'compiledExtension' => '.compiled'
));
$compiler = $volt->getCompiler();
$compiler->addFunction('is_a', 'is_a');
return $volt;
}
));
return $view;
});
/* #var $simpleView \Phalcon\Mvc\View\Simple */
$simpleView = $this->getDI()->get('simpleView');
foreach ($parameters as $key => $value) {
$simpleView->{$key} = $value;
}
$html = $simpleView->render('emails/' . $name, $parameters);
return $html;
}
Sample was pulled straight from our working app so may need some re-working but should help solve the original issue.
This works for me using \View as the application DI registered view component which renders controller action volt views and the above \View\Simple with fresh volt registration successfully emails and allows the original view with volt to carry on.
This was asked a while ago however i've not seen a working solution anywhere else.
For completeness I've registered a github issue with the findings: https://github.com/phalcon/cphalcon/issues/3096
I recently had to deal with a similar problem, I'm not certain where you're falling short, but one important thing was to use a separate view from the one used by the application – you're already doing this. See if the following works.
protected function renderView($view, $template, array $data = null)
{
return $view
->reset()
->pick('emails/' . $template)
->setVars($data)
->start()
->render(null, null)
->finish()
->getContent();
}
public function renderHTMLEmail($template_name, $template_params)
{
$content = $this->render($template_name, $template_params);
return $this->render('master', array('content' => $content));
}