how to extend Builder class in laravel 5.2 - laravel

I tried to extend Illuminate\Database\Query\Builder to override various functions, but i cant make it.
I created a custom builder (CustomBuilder.php)
<?php
use Closure;
use Illuminate\Support\Collection;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Query\Grammars\Grammar;
use Illuminate\Database\Query\Processors\Processor;
class CustomBuilder extends Illuminate\Database\Query\Builder {
public function get($columns = ['*'])
{
$builder = $this->applyScopes();
$models = $builder->getModels($columns);
if (count($models) > 0) {
$models = $builder->eagerLoadRelations($models);
}
return $builder->getModel()->newCollection($models);
}
}
And a custom model (CustomModel.php)
<?php
use DateTime;
use ArrayAccess;
use Carbon\Carbon;
use LogicException;
use Illuminate\Events\Dispatcher;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Contracts\JsonableInterface;
use Illuminate\Support\Contracts\ArrayableInterface;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
// use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\ConnectionResolverInterface as Resolver;
use CustomBuilder as QueryBuilder; // MyModel should now use your MyQueryBuilder instead of the default which I commented out above
abstract class CustomModel extends Illuminate\Database\Eloquent\Model
{
}
?>
What is the correct folder to put these files, and how to call it from my models?
I tried in app/Extensions, in vendor, but i get the same error.
Class CustomModel cannot be found.
Thanks

Related

Return value must be of type Laravel 10

I am working on a Laravel 10 project and trying to create a controller that displays records. However, I have run into a problem while attempting to do so :
App\Http\Controllers\StudentController::index(): Return value must be of type Illuminate\Http\Response, Illuminate\View\View returned
I have attached below what I have tried so far:
Student Controller
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\Student;
class StudentController extends Controller
{
public function index(): Response
{
$students = Student::all();
return view ('students.index')->with('students', $students);
}
If I remove the Response class, the code works, but I need to implement the Laravel 10 standard. I am unsure how to solve this issue. Can you please provide a solution?
Routes
Route::resource("/student", StudentController::class);
Laravel utilized all of the type-hinting features available in PHP at the time. However, many new features have been added to PHP in the subsequent years, including additional primitive type-hints, return types, and union types.
Release notes.
If you are using view function, you need to use the Illuminate\View\View class for type-hinting.
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use App\Models\Student;
class StudentController extends Controller
{
public function index(): View
{
$students = Student::all();
return view('students.index')
->with('students', $students);
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\CatalogueModel;
use Illuminate\Contracts\View\View;
class StudentController extends Controller
{
public function index(): View
{
$data['students'] = Student::all();
return view('students.index')->with($data);
}
}

Call to undefined method Auth::user()->can() in laravel 8 error

I have a problem with determining the permission with Auth::user()->can().
For example Auth::user()->can('trunk.index) returns always error;
But I have a problem.
If I dump $user->getPermissionsViaRoles(); ,I will get a large result.
I'm using different table user_view table.
And according to it I have changed in Auth.php file. and login is working fine.
'providers' => [
'users' => [
'driver' => 'self-eloquent',
'model' => App\Models\UserView::class,
]
],
But when I try to check permission the via Auth::user()->can('trunk.index) then it gives error below error.
Call to undefined method App\\Models\\UserView::can()
Below is my UserView model code.
<?php
namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Support\Facades\Hash;
use Spatie\Permission\Traits\HasRoles;
use Laravel\Lumen\Auth\Authorizable;
use Laravel\Sanctum\HasApiTokens;
class UserView extends Model implements AuthenticatableContract
{
use Authenticatable;
use HasFactory;
use HasRoles;
use HasApiTokens;
protected $table = 'user_view';
protected $primaryKey = "user_id";
protected $fillable = [
'username', 'password',
];
protected $guarded = [];
public function getAuthPassword()
{
return ['password' => $this->attributes['user_password']];
}
// public function can($abilities, $arguments = []) {
// }
}
help me if I'm missing something. Thank you.
You are using a custom User model which does not implement the \Illuminate\Contracts\Auth\Access\Authorizable interface and \Illuminate\Contracts\Auth\Access\Gate\Authorizable trait. You do actually have an import for this interface, but it is not used anywhere.
Also be careful about the existing import Laravel\Lumen\Auth\Authorizable. I'm not familiar with Lumen, but this might be a different implementation / wrong import.
You essentially need to update your model with the following two lines:
<?php
namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Foundation\Auth\Access\Authorizable; // <-- add import
use Spatie\Permission\Traits\HasRoles;
use Laravel\Sanctum\HasApiTokens;
class UserView extends Model implements AuthenticatableContract,
AuthorizableContract // <-- add interface
{
use Authenticatable;
use Authorizable; // <-- add trait
use HasFactory;
use HasRoles;
use HasApiTokens;
// ... other code ...
}

App\Repositories\AdminRepository::getAllAdmins(): Return value must be of type Illuminate\Pagination\Paginator, LengthAwarePaginator returned

I used paginate to display the database data but got the following error
App\Repositories\AdminRepository::getAllAdmins(): Return value must be of type Illuminate\Pagination\Paginator, Illuminate\Pagination\LengthAwarePaginator returned
What namespace should I use to fix it?
This is my AdminRepository.php
<?php
namespace App\Repositories;
use App\Repositories\Interfaces\AdminRepositoryInterface as AdminRepositoryInterface;
use Illuminate\Database\QueryException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use App\Models\Admin;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\EditPassword;
use Illuminate\Contracts\View\View;
use App\Http\Requests\CreateAdmin;
use App\Http\Requests\DeleteAdmin;
use App\Http\Requests\EditAdmin;
use App\Services\AdminService;
use Illuminate\Http\Request;
class AdminRepository implements AdminRepositoryInterface
{
public function getAllAdmins(int $count):Illuminate\Pagination\AbstractPaginator
{
return Admin::paginate($count);
}
This is my AdminRepositoryInterface.php
namespace App\Repositories\Interfaces;
use App\Models\Admin;
use Illuminate\Http\RedirectResponse;
interface AdminRepositoryInterface
{
public function getAllAdmins(int $count):Illuminate\Pagination\AbstractPaginator;
The result of the getAllAdmins() function is a type of LengthAwarePaginator because the Laravel paginate function return that type and your function return it. so, you should change the return type to Illuminate\Pagination\LengthAwarePaginator not Paginator.
use Illuminate\Pagination\LengthAwarePaginator;
...
public function getAllAdmins(int $count): LengthAwarePaginator
{
return Admin::paginate($count);
}

Laravel: Class not found if it is called from a Trait

After creating several Apps with Laravel and using softDelete properties I realized that methods like destroy(), restore() and kill() are exactly the same among several controllers. Therefore I am trying to put themn in a trait and use it from diferent Controllers.
My code is as follows:
ProfilesController.php
<?php
namespace App\Http\Controllers;
use App\Profile;
class ProfilesController extends Controller
{
public function destroy(Profile $profile)
{
Profile::del($profile, 'profiles');
return redirect()->route('profiles.index');
}
public function trashed()
{
Profile::trash('Profile');
}
}
Profile.php (model)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Profile extends Model
{
protected $fillable = ['user_id', 'role_id', 'title', 'subtitle', 'slug', 'birthday', 'about'];
use SoftDeletes, Helpers, commonMethods;
public function getRouteKeyName()
{
return 'slug';
}
// ... more code here
}
trait file: commonMethods.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use App\Profile;
use Session;
trait commonMethods
{
public static function del($element, $page_name)
{
$element->delete();
Session::flash('success', $element . ' successfully deleted!');
}
public static function trash($model)
{
$total = $model::onlyTrashed()->get();
$total_tr = count($total);
$all_tr = $model::all();
return view('partials.templates.trashed', compact('total', 'total_tr', 'all_tr'));
}
// ...more code here
}
The problem:
I try to visit the view "Trashed" that will list all elements "softdeleted" but not "killed", the method.
I pass the $model variable with the method trash($model)
I get the following error:
Class App/Profile does not found. Try to call App/Profile
I have debugged and the $model variable contains exactly what I need, the string 'Profile' which is what I need to build the Query:
$total = Profile::onlyTrashed()->get();
This query works while in the ProfilesController, but does not work while in a trait, since the model class is not found.
Any idea how could I make it work?
I am using Laravel 6.
If you need to use a class as a string you will want to use its full name. 'App\Profile' instead of 'Profile'.
$model = 'Profile';
new $model; // will use `\Profile`
$model = 'App\Profile';
new $model; // will use '\App\Profile';
In your controller( ProfilesController ) write :
use App\Profile;
In your model write :
use App\commonMethods;

Laravel Global Scope Auth

I've created an anonimus global scope in the users model as below in order to get only public users in the frontend:
protected static function boot()
{
parent::boot();
static::addGlobalScope('is_public', function(Builder $builder) {
$builder->where('is_public', '=', 1);
});
}
But... when i need to perform the login in the backend i need of course to check for not-public users so i need to exclude the global scope.
Is this possibile using the default AuthController of laravel?
Many Thanks!!
You just need to create two Models - one without global scope (i.e. AuthUser) and another with the global scope that extends the first one (i.e. User).
Then you can use AuthUser for authentication And User everywhere else.
You can remove any global scope on the fly with the following method:
User::withoutGlobalScope('is_public')->get();
I resolved it by creating the new package.
mpyw/scoped-auth: Apply specific scope for user authentication.
Run composer require mpyw/scoped-auth and modify your User model like this:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mpyw\ScopedAuth\AuthScopable;
class User extends Model implements UserContract, AuthScopable
{
use Authenticatable;
public function scopeForAuthentication(Builder $query): Builder
{
return $query->where('is_public', '=', 1);
}
}
Thats' all.
Either creating two separate models, I would prefer to put condition on the global scope because if you want to access the relationship methods from both models then you need to include those methods in both models or you have to extend one model to another. I think that is not a good solution.
create new file for the global scope:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
class IsPublicScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
if (Auth::hasUser()) {
$builder->where('is_public', '=', 1);
}
}
}
?>
and add this method to your user model:
protected static function boot()
{
parent::boot();
static::addGlobalScope(new IsPublicScope());
}
Thanks #mpyw for the correction.

Resources