How to override error handler from a module - error-handling

To override error handler from a module based this samdark guid:
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
\Yii::configure($this, [
'components' => [
'errorHandler' => [
'class' => ErrorHandler::className(),
]
],
]);
/** #var ErrorHandler $handler */
$handler = $this->get('errorHandler');
\Yii::$app->set('errorHandler', $handler);
$handler->register();
}
}
This method only worked for valid module controllers, but can not handle invalid module controllers. Even affects all over the application so that module error handler will be default error handler all over the application. i was confused how can solve it!
Example: I was willing www.site.com/module/x handled with module error handler(www.site.com/module/default/error),where x is not a valid module controller. If that was not the case, it was handled with app error handler(www.site.com/site/error).
Finally i used this code: (admin is my module name). Know everything is fine.
class AdminModule extends \yii\base\Module
{
public function init()
{
parent::init();
// Is better used regex method, temporally i used this method
$r = Yii::$app->urlManager->parseRequest(Yii::$app->request)[0];
$r_array = explode('/',$r);
if($r_array[0] === 'admin'){
Yii::configure($this, [
'components' => [
'errorHandler' => [
'class' => ErrorHandler::className(),
'errorAction' => '/admin/default/error',
]
],
]);
$handler = $this->get('errorHandler');
Yii::$app->set('errorHandler', $handler);
$handler->register();
}
}
}
If you know a better way please share with me. Thanks

Related

Laravel custom routing files not working with new routes

I am building a CMS SPA with Laravel 8 and I wanted to seperate the routes by category (admin, api, auth) in seperate route files with the use of custom slugs (/admin/settings , /auth/login) but I cant seem to get it to work so what am I doing wrong? It all did work when it was the API file but when dividing it over seprate files it wont work.
routes/admin.php
Route::group(['middleware' => 'auth:sanctum'], function () {
Route::get('settings', [SettingsController::class, 'index'])->name('settings');
});
routeServiceProvider.php
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('web')
->group(base_path('routes/web.php'));
Route::prefix('api')
->middleware('api')
->group(base_path('routes/api.php'));
Route::prefix('auth')
->middleware('auth')
->namespace($this->namespace)
->group(base_path('routes/auth.php'));
Route::prefix('admin')
->middleware('admin')
->namespace($this->namespace)
->group(base_path('routes/admin.php'));
});
}
routes/web.php
Route::get('/{any}', function () {
return view('layouts.vue');
})->where('any', '^(?!api|admin|auth).*$');
kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'admin' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'auth' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
]
];
Component.vue
const response = axios.get('/admin/settings')// not giving the data back
const response = axios.get('/api/settings')// in the past did work
While someone else gives a better answer about your approach. As simple way to achieve /admin/settings in the web/routes.php file would be to use prefixes
Route::prefix('admin')->middleware(['auth:sanctum'])->group(function() {
Route::get('settings', [SettingsController::class, 'index']);
});
With this approach you won't need to make changes to your app\Http\kernel.php or routeServiceProvider.php files.
Also if you want to abstract it away, you could put your it in a new file and just require require_once __DIR__ . '/admin.php'; as you would a regular php file.

CakePHP3 CRUD API and API Routing

I am using the Friends of Cake CRUD plugin for my back-end API. I am also using API prefixes for my routes:
Router::prefix('Api', function ($routes) {
$routes->extensions(['json', 'xml', 'ajax']);
$routes->resources('Messages');
$routes->resources('ReportedListings');
$routes->fallbacks('InflectedRoute');
});
So far so good. My controller is as follows:
namespace App\Controller\Api;
use App\Controller\AppController;
use Cake\Event\Event;
use Cake\Core\Exception\Exception;
class MessagesController extends AppController {
use \Crud\Controller\ControllerTrait;
public function initialize() {
parent::initialize();
$this->loadComponent(
'Crud.Crud', [
'actions' => [
'Crud.Add',
'update' => ['className' => 'Crud.Edit']
],
'listeners' => ['Crud.Api'],
]
,'RequestHandler'
);
$this->Crud->config(['listeners.api.exceptionRenderer' => 'App\Error\ExceptionRenderer']);
$this->Crud->addListener('relatedModels', 'Crud.RelatedModels');
}
public function beforeFilter(Event $event){
parent::beforeFilter($event);
}
public function add() {
return $this->Crud->execute();
}
When I make a call as follows:
[POST] /api/messages.json
I get an error:
Action MessagesController::index() could not be found, or is not accessible.
I instead use:
[POST] /messages.json
I don't get the error and I can add a message. So the question is why with my api prefix routing does the CRUD look for index and how can I avoid this behavior?
I found the issue:
Router::prefix('Api', function ($routes) {
....
}
The 'Api' should be lowercase!
Router::prefix('api', function ($routes) {
....
}

Laravel Route::controller routing issue with prefix

I have following implicit route defined (Laravel 5.2)
// Handle locale
Route::group([
'prefix' => '{country}/{language}',
], function () {
Route::controller('user', 'UserController');
});
And here is my controller
class UserController extends BaseLocaleController
{
public function getIndex()
{
return view('user/index');
}
public function getProfile($slug)
{
echo $slug;die;
return view('user/view');
}
}
My URI Structure is
http://{host}/in/en/user/profile/manju
The problem here, my slug value is in instead of manju. Is there any URI pattern I need to apply?
How can make this work in Laravel 5.2. As you could see, I have country and language prefix in Route::group.
Just pass the $country, $language to the method
So it should be
public function getProfile($country, $language, $slug)
{
echo $slug;die;
return view('user/view');
}

Yii2 autologin doesn't work

I try to realize the autologin feature in yii2.
So I've enabled autologin in configuration:
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
'loginUrl' => ['account/login', 'account', 'account/index'],
],
Also I've added rememberMe field in form configuration
public function scenarios() {
return [
'login' => ['username','password','rememberMe'],
'activate' => ['password','passwordrepeat'],
'register' => ['username', 'mail'],
'setup' => ['username', 'password', 'passwordrepeat', 'mail', 'secretkey'],
];
}
// ...
[
['rememberMe'],
'boolean',
'on' => 'login',
],
I'm using this now at login:
public function login() {
//var_dump((bool) ($this->rememberMe)); exit();
if (!$this->validate()) {
return false;
}
return Yii::$app->user->login($this->getUser(), (bool) ($this->rememberMe) ? 3600*24*30 : 0);
}
If I log in, users function getAuthKey function is called and a new auth_key is generated.
public function generateAuthKey() {
$this->auth_key = Yii::$app->getSecurity()->generateRandomString();
Helper::save($this);
// Helper is a database helper which will update some rows like last_modified_at and similar in database
}
/**
* #inheritdoc
*/
public function getAuthKey()
{
$this->generateAuthKey();
return $this->auth_key;
}
But always, I log in, it doesn't set some cookie variables.
My cookies are always
console.write_line(document.cookie)
# => "_lcp=a; _lcp2=a; _lcp3=a"
And if I restart my browser I'm not logged in.
What am I doing wrong?
It seems that Yii doesn't work with cookies correctly:
var_dump(Yii::$app->getRequest()->getCookies()); exit();
Results in:
object(yii\web\CookieCollection)#67 (2) { ["readOnly"]=> bool(true) ["_cookies":"yii\web\CookieCollection":private]=> array(0) { } }
If I access via $_COOKIE I have the same values as in JS.
Thanks in advance
I guess you don't have to generate auth key every time in your getAuthKey method. Your app tries to compare database value to the auth key stored in your cookie. Just generate it once before user insert:
/**
* #inheritdoc
*/
public function getAuthKey()
{
return $this->auth_key;
}
/**
* #inheritdoc
*/
public function beforeSave($insert)
{
if (!parent::beforeSave($insert)) {
return false;
}
if ($insert) {
$this->generateAuthKey();
}
return true;
}
Could be your timeout for autologin is not set
Check if you have a proper assignment to the value assigned to the variable:
$authTimeout;
$absoluteAuthTimeout;
See for more

yii friendly url for modules does not work

I created a modules called calculator and am trying to create the freindly url for it.
here is my code
'<action:(calc1|calc2|calc3)>' => '/calculator/<action>',
the view files are in
modules/calculator/view/default/pages/calc2.php
when i type in my address bar
localhost/dev/cal2
i get this error
Error 404
Unable to resolve the request "calculator/calc2".
in my controller i have this
class DefaultController extends Controller
{
public function actions() {
return array(
'page' => array('class' => 'CViewAction'),
);
}
public function actionIndex()
{
$this->render('index');
}
}
the default page shows when i go to http://localhost/dev/calculator but the inner pages in the modules doesn't.
here is my regex
'<view:(about|terms|faq|privacy)>' => 'site/page',
'<action:(contact|login|logout)>' => 'site/<action>',
'<fileName:(calc1|calc2|calc3)>' => '/calculator/default/page/view/<fileName>',
'<action:(registration|create)>' => 'user/<action>',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
any idea what i'm doing wrong?
In order to use the page action your urls should resolve to /<module>/<controller>/page/view/<fileName> where fileName is calc1, calc2 etc. Therefore in your case your rules should be:
'<fileName:(calc1|calc2|calc3)>' => '/calculator/default/page/view/<fileName>',
Reference: http://www.yiiframework.com/wiki/22/how-to-display-static-pages-in-yii/
First you need to define your action in your calculator controller:
class CalculatorController extends Controller
{
public function actionCalc1()
{
$this->render('calc1');
}
public function actionCalc2()
{
$this->render('calc2');
}
public function actionCalc3()
{
$this->render('calc3');
}
}
Of course you've to change your view paths and then you should see something when you type into your browser <your domain>/calculator/calc2.