Laravel Global Scope Auth - laravel

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.

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);
}
}

How can i get result from model in laravel 5

Good day, i'm trying to get the result from my model that called with Mainmodel through my controller, my controller is MainController.
Here is my controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use app\Mainmodel;
class MainController extends Controller
{
function index(){
echo "Kok, direct akses sih?";
}
function get_menu(){
$menu = app\Mainmodel::request_menu();
dd($menu);
}
}
Here is my model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Mainmodel extends Model
{
function request_menu(){
$menu = DB::table('menu')
->orderBy('[order]', 'desc')
->get();
return $menu;
}
}
my routes
Route::get('menu','MainController#get_menu');
with my script above i get this
FatalErrorException in MainController.php line 17: Class
'App\Http\Controllers\app\Mainmodel' not found
how can i fix this ? thanks in advance.
Note: I'm bit confuse with laravel. I'm using codeigniter before. And i have a simple question. In laravel for request to database should i use model ? or can i just use my controller for my request to database.
sorry for my bad english.
I would imagine it's because your using app rather than App for the namespace.
Try changing:
app\Mainmodel
To:
App\Mainmodel
Alternatively, you can add a use statement to the top of the class and then just reference the class i.e.:
use App\Mainmodel;
Then you can just do something like:
Mainmodel::request_menu();
The way you're currently using you models is not the way Eloquent should be used. As I mentioned in my comment you should create a model for each table in your database (or at least for the majority of use cases).
To do this run:
php artisan make:model Menu
Then in the newly created Menu model add:
protected $table = 'menu';
This is because Laravel's default naming convention is singular for the class name and plural for the table name. Since your table name is menu and not menus you just need to tell Laravel to use a different table name.
Then your controller would look something like:
<?php
namespace App\Http\Controllers;
use App\Menu;
class MainController extends Controller
{
public function index()
{
echo "Kok, direct akses sih?";
}
public function get_menu()
{
$menu = Menu::orderBy('order', 'desc')->get();
dd($menu);
}
}
Hope this helps!
You can solve it by different solution. The solution is you don't have to call request_menu(); you can get it in your controller.
MainController
use use Illuminate\Support\Facades\DB;
public function get_menu(){
$menu = DB::table('menu')
->orderBy('Your_Field_Name', 'DESC')
->get();
dd($menu);
}

how to extend Builder class in laravel 5.2

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

Unable to maintain one to many relationship in Eloquent using laravel 5.3

I am using laravel eloquent model so there are three tables tempsocials, tempusers and tempdevices. so one user can have multiple devices and multiple social acounts.
I created a models for three of above table and trying to maintain relationship in between like following
This is my Tempuser model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tempuser extends Model
{
public function tempsocials(){
return $this->hasMany('App\Tempsocial');
}
public function tempdevices(){
return $this->hasMany('App\Tempdevice');
}
}
This is my Tempdevice model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tempdevice extends Model
{
public function tempusers(){
return $this->belongsTo('App\Tempuser');
}
}
And this one is last Tempsocial model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tempsocial extends Model
{
public function tempusers(){
return $this->belongsTo('App\Tempuser');
}
}
Now this is my controller where i want to retrive all the devices and social accounts of particular user
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Collection;
use App\Http\Requests;
use App\tempLogin;
use App\Tempdevice;
use App\Tempuser;
use App\Tempsocial;
class loginController extends Controller
{
public function check_credentials(Request $request){
$count=0;
if($request->header('content-type')=='application/json'){
$temp=new Tempuser;
$devices = $temp->tempdevices();
return $devices;
}
}
}
But i got following error:
Object of class Illuminate\Database\Eloquent\Relations\HasMany could
not be converted to string
You're making a new Tempuser(), it has no id, so your relation returns nothing as expected, you will need to pass an id to the method and with that id you could do something like:
Tempuser::find($id);
This will then return an actual model instead of creating a new one.
Also because when you call ->tempdevices() as a function it will return a query builder, instead when you do ->tempdevices it will return a collection, change it like this:
$devices = $temp->tempdevices;
Also, if you expect a json response (if thats not the case you can ignore this part), it might be better to also state it in your return by doing:
return response()->json($devices);

Polymorphic relations in upgraded Laravel app from 4.2 to 5

Short: some related models are returning instances correctly, but some aren't (the polymorphic ones).
I have those three models:
app/Models/User.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function company()
{
return $this->hasOne('App\Company');
}
}
app/Models/Company.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model {
public function user()
{
return $this->belongsTo('App\User');
}
public function address()
{
// Also tested with morphMany, without success
return $this->morphOne('App\Address', 'addressable');
}
}
app/Models/Address.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Address extends Model {
public function addressable()
{
return $this->morphTo();
}
}
And the controller:
app/Http/Controllers/MyController.php
<?php namespace App\Http\Controllers;
// ... many "use" clauses not relevant to the question
use Auth;
// ...
use App\Address;
use App\Company;
use App\User;
class MyController extends Controller {
// Ok here
$user = Auth::user();
// Ok here, too
$company = $user->company()->first();
// Here is the problem; $address is null
$address = $company->address()->first();
}
The line $company->address()->first(); is always returning null to $address in Laravel 5, but it worked well in Laravel 4.2
In L4 models were not namespaced by default, so they were saved as ModelName in your table, while now in L5 they are rather Namespace\ModelName and are retrieved the same way.
That said, your data saved in L4 needs to be adjusted so it matches your current models, or you can use protected $morphClass on the models.
However take this into consideration for the latter solution.
If you open your database - you'll see the relationship in your old L4 data stored as: User or Company
You need to run a script that updates the columns to the new namespace names - such as App\User or App\Company
This is because you are now namespacing your models - so Laravel needs to know which namespace to call.
Along with #The Shift Exchange's answer and following my question's example, you can follow this approach:
Instead of adding the namespace in addressable_type column values from address table (and this is a valid solution), you can use $morphClass:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model {
protected $morphClass = 'Company';
public function user()
{
return $this->belongsTo('App\User');
}
public function address()
{
// Also tested with morphMany, without success
return $this->morphOne('App\Address', 'addressable');
}

Resources