How to call a function within the same controller? - oop

I have to call a soap service using laravel and done so correctly. This soap service requires me to send a login request prior to sending any other request.
The code I'm using works, but I want to improve by removing the login from all the functions and creating one function.
I tried changing the following for one function:
public function getcard($cardid)
{
SoapWrapper::add(function ($service) {
$service
->name('IS')
->wsdl(app_path().'\giftcard.wsdl')
->trace(true);
});
$data = [
'UserName' => 'xxxx',
'Password' => 'xxxx',
];
$card = [
'CardId' => $cardid,
];
SoapWrapper::service('IS', function ($service) use ($data,$card) {
$service->call('Login', [$data]);
$cardinfo=$service->call('GetCard', [$card]);
dd($cardinfo->Card);
});
}
Into:
public function login()
{
SoapWrapper::add(function ($service) {
$service
->name('IS')
->wsdl(app_path().'\giftcard.wsdl')
->trace(true);
});
$data = [
'UserName' => 'xxxx',
'Password' => 'xxxx',
];
SoapWrapper::service('IS', function ($service) use ($data) {
return $service->call('Login', [$data]);
//$service->call('Login', [$data]);
//return $service;
});
}
public function getcard($cardid)
{
$this->login();
$card = [
'CardId' => $cardid,
];
$cardinfo=$service->call('GetCard', [$card]);
dd($card);
}
But this doesn't work. I also tried it with the commented out part, but that doesn't work. Both options result in an error that it didn't find 'service'.
I know it has something to do with oop, but don't know any other option.
I took this as an example, but I probably implemented it wrong?
So my question is: How do I reuse the login part for all other functions?

Your return statement in the login() method is within the scope of that closure. You need to return the result of the closure as well.
return SoapWrapper::service('IS', function ($service) use ($data) {
return $service->call('Login', [$data]);
});
EDIT:
To explain a little bit. You have a function:
SoapWrapper::service('IS' ,function() {}
Inside of a function : public function login()
If you need to return data from your login() method, and that data is contained within your SoapWrapper::service() method, then both methods need a return statement

Related

laravel 8 session doesn't save data

I'm trying to save an array for checkout but when i print session it gives null
namespace App\Http\Livewire;
use App\Orders;
use Livewire\Component;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Cart;
use Carbon\Carbon;
public function setAmountForCheckout()
{
if(session()->has('coupon'))
{
session()->put('checkout',[
'discount'=>$this->discount,
'subtotal'=>$this->subtotalAfterDiscount,
'total'=>$this->totalAfterDiscount,
]);
}
else
{
session()->put('checkout',[
'discount'=>0,
'tax'=>Cart::instance('cart')->tax(),
'subtotal'=>Cart::instance('cart')->subtotal(),
'total'=>Cart::instance('cart')->total(),
]);
session()->save();
}
}
public function placeOrder(Request $request)
{
dd(session()->get('checkout'));
$this->validate([
'first_name' => 'required|min:4|string',
'Phone_number' => 'required|digits:11'
]);
$order=new Orders();
$order->user_id=Auth::id();
$order->cust_name=$this->first_name;
$order->phone=$this->Phone_number;
$order->subtotal=session()->get('checkout')['subtotal'];
$order->discount=session()->get('checkout')['discount'];
$order->total=session()->get('checkout')['total'];
$order->status='ordered';
$order->is_shipping=$this->haveShipping ? 1:0;
foreach(Cart::instance('cart')->content() as $items)
{
$orderItem= new OrderItems();
$orderItem->product_id=$items->id;
$orderItem->price=$item->price;
$orderItem->order_id=$order->id;
$orderItem->quantity=$item->qty;
$orderItem->save();
}
if($this->haveShipping)
{
$this->validate([
'Address'=>'required|min:4',
'shipping_fee'=>'required|numeric'
]);
$order->address=$this->Address;
$order->delivery=$this->shipping_fee;
}
$order->save();
Cart::instance('cart')->destroy();
session()->forget('checkout');
}
when i remove dd it gives me the error "Trying to access array offset on value of type null"
I'm trying to find what's wrong with the session.
also i have checked the cart if it works or not but i found that it works well and delivers data.
Remove
session()->save();
This is not needed as per https://laravel.com/docs/8.x/session#storing-data

Dynamic domain in reset password link Laravel 8

I'm aware that password reset link can be customized by adding the below function in AuthServiceProvider.php
ResetPassword::createUrlUsing(function ($user, string $token) {
return 'https://example.com/reset-password?token='.$token;
});
This is my sendResetPassword function
public function sendResetPassword(Request $request) {
$request->validate(['email' => 'required|email']);
$status = Password::sendResetLink(
$request->only('email')
);
if ($status === Password::RESET_LINK_SENT) {
return response()->json(['message' => __($status)], 200);
} else {
return response()->json(['message' => __($status)], 500);
}
}
Now I'm wondering if there is a way to pass a domain from the sendResetPassword $request to the createUrlUsing function.
The main purpose of this is to avoid hardcoding the frontend URL in my API. I just want that the forgot password form in my frontend sends the email and also the domain.
Not sure if this is the best approach, but as soon I posted the question I found that this is a working solution:
ResetPassword::createUrlUsing(function ($user, string $token) {
return $this->app->request->headers->get('origin').'/reset-password?token='.$token;
});

Laravel8 role based access using and pivot tables and middlewares

I am trying to write a large project using laravel8 and will need role based access. So I have created a roles table and linked it to the users table via a modal table called role_user. Now I am able to create the access and perform checks inside controllers and users model and everything works correctly
my problem is that this way I have to keep checcking if a user has access in each and every function for all my user access levels and this is tedious.
I have thus tried to convert this approcah and use middlewares but the problem is that I am unable to redirect the users to the appropriate dashboard upon authentication and they are both being redirected to the home page that is designated for users only.
I have tried the following
I have addes the following code to the users model to create a many to many relationship between the users and the roles and also to check if the user has roles and peform appropriate tasks as per the code blocks
public function roles() {
return $this->belongsToMany(Role::class);
}
public function checkRoles($roles) {
if ( ! is_array($roles)) {
$roles = [$roles];
return false;
}
if ( ! $this->hasAnyRole($roles)) {
auth()->logout();
abort(404);
}
}
public function hasAnyRole($roles): bool {
return (bool) $this->roles()->whereIn('name', $roles)->first();
}
public function hasRole($role): bool {
return (bool) $this->roles()->where('name', $role)->first();
}
Now this would have worked if I proceeded to peforem checks on each controller's model directly but after creating middlewares for each role and peforming checks in each as follows things failled
a) Admin Middleware
public function handle(Request $request, Closure $next){
if (Auth::user() && $request->user()->hasRole('admin')) {
return $next($request);
}
return redirect('home')->with('error','You have not admin access');
}
b) SuperAdmin Middleware
public function handle(Request $request, Closure $next) {
if (Auth::user() && $request->user()->hasRole('super_admin')) {
return $next($request);
}
return redirect('home')->with('error','You have not permission to peform this task');
}
Now after registering all the middlewareds inside the Kernel class, I modified the login Controller class and added the following code inside the construct function:
if(Auth::check()){
if(Auth::user()->hasRole('super_admin')){
return redirect(RouteServiceProvider::SUPERADMINADMINHOME);
}elseif(Auth::user()->hasRole('admin')){
return redirect(RouteServiceProvider::ADMINHOME);
}elseif(Auth::user()->hasRole('vendor')){
return redirect(RouteServiceProvider::VENDORHOME);
}else {
return redirect(RouteServiceProvider::HOME);
}
}
I also updated my routes as follows
Route::group(['prefix' => 'super', 'as' => 'super.', 'namespace' => 'Super', 'middleware' => ['Super']], function () {
Route::get('/', [App\Http\Controllers\SuperAdminController::class,'index'])->name('superadminhome');
});
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'namespace' => 'Admin', 'middleware' => ['Admin']], function () {
Route::get('/', [App\Http\Controllers\AdminController::class,'index'])->name('adminhome');
});
Route::group(['prefix' => 'vendor', 'as' => 'vendor.', 'namespace' => 'Vendor', 'middleware' => ['Vendor']], function () {
Route::get('/', [App\Http\Controllers\VendorController::class,'index'])->name('vendorhome');
});
After doing all this, I tried tom login with the superadmin credentials and the admin credentials but all of them take me to the same page home. What could I be doing wrong or where can I get step by step guide to how to achieve this task noting that I am new to middlewares in laravel.
From what I can see you are having this problem becasue the checks are all yielding false hence the last is being taken into account. That would mean that the way in which you are checking for the roles is probably wrong. I would suggest looping through the roles and using a switch statement. checking if it matches the ones you need and then redirecting appropriately.
This would mean changing your if statements that check for the availability of a specific roles.
That is this part of your code
if(Auth::user()->hasRole('super_admin')){
return redirect(RouteServiceProvider::SUPERADMINADMINHOME);
}elseif(Auth::user()->hasRole('admin')){
return redirect(RouteServiceProvider::ADMINHOME);
}elseif(Auth::user()->hasRole('vendor')){
return redirect(RouteServiceProvider::VENDORHOME);
}else {
return redirect(RouteServiceProvider::HOME);
}

How to add captcha required only for a particular condition yii2

I am trying make the captcha field required only when the number of failed login attempts exceed 3 times. For which I have written below code till now.
In LoginForm model I have added the below rules
public function rules()
{
return [
[['username', 'password'], 'required'],
['password', 'validatePassword'],
['verifyCode', 'captcha', 'when' => function($model) {
return $this->checkattempts();
}],
];
}
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addLoginAttempt($user->id);
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
public function checkattempts()
{
$user = $this->getUser();
$ip = $this->get_client_ip();
$data = (new Query())->select('*')
->from('login_attempts')
->where(['ip' => $ip])->andWhere(['user_ref_id' => $user->id])
->one();
if($data["attempts"] >=3){
return false;
}else{
return true;
}
}
public function addLoginAttempt($uid) {
$ip = $this->get_client_ip();
$data = (new Query())->select('*')
->from('login_attempts')
->where(['ip' => $ip])->andWhere(['user_ref_id' => $uid])
->one();
if($data)
{
$attempts = $data["attempts"]+1;
#Yii::$app->db->createCommand("UPDATE login_attempts SET attempts=".$attempts." where ip = '$ip' AND user_ref_id=$uid")->execute();
}
else {
Yii::$app->db->createCommand("INSERT into login_attempts (attempts, user_ref_id, ip) VALUES(1,'$uid', '$ip')")->execute();
}
}
Here I am validating the password first. If the password is incorrect then I am incrementing the count by 1. This part is working fine. The count is incrementing successfully.
After this I am trying to get the count of failed attempts while validating captcha using the function checkattempts(), but it is not working.
Can anyone please tell me where I have made mistake.
Thanks in advance.
In your model:
if (!$model->checkattempts())
//show the captcha
Then, in your model rules you'll need something like:
['captcha', 'captcha'],
In your case, what you can do is use different scenarios depending on the user attempts, and in one scenario (more than X attempts) make the captcha required.
More documentation about the captcha and about scenarios.

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