How to modify fortify CreatesNewUsers.php interface? - laravel

I need to modify /vendor/laravel/fortify/src/Contracts/CreatesNewUsers.php interface
and to add 1 more bool parameter, as using CreateNewUser in different places of the app
validations rules are different, say in some places password is not filled on user creation, but must be separate function.
So I copied file /project/resources/fortify/CreatesNewUsers.php with content :
<?php
namespace Laravel\Fortify\Contracts;
interface CreatesNewUsers
{
public function create(array $input, bool $makeValidation);
}
and in app/Actions/Fortify/CreateNewUser.php I modified :
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
//use Laravel\Fortify\Contracts\CreatesNewUsers;
use Resources\Fortify\CreatesNewUsers; // Reference to my interface
use Laravel\Jetstream\Jetstream;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
public function create(array $input, bool $makeValidation)
{
...
But trying to use this class I got error
Interface "Resources\Fortify\CreatesNewUsers" not found
Which is the valid way ?
Thanks!

I moved interface at file app/Actions/Fortify/CreatesNewUsers.php :
<?php
namespace App\Actions\Fortify;
interface CreatesNewUsers
{
public function create(array $input, bool $make_validation, array $hasPermissions);
}
and modified app/Actions/Fortify/CreateNewUser.php :
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use DB;
use App\Actions\Fortify\CreatesNewUsers;
use Laravel\Jetstream\Jetstream;
use Spatie\Permission\Models\Permission;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Validate and create a newly registered user.
*
* #param array $input
*
* #return \App\Models\User
*/
public function create(array $input, bool $make_validation, array $hasPermissions)
{
if ($make_validation) {
$userValidationRulesArray = User::getUserValidationRulesArray(null, '', []);
if (\App::runningInConsole()) {
unset($userValidationRulesArray['password_2']);
}
$validator = Validator::make($input, $userValidationRulesArray);//->validate();
if ($validator->fails()) {
$errorMsg = $validator->getMessageBag();
if (\App::runningInConsole()) {
echo '::$errorMsg::' . print_r($errorMsg, true) . '</pre>';
}
return $errorMsg;
}
} // if($make_validation) {
$newUserData = [
'name' => $input['name'],
'email' => $input['email'],
'account_type' => $input['account_type'],
'phone' => $input['phone'],
'website' => $input['website'],
'notes' => $input['notes'],
'first_name' => $input['first_name'],
'last_name' => $input['last_name'],
];
if (isset($input['password'])) {
$newUserData['password'] = Hash::make($input['password']);
}
if (isset($input['status'])) {
$newUserData['status'] = $input['status'];
}
if (isset($input['activated_at'])) {
$newUserData['activated_at'] = $input['activated_at'];
}
if (isset($input['avatar'])) {
$newUserData['avatar'] = $input['avatar'];
}
try {
DB::beginTransaction();
$newUser = User::create($newUserData);
foreach ($hasPermissions as $nextHasPermission) {
$appAdminPermission = Permission::findByName($nextHasPermission);
if ($appAdminPermission) {
$newUser->givePermissionTo($appAdminPermission);
}
}
DB::commit();
return $newUser;
} catch (QueryException $e) {
DB::rollBack();
if (\App::runningInConsole()) {
echo '::$e->getMessage()::' . print_r($e->getMessage(), true) . '</pre>';
}
}
return false;
}
}
It allows me to use CreateNewUser from different parts of app, like seeders, adminarea, user registration
with different behaviour. For me it seems good way of using fortify and CreateNewUser...

Related

Laravel - Target [App\Interfaces\Auth\AuthInterface] is not instantiable while building

In my Laravel-8 application, I am trying to bind Repository to an Interface
I have this code:
App\Providers\RepositoryServiceProvider:
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
'App\Interfaces\Auth\AuthInterface',
'App\Repositories\Auth\AuthRepository'
);
}
}
config\app:
App\Providers\RepositoryServiceProvider::class,
Then the interface looks like this:
namespace App\Interfaces\Auth;
use Illuminate\Http\Request;
use App\Http\Requests;
interface AuthInterface
{
public function register(Request $request);
}
Repository Implementation:
namespace App\Repositories\Auth;
use App\Interfaces\Auth\AuthInterface;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\Traits\ApiResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class AuthRepository implements AuthInterface
{
use ApiResponse;
public function register(DriverRequest $request)
{
DB::beginTransaction();
try {
$newUser = User::create([
'first_name' => $request->first_name,
'last_name' => $request->last_name,
'email' => preg_replace('/\s+/', '', strtolower($request->email)),
'password' => bcrypt($request->password)
]);
DB::commit();
return $this->success('Signup Successfully Done, please check your email to activate account', $newUser);
} catch(\Exception $e) {
DB::rollback();
Log::error($e);
return $this->error($e->getMessage(), $e->getCode());
}
}
}
Controller
use App\Interfaces\Auth\AuthInterface;
class AuthController extends Controller
{
protected $authInterface;
public function __construct(AuthInterface $auth)
{
$this->authInterface = $auth;
}
public function register(Request $request)
{
return $this->authInterface->register($request);
}
}
When I did php artisan route:list, I got this error:
Illuminate\Contracts\Container\BindingResolutionException
Target [App\Interfaces\Auth\AuthInterface] is not instantiable while building [App\Http\Controllers\Api\V1\Auth\AuthController].
at C:\xampp\htdocs\myapp\vendor\laravel\framework\src\Illuminate\Container\Container.php:1049
1045▕ } else {
1046▕ $message = "Target [$concrete] is not instantiable.";
1047▕ }
1048▕
➜ 1049▕ throw new BindingResolutionException($message);
1050▕ }
1051▕
1052▕ /**
1053▕ * Throw an exception for an unresolvable primitive.
1 C:\xampp\htdocs\myapp\vendor\laravel\framework\src\Illuminate\Container\Container.php:842
Illuminate\Container\Container::notInstantiable("App\Interfaces\Auth\AuthInterface")
2 C:\xampp\htdocs\myapp\vendor\laravel\framework\src\Illuminate\Container\Container.php:714
Illuminate\Container\Container::build("App\Interfaces\Auth\AuthInterface")
How do I get it resolved?
Thanks
It might be from your namespace, I had the same issue...it came from my namespace

Not showing mesage when validating excel file in laravel import

I am using excel 3.1 in Laravel for importing excel files. I have included a validation for the name field. So whenever the name field is duplicating it will not import that row data to DB. everything works fine up to here. but the problem is I want to show success message in the controller. But the message is not showing and not showing any other error messages.
This is my import function
namespace App\Imports;
use App\Products;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\SkipsErrors;
use Maatwebsite\Excel\Concerns\Importable;
use App\Categories;
use App\Brand;
use App\Unit;
use Maatwebsite\Excel\Concerns\WithValidation;
// use Illuminate\Validation\Rule;
// use Throwable;
class ExcelImport implements ToModel, WithStartRow, WithValidation, SkipsOnError
{
use Importable, SkipsErrors;
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
$name = $row[0];
$des = $row[1];
$product = new Products([
'name' => $row[0],
'description' => $row[1],
]);
return $product;
}
public function startRow(): int
{
return 2;
}
public function rules(): array{
return[
'0' => 'unique:products,name',
];
}
}
this is my controller
public function uploadfile(Request $request)
{
$this->validate($request, [
'file' => 'required',
]);
if($request->hasfile('file'))
{
foreach($request->file('file') as $file)
{
$import = new ExcelImport;
$import = $import->import($file);
}
//if the import is successful then I want to show some messages here
}
else{
return back()->with('error','File contains invalid data. Please upload a valid file.');
}
}

Argument 1 passed to ::showAll() must be an instance of Collection, instance ofCollection given, called BuyerProductController.php on line 23

I don't understand this mistake, can someone help me?
I am taking a course on ApiRestfull and the code works for the teacher but I can't get it to work for me
I am using laravel 5.8*
The error he shows me is this: Error:
Argument 1 passed to App\Http\Controllers\ApiController::showAll() must be an instance of Illuminate\Database\Eloquent\Collection, instance of Illuminate\Support\Collection given, called in C:\laragon\www\udemy-apirestfull\app\Http\Controllers\Buyer\BuyerProductController.php on line 23
BuyerProductController.php:
<?php
namespace App\Http\Controllers\Buyer;
use App\Buyer;
use Illuminate\Http\Request;
use App\Http\Controllers\ApiController;
class BuyerProductController extends ApiController
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Buyer $buyer)
{
$products = $buyer->transactions()->with('product')
->get()
->pluck('product');
return $this->showAll($products);
}
}
ApiController:
<?php
namespace App\Http\Controllers;
use App\Traits\ApiResponser;
use Illuminate\Http\Request;
class ApiController extends Controller
{
use ApiResponser;
}
ApiResponser:
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
trait ApiResponser
{
private function successResponse($data, $code)
{
return response()->json($data, $code);
}
protected function errorResponse($message, $code)
{
return response()->json(['error' => $message, 'code' => $code], $code);
}
protected function showAll(Collection $collection, $code = 200)
{
return $this->successResponse(['data' => $collection], $code);
}
protected function showOne(Model $instance, $code = 200)
{
return $this->successResponse(['data' => $instance], $code);
}
}
Buyer model:
<?php
namespace App;
use App\Transaction;
use App\Scopes\BuyerScope;
class Buyer extends User
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new BuyerScope);
}
public function transactions()
{
return $this->hasMany(Transaction::class);
}
}
Product Model:
<?php
namespace App;
use App\Seller;
use App\Category;
use App\Transaction;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use SoftDeletes;
const PRODUCTO_DISPONIBLE = 'disponible';
const PRODUCTO_NO_DISPONIBLE = 'no disponible';
protected $dates = ['deleted_at'];
protected $fillable = [
'name',
'description',
'quantity',
'status',
'image',
'seller_id',
];
public function estaDisponible()
{
return $this->status == Product::PRODUCTO_DISPONIBLE;
}
public function seller()
{
return $this->belongsTo(Seller::class);
}
public function transactions()
{
return $this->hasMany(Transaction::class);
}
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
Transaction Model:
<?php
namespace App;
use App\Buyer;
use App\Product;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Transaction extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $fillable = [
'quantity',
'buyer_id',
'product_id',
];
public function buyer()
{
return $this->belongsTo(Buyer::class);
}
public function product()
{
return $this->belongsTo(Product::class);
}
}
Illuminate\Database\Eloquent\Collection extends Illuminate\Support\Collection
So if not mandatory, you can change the signature of showAll method to accept Illuminate\Support\Collection as a parameter
There will be no error if the parameter supplied will be an instance of Illuminate\Database\Eloquent\Collection
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; //Changed here
trait ApiResponser
{
private function successResponse($data, $code)
{
return response()->json($data, $code);
}
protected function errorResponse($message, $code)
{
return response()->json(['error' => $message, 'code' => $code], $code);
}
protected function showAll(Collection $collection, $code = 200)
{
return $this->successResponse(['data' => $collection], $code);
}
protected function showOne(Model $instance, $code = 200)
{
return $this->successResponse(['data' => $instance], $code);
}
}

Log failed queue jobs to file fallback

If MySQL go down, there is any fallback options to log Failed Queue Jobs to file?
I try
namespace App\Providers\AppServiceProvider;
function register()
Queue::failing(function (JobFailed $event) {
if($event->exception instanceof \PDOException){
$data = [
'code' => $event->exception->getCode(),
'connectionName' => $event->connectionName,
'getQueue' => $event->job->getQueue(),
'getRawBody' => $event->job->getRawBody(),
'exception' => (string)$event->exception,
];
\App\Repositories\FailedJobMysqlDown::set($data);
}
});
but this check the reasons of jobs go down,
i wanna catch inserting into failed_jobs exception
[2002] No such file or directory (SQL: insert into `failed_jobs` (`connection`, `queue`, `payload`, `exception`, `failed_at`) values (redis, superhigh, {"ty................
Any Ideas?
Thanks
found solutions
Create class
<?php
namespace App\Override;
use Illuminate\Queue\Failed\FailedJobProviderInterface;
use Illuminate\Queue\Failed\DatabaseFailedJobProvider ;
use Illuminate\Support\Facades\Date;
class FallbackDatabaseFailedJobProvider extends DatabaseFailedJobProvider implements FailedJobProviderInterface
{
public function log($connection, $queue, $payload, $exception)
{
try{
return parent::log(...func_get_args());
}catch (\Exception $e) {
$failed_at = Date::now();
$exception = (string) $exception;
$data = [
'connectionName' => $connection,
'getQueue' => $queue,
'getRawBody' => $payload,
'exception' => $exception,
'failed_at' => $failed_at,
];
\App\Repositories\FailedJobMysqlDown::set($data);
}
}
}
and register it in serviceprovider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Override\FallbackDatabaseFailedJobProvider;
class FailedLogServiceProvider extends ServiceProvider
{
public function boot()
{
// Get a default implementation to trigger a deferred binding
$_ = $this->app['queue.failer'];
// Swap the implementation
$this->app->singleton('queue.failer', function ($app) {
$config = $this->app['config']['queue.failed'];
return new FallbackDatabaseFailedJobProvider($this->app['db'], $config['database'], $config['table']);
});
}
}
add to condig/app.php in providers
'providers' => [
..............
App\Providers\FailedLogServiceProvider::class,
]
use current or create your own implementation log function
<?php
namespace App\Repositories;
/**
* Log failed job to file fallback
*/
class FailedJobMysqlDown
{
private static $file = '_xlogJobFailedMysqlDown'; //set full path
public static function get(){
$x = file(self::$file);
$data = [];
foreach($x as $line){
$data[] = json_decode($line);
}
return $data;
}
public static function set($message){
$message = json_encode($message);
file_put_contents(self::$file,$message.PHP_EOL , FILE_APPEND | LOCK_EX );
}
}
voilà

Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Auth\UserInterface, null given open:

I have facebook login which uses socialite library. The error in the question occurs when the callback occurs.
Here is my "USER" model
<?php
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements Authenticatable
{
//use Illuminate\Contracts\Auth\Authenticatable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
use \Illuminate\Auth\Authenticatable;
public function posts()
{
return $this->hasMany('App\Post');
}
public function likes()
{
return $this->hasMany('App\Like');
}
}
The Socialite logins are handled by SocialAuthController and what i understood from the error is , auth()->login($user); , null is passed to the login("NULL"). Here is the code of SocialAuthController. What's the mistake i have made here and how to fix this. thanks in advance
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Socialite;
use App\SocialAccountService;
class SocialAuthController extends Controller
{
public function redirect($provider)
{
return Socialite::driver($provider)->redirect();
}
use \Illuminate\Auth\Authenticatable;
public function callback(SocialAccountService $service , $provider)
{
$user = $service->createOrGetUser(Socialite::driver($provider));
auth()->login($user);
return redirect()->to('/home');
}
}
The below is the handling service that will try to register user or log in if account already exists.
Here is the code of SocialAccountService.php
<?php
namespace App;
use Laravel\Socialite\Contracts\Provider;
class SocialAccountService
{
public function createOrGetUser(Provider $provider)
{
$providerUser = $provider->user();
$providerName = class_basename($provider);
$account = SocialAccount::whereProvider($providerName)
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => $providerName
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
This will try to find provider's account in the system and if it is not present it will create new user. This method will also try to associate social account with the email address in case that user already has an account.
My wild guess is that createOrGetUser() returns NULL because the SocialAccount does not have a user. So what could do is change the if condition in that method to check if the $account has a user:
public function createOrGetUser(Provider $provider)
{
...
if ( $account && property_exists($account, 'user') && $account->user ) {
return $account->user;
} else {
...

Resources