How to change the behavior of the beforeAction? - yii2

There is a beforeAction() in Controller.php
public function beforeAction($action)
{
if (parent::beforeAction($action)) {
if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) {
throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.'));
}
return true;
}
return false;
}
It throws an exception but I want to change this in my own controller which extends controller.php. I try something like that
public function beforeAction($action) {
if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) {
Yii::$app->session->setFlash('info', 'Error');
$this->goBack();
}
return parent::beforeAction($action);
}
But it still shows exception.

Not sure but it might work with just changing this row...
$this->goBack();
into...
return $this->goBack();
Another approach would be to catch the Exception from the parent instead. Later there might be other events triggered by beforeAction and if not calling the parent::beforeAction these may not be run as intended.

Related

Laravel 8 Handler Undefined class 'Exception'

I work in API Laravel project and try to handler
"message": "No query results for model ID"
and page 404
I use this function but don't send anything in API and no effect on 404 pages
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class Handler extends ExceptionHandler
{
public function render($request, Exception $e)
{
// "message": "No query results for model ID" in API
if ($e instanceof ModelNotFoundException) {
return response()->json(['error' => 'Data not found.']);
}
if($this->isHttpException($e))
{
switch ($e->getStatusCode())
{
// not found
case 404:
return redirect()->guest('home');
break;
// internal error
case '500':
return redirect()->guest('home');
break;
default:
return $this->renderHttpException($e);
break;
}
}
else
{
return parent::render($request, $e);
}
}
}
Use Throwable not Exception
public function render($request, Throwable $e)
{
// "message": "No query results for model ID" in API
if ($e instanceof ModelNotFoundException) {
return response()->json(['error' => 'Data not found.']);
}
return parent::render($request, $e);
}

DNN API Controller - A task was canceled Log

We have an JQuery Ajax call that will execute when a user is about to leave a page on a DNN module.
This error is being logged the whole time in the DNN logs.
How can I improve the error handling so that it doesn't log the whole time?
Here is the DNN log:
Here is the Front End Code on the Module :
$(window).on("beforeunload", function () {
ClearTempUserSessionWhenLeavePage();
});
function ClearTempUserSessionWhenLeavePage() {
if ($fromButtonEvent == false) {
var Url = $.fn.GetBaseURL() + 'DesktopModules/DNNCommon/API/Store/ClearTempUserSessionWhenLeavePage';
$.ajax({
url: Url,
type: 'GET',
async: true,
dataType: 'json',
success: function () {
},
error: function (x, y, z) {
}
}).promise().done(function () {
});
}
$fromButtonEvent = false;
}
We are inheriting the DNNApiController class on our DNNCommon class.
This is the C# method being called:
[AllowAnonymous]
[HttpGet]
public void ClearTempUserSessionWhenLeavePage()
{
if (SessionManager.GetSessionObject("NewCreatedWebUser") != null)
{
System.Web.HttpContext.Current.Session["DoNotRemoveSessionIfNotAuthenticated"] = false;
SessionManager.SetSessionObject("NewCreatedWebUser", null);
SessionManager.SetSessionObject("UserInfo", null);
SessionManager.SetSessionObject("NewCustomerCode", null);
}
}
I have attempted to add two different types of Try Catch clauses, but when I debug the code it won't hit the breakpoints and somehow it still logs the error in the DNN Admin logs. Is there perhaps a Try Catch in the DNNController class that is writing this error?
First attempt with Try Catch Clause with TaskCanceledException and TimeoutException:
[AllowAnonymous]
[HttpGet]
public void ClearTempUserSessionWhenLeavePage()
{
try
{
if (SessionManager.GetSessionObject("NewCreatedWebUser") != null)
{
System.Web.HttpContext.Current.Session["DoNotRemoveSessionIfNotAuthenticated"] = false;
SessionManager.SetSessionObject("NewCreatedWebUser", null);
SessionManager.SetSessionObject("UserInfo", null);
SessionManager.SetSessionObject("NewCustomerCode", null);
}
}
catch (Exception ex)
{
EventLogController logController = new EventLogController();
if (ex.InnerException is TimeoutException)
{
ex = ex.InnerException;
}
else if (ex is TaskCanceledException)
{
if ((ex as TaskCanceledException).CancellationToken == null || (ex as TaskCanceledException).CancellationToken.IsCancellationRequested == false)
{
ex = new TimeoutException("Timeout occurred");
logController.AddLog("Timout Occured - Clearing Temp User Session When Leave Page.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
}
}
logController.AddLog("Problem Clearing Temp User Session When Leave Page.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
}
}
Second attempt with a TaskCanceledException:
[AllowAnonymous]
[HttpGet]
public void ClearTempUserSessionWhenLeavePage()
{
try
{
if (SessionManager.GetSessionObject("NewCreatedWebUser") != null)
{
System.Web.HttpContext.Current.Session["DoNotRemoveSessionIfNotAuthenticated"] = false;
SessionManager.SetSessionObject("NewCreatedWebUser", null);
SessionManager.SetSessionObject("UserInfo", null);
SessionManager.SetSessionObject("NewCustomerCode", null);
}
}
catch (TaskCanceledException ex)
{
EventLogController logController = new EventLogController();
logController.AddLog("Task Cancelled Exception - Clearing Temp User Session When Leave Page.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
}
}

Yii2 show error when exception occurs

I have this code in my controller:
...
if (Model::validateMultiple($ttepk)) {
$transaction = \Yii::$app->db->beginTransaction();
try {
foreach ($ttepk as $ttep) {
$ttep->save(false);
if (!$ttep->assignPs()) {
throw new UserException('assignPs failed');
}
}
$transaction->commit();
return $this->redirect(['index']);
} catch (Exception $ex) {
$transaction->rollBack();
throw $ex;
}
}
...
in model:
...
public function assignPs() {
foreach (...) {
$ttepetk[...] = new Ttepet;
$ttepetk[...]->ttepId = $this->id;
... // set other attributes
}
}
if (Model::validateMultiple($ttepetk)) {
foreach ($ttepetk as $ttepet) {
$ttepet->save(false);
}
return true;
} else {
return false;
}
}
...
Everything is working fine (no inserts are happening if any of the models fail validation), except that I would like to see the exact error, exactly by which Ttep (each Ttep is a model) and by which Ttepet (Ttep:Ttepet = 1:N) has the error happened, and what was that. Now I see the Exeption page only, and I don't know how to make the errors visible. Please point me to the right direction. Thanks!
You could iterate on each single model validating one by one and getting the errors when occurs ...
if (Model::validateMultiple($ttepetk)) {
foreach ($ttepetk as $ttepet) {
$ttepet->save(false);
}
return true;
} else {
foreach($ttepetk as $model){
if ($model->validate()) {
// all inputs are valid
} else {
// validation failed: $errors is an array containing error messages
$errors = $model->errors;
}
}
return $errors;
}
you can get the errors this way
$myErrorResult = $ttep->assignPs();
if (!$myErrorResult) {
......

controller action with different render view base on contest page

I have a controller action that get called in different places in my app.
Is it possible to render different view based on caller page?
public function actionMyaction($id){
// blar, blar
if (/* if I'm calling this action from index */) {
return $this->redirect(['index']);
}
else{
return $this->redirect(['update']);
}
}
Try something like,
if($model->isNewRecord)
return $this->render('create', ['model' => $model]);
else
return $this->render('update', ['model' => $model]);
Yes, by "caller page" I assume you mean the referrer.
class ExampleController extends Controller {
private function handleRedirect() {
$referrer = $_SERVER["HTTP_REFERER"];
if (!empty($referrer)) {
switch ($referrer) {
case "blar": return $this->redirect("blar");
}
}
$this->redirect("foo");
}
public function actionMyaction() {
// ... blar
return $this->handleRedirect();
}
}
If not, then maybe you mean the action is the differentiator:
class ExampleController extends Controller {
private function handleRedirect() {
switch (\Yii::$app->controller->action->id) {
case "myaction": return $this->redirect("blar");
}
$this->redirect("foo");
}
public function actionMyaction() {
// ... blar
return $this->handleRedirect();
}
}
If not again then please clarify your question!
You can use:
$this->redirect(Yii::$app->request->referrer);
or:
$this->goBack(Yii::$app->request->referrer);
As per the PHP documentation, $_SERVER["HTTP_REFERER"] is not always to be trusted:
PHP $_SERVER
Edit: of course, you get the added benefit that the Yii team can actually spell "referrer", and your brain doesn't have to scream about the mis-spelt HTTP version.
Maybe you need something like this:
public function actionMyaction($id){
// blar, blar
$referrer = Yii::$app->request->referrer;
$action = explode('/', $referrer);
switch (end($action)) {
case 'index':
return $this->redirect(['index']);
break;
case 'update':
return $this->redirect(['update']);
break;
default:
break;
}
}

send keyCode without key event?

I got this function (in the document class)
public function kyz(event:KeyboardEvent):void{
trace(event.keyCode);
switch (event.keyCode){
case 65:{
if (ppm.currentFrame<200 || ppm.currentFrame>300) {
ppm.gotoAndStop(301);
ssm.gotoAndStop(302);
llm.gotoAndStop(302);
mmm.gotoAndStop(302);
myTimer.stop();
pd.play();
}else {
pd.play();
ppm.gotoAndPlay(10);
tlrnc-=10;
}
break;
}
case 68:{
if (ssm.currentFrame<200 || ssm.currentFrame>300) {
ssm.gotoAndStop(301);
ppm.gotoAndStop(302);
llm.gotoAndStop(302);
mmm.gotoAndStop(302);
myTimer.stop();
mTimer.stop();
sd.play();
}else {
sd.play();
ssm.gotoAndPlay(10);
tlrnc-=10;
}
break;
}
case 74:{
if (llm.currentFrame<200 || llm.currentFrame>300) {
llm.gotoAndStop(301);
ppm.gotoAndStop(302);
ssm.gotoAndStop(302);
mmm.gotoAndStop(302);
myTimer.stop();
mTimer.stop();
ld.play();
}else {
ld.play();
llm.gotoAndPlay(10);
tlrnc-=10;
}
break;
}
case 76:{
if (mmm.currentFrame<200 || mmm.currentFrame>300) {
mmm.gotoAndStop(301);
ppm.gotoAndStop(302);
ssm.gotoAndStop(302);
llm.gotoAndStop(302);
myTimer.stop();
mTimer.stop();
md.play();
}else {
md.play();
mmm.gotoAndPlay(10);
tlrnc-=10;
}
break;
}
}
}
that receives key event's and do stuff. now I'm trying to pass they keyCode from another function (to avoid changing the whole code for adding click functionality) got any suggestions?
you could dispatch a KeyboardEvent
stage.dispatchEvent(
new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, myCharCode, myKeyCode));
just add the needed keyCode as a parameter
You cannot send any Keyboard or Mouse event without interactivity with user. You can handle this in another private function:
private function keyDownHandler(event : KeyboardEvent) : void {
this.handleEvent(event.keyCode);
}
private function handleEvent(keyCode : uint) : void {
//some actions
}
And when you need to make specific actions, you can just call handleEvent function without user side interactivity.