yii before actions for specified action - yii

I know controller have a method called:CController:beforeAction()
It will be called before every action in current controller.
But how to make it only work before "actions"?
public function actions(){
return array(
//trigger something like beforeaction only for action "uploader"
'uploader' => array(
'class' =>'',
),
);
}

Nice question. I think there isn't anyway to disable running beforeAction on specific action. If you have beforeAction inside your controller, this method will run before any action. But you can do this instead:
protected function beforeAction($action)
{
if($action->id != "uploader")
{
//do some stuff here
}
return parent::beforeAction($action);
}

Related

How to check permissions in my controller

I'm new to Laravel and I'm writing a user management System on my own.
At this time,
I can CRUD permissions, roles and users,
I can check the permissions by the AuthServiceProvider#boot method like this:
public function boot()
{
Gate::before( function (User $user , $permission) {
// App administrator
if($user->getPermissions()->contains('appAll'))
{
return true;
}
// Permission check
return $user->getPermissions()->contains($permission);
});
}
In my AdminUserController, I can check the permissions like that:
public function index()
{
if( Gate::check('createUser') || Gate::check('readUser') || Gate::check('updateUser') || Gate::check('deleteUser')) {
return view('userMgmt/users/index', [
'users' => User::getUsersWithRolesWithTexts()
]);
}
else
{
return redirect(route('home'))->withErrors('You do not have required permission');
}
}
That is working well.
BUT
Is this the right way to wrap each controller method with:
if( Gate::check(...) ...) {
//Do what the method is supposed to do
}
else
{
return redirect(route('SOME.ROUTE'))->withErrors('SOME ERROR OCCURRED');
}
It would be nice if someone can give me some ideas.
Tank you
There is a controller helper function named authorize that you can call from any method in a controller that extends App\Http\Controllers\Controller. This method accepts the action name and the model, and it will throw an exception if the user is not authorized. So instead of the if...else statement, it will be one line:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// The current user can update the blog post...
}

Laravel 6: How to change the URL of the password reset email link in custom class

I'm building API with Laravel and working on resetting password. Everything is working fine but I want to change the URL which will handle the reset link to be different than the API domain
Route::group(['namespace' => 'Api', 'middleware' => 'guest'], function () {
Route::post('password/reset', 'ResetPasswordController')->name('password.reset');
public function forgotPassword($data) {
Password::sendResetLink(['email' => $data['email']]);
}
Laravel reset password class (class ResetPassword extends Notification)
return (new MailMessage)
....
->action(Lang::get('Reset Password'), url(route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
....
}
I want to change the URL
http://api.test:8000/api/password/reset?token=dced9b55a73fcd0692ce4157d2685826f51c332d0dcce613cad108a8599881d7&email=user#mail.com
to be
http://frontend.test:8000/reset-password?token=dced9b55a73fcd0692ce4157d2685826f51c332d0dcce613cad108a8599881d7&email=user#mail.com
I managed to change it in the original class
// ->action(Lang::get('Reset Password'), url(route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
->action(Lang::get('Reset Password'), 'http://frontend.test:8000/reset-password?token='.$this->token.'&email='.$notifiable->getEmailForPasswordReset())
But how can I override this function in my own class that would be better to keep the original function as it is but don't know how.
Thanks in advance
There is a static helper in Laravel's ResetPassword notification, you can add following code in the App\Providers\AuthServiceProvider class:
use App\Notifications\Auth\ResetPasswordNotification;
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
ResetPasswordNotification::createUrlUsing(function ($notifiable, $token) {
return config('app.frontend_url')."/password/reset/$token?email={$notifiable->getEmailForPasswordReset()}";
});
//
}
I found a simple answer here by creating a custom notification and using it in CanResetPassword trait https://laracasts.com/discuss/channels/laravel/how-to-override-the-tomail-function-in-illuminateauthnotificationsresetpasswordphp

Yii2 - Capture paramether from router in beforeAction

Is there a way to capture parameter from router in the beforeAction, so it could be use by all functions in controller?
I have this router:
'http://<user:\w+>.' . $domain . '/<controller:\w+>/<action:\w+>' => '<controller>/<action>',
I want to use as ID in all functions in controller, and make it available without injecting it into the function? Is this possible?
A raw solution can be intercept the $params array inside the bindActionParams:
class ParamController extends Controller {
public $user;
public function bindActionParams($action, $params)
{
if(isset($params['user'])){
// may be some business based on $this or $action
$this->user = $params['user'];
}
return parent::bindActionParams($action, $params); // TODO: Change the autogenerated stub
}
}
Of course you need to extends all your controllers from ParamsController.

yii2 How to change user password via actionUpdate?

I have advanced app. I create CRUD for User model. So i got update action. I tried to update password by adding
<?= $form->field($model, 'password')->passwordInput() ?>
But it call error, something like "password is write-only variable"
I tried to use field
<?= $form->field($model, 'new_password')->passwordInput() ?>
With adding in actionUpdate model->setPassword($this->new_password); and it throw Getting unknown property: common\modules\user\controllers\DefaultController::new_password.
But model->setPassword('123456'); successfully setting pussword 123456.
How can i get new_password field from view, to put it in model->setPassword('there');
Or maybe exist best way to do it?
UPD
I tried do it. Is not work.
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if ($this->new_password) {
$this->setPassword($this->new_password);
}
return true;
} else {
return false;
}
}
UPD2
public function setPassword($password) {
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
And password_hash writing in database. I can easy change hash, via generated CRUD, but don't know how to use setPassword() in updateAction.
You can try write updatePassword function like setPassword with another variable
public function updatePassword($new_password) {
$this->password_hash = Yii::$app->security->generatePasswordHash($new_password);
}
declare a variable
public $new_password;
And add it in rules()
public function rules() {
return [
//...
['new_password', 'required'],
['new_password', 'string', 'min' => 6],
];
}
And at actionUpdate in your controller add
$model->updatePassword($model->new_password);
This should help
Here "$this" is your Controller which of course, doesn't have 'new_password' property. You'd better not set new password in controller, but do it in model, for example in beforeSave method:
if ($this->new_password) {
$this->setPassword($this->new_password);
}

Using action filters to perform transactions

I want to make a TransactionFilter in Yii to be applied over an action to wrap it in a transaction so I donĀ“t have to write the same code over and over every time I want to use transactions, at least that's the idea. I have
class TransactionFilter extends CFilter
{
public function filter($filterChain)
{
if(Yii::app()->getRequest()->getIsPostRequest())
{
$transaction= Yii::app()->db->beginTransaction();
try {
$filterChain->run();
$transaction->commit();
}catch(Exception $e) {
$transaction->rollback();
}
}
else
$filterChain->run();
}
}
This is my filters method in my User class:
public function filters()
{
return array(
'accessControl',
'postOnly + delete',
array('application.components.TransactionFilter + create'),
);
}
I'm assuming $filterChain->run() will eventually execute the action but the problem arises when there's a redirect in the action, it never made it after the $filterChain->run() sentence in the filter
I don't know if this approach would be advisable and posible in Yii, if not I would appreciate the help if there is another approach or I have to stick with the traditional one.
Thank you.
You have to begin transaction on:
protected function preFilter($filterChain)
And commit, rollback on :
protected function postFilter($filterChain)