Laravel Spatie Permissions - how to change default model 'role' by another model - laravel

please how can i change the default model 'role' by another model in my project (laravel project) has the same architecture as 'role'; the default model package.
in the config/permission.php config file contains:
'models' => [
/*
* When using the "HasPermissions" trait from this package, we need to know which
* Eloquent model should be used to retrieve your permissions. Of course, it
* is often just the "Permission" model but you may use whatever you like.
*
* The model you want to use as a Permission model needs to implement the
* `Spatie\Permission\Contracts\Permission` contract.
*/
'permission' => Spatie\Permission\Models\Permission::class,
/*
* When using the "HasRoles" trait from this package, we need to know which
* Eloquent model should be used to retrieve your roles. Of course, it
* is often just the "Role" model but you may use whatever you like.
*
* The model you want to use as a Role model needs to implement the
* `Spatie\Permission\Contracts\Role` contract.
*/
'role' => Spatie\Permission\Models\Role::class,
],
i want to have something like this:
'role' => App\Fonction::class,
the documentation says that i have to implement the
Spatie\Permission\Contracts\Role` contract.
any idea how can i do this in the right way.
the Fonction Model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Fonction extends Model
{
protected $fillable = [
'nom','description'
];
public function comptes()
{
return $this->hasMany('App\Compte') ;
}
}

You can extend Spatie\Permission\Models\Role class. It already implements Spatie\Permission\Contracts\Role interface. Check details in doc.
<?php
namespace App;
use Spatie\Permission\Models\Role;
class Fonction extends Role
{
protected $fillable = [
'nom','description'
];
public function comptes()
{
return $this->hasMany('App\Compte') ;
}
}

Related

I got an odd question on laravel's migration [duplicate]

This question already has answers here:
Laravel seed issue, laravel is looking for plural table name
(2 answers)
Closed 1 year ago.
I have been trying to google this but I still couldn't pinpoint the exact answer to the question in my head.
I have used php artisan to create a migration file to set up a table called blogs (note the plural). Previously, the table was called blog (singular) and the factory would not seed because the error shown on the terminal was that no relations found for "blogs" - which didn't make sense to me because every reference I used in the controllers, models and factories were singular. It would not let me seed until I have rolled back the migration and re-created the table as blogs in plural form.
And the strangest thing is that I have kept everything else in singular still, anyone got any clues as to why the seeding works only when I used plural for the table's name?
This is my migration file after the table is revised from blog to blogs:
class CreateBlogsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('blogs', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title', 255);
$table->text('body');
$table->text('user_id');
});
}
This is my factory - named BlogFactory:
namespace Database\Factories;
use App\Models\Blog;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class BlogFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Blog::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'title' => $this->faker->sentence, //Generates a fake sentence
'body' => $this->faker->paragraph(30), //generates fake 30 paragraphs
'user_id' => User::factory() //Generates a User from factory and extracts id
];
}
}
This is my model - named Blog:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model
{
use HasFactory;
protected $fillable = [
'title',
'body',
'user_id',
];
}
This is my controller - named BlogController:
<?php
namespace App\Http\Controllers;
use App\Models\Blog;
use Illuminate\Http\Request;
class BlogController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return Blog::all();
}
I seem to recall similar issues regarding renamed class-names and/or tables... Could you try running "composer dump-autoload" after having all the migrations and/or class-name refactorings ready? I remember old class-names being somehow cached, which gave me an headache. Apparently dumping autoload should rebuild this cache.
Edit: With your newest edit you will not need to do this change as you have changed the migration from creating a blog table to creating a blogs table.
You will need to edit your model to understand that you use non-standard Laravel formatting for your table name.
Laravel, per default, will assume your table is a pluralized version of your model name. To override this, you need to add the following attribute to the model: protected $table = 'blog';
See below code; however, I suggest not changing this and sticking to the Laravel defined standards. The closer you are to doing it the way the framework wants, the easier it will be for you. Especially when learning, it is much easier not to fight the framework at the same time.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model
{
use HasFactory;
protected $table = 'blog';
protected $fillable = [
'title',
'body',
'user_id',
];
}

Using Sanctum with Laravel Spark conflict

My setup
Laravel 8
Laravel Spark Mollie
I'm constantly hitting a brick wall when calling API requests with Spark & Sanctum. I've installed Sanctum with no problem and migrated.
I've added use Laravel\Sanctum\HasApiTokens; to app/Models/User.php and added use HasApiTokens; to the class.
My Api.php route
Route::group([
'middleware' => 'auth:sanctum'
], function () {
Route::get('categories', [\App\Http\Controllers\categories::class, 'fetchCategories']);
});
When I call the Api I get this error
ErrorException
Declaration of Laravel\Sanctum\HasApiTokens::tokenCan(string $ability) should be compatible with Laravel\Spark\User::tokenCan($ability)
I've tried changing use Laravel\Sanctum\HasApiTokens; to Laravel\Spark\HasApiTokens on User.php. The error goes away, but whenever I try calling the Api, it returns me back to the login homepage.
Any ideas? As the Spark documentation doesn't really explain how Sanctum or Api protection work.
The problem is that your main User class extends the User class from the vendor Spark library. This User model uses the trait named HasApiTokens which is not the same as Sanctum
Since you don't want to change the file from the vendor directory, one fix I found was to copy the original SparkUser model class from the vendor and create a new one like this and remove the trait HasApiTokens since you don't want to use it anymore.
<?php
namespace App\Models\Users;
use Illuminate\Support\Str;
use Laravel\Spark\Billable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class SparkUser extends Authenticatable
{
use Billable, Notifiable; // HasApiTokens was removed from the original SparkUser class
/**
* Get the profile photo URL attribute.
*
* #param string|null $value
* #return string|null
*/
public function getPhotoUrlAttribute($value)
{
return empty($value) ? 'https://www.gravatar.com/avatar/'.md5(Str::lower($this->email)).'.jpg?s=200&d=mm' : url($value);
}
/**
* Make the team user visible for the current user.
*
* #return $this
*/
public function shouldHaveSelfVisibility()
{
return $this->makeVisible([
'uses_two_factor_auth',
'country_code',
'phone',
'card_brand',
'card_last_four',
'card_country',
'billing_address',
'billing_address_line_2',
'billing_city',
'billing_state',
'billing_zip',
'billing_country',
'extra_billing_information'
]);
}
/**
* Convert the model instance to an array.
*
* #return array
*/
public function toArray()
{
$array = parent::toArray();
if (! in_array('tax_rate', $this->hidden)) {
$array['tax_rate'] = $this->taxPercentage();
}
return $array;
}
}
And now all I had to change was my original User class model to use this new model like this and add the trait HasApiTokens from Sanctum!
use App\Models\SparkUser; // Modified from the original in the vendor folder
use Laravel\Sanctum\HasApiTokens;
class User extends SparkUser
{
use HasApiTokens;
...
}

laravel one-to-many relationship is null

I have 3 models: User, Company and Branch.
In a blade file i want to be able to display the branch the company of the user belongs to.
In my opinion i should have the following relationships:
User -> Company : user belongsto a company and a company has many users , so this in a one-to-many relationship.
Company -> Branch: A company belongsto a branch and a branch can have many companies. So once again a one-to-many relationship.
I have foreign keys in the users table: company_id which references id on the company table.
Another FK in the company table: branch_id which references id on the branch table.
In my blade file want to display the branch name like this: {{ $user->company->branch->name }} where only name is a property. Company and branch are relationships.
My query looks like this:
$users = User::with(['company','company.branche' => function($q){
$q->select('name');
}])->inRandomOrder()->paginate(24);
<?php
namespace App;
use App\Events\GeneralEvent;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Nicolaslopezj\Searchable\SearchableTrait;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable, SoftDeletes, HasRoles, SearchableTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'gender', 'first_name','last_name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
...
public function company()
{
return $this->belongsTo(Company::class,'company_id');
}
}
<?php
namespace App;
use App\Events\GeneralEvent;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Nicolaslopezj\Searchable\SearchableTrait;
class Company extends Model
{
use SoftDeletes, SearchableTrait;
...
public function branche()
{
return $this->belongsTo(Branche::class);
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Nicolaslopezj\Searchable\SearchableTrait;
class Branche extends Model
{
protected $fillable = [
'name'
];
protected $searchable = [
'columns' => [
'name' => 10,
],
];
public function companies()
{
return $this->hasMany(Company::class);
}
}
However when i dump the $user->company i get null. So adding the branch after that is pointless for now. When i dump the user the relation shows up but is null. I have no idea where i am going wrong. Can someone please help?
You have to include the id of the branch so that eloquent can link the branch and company
you can do like that
$users = User::with(['company','company.branche' => function($q){
$q->select('id','name');
}])->inRandomOrder()->paginate(24);
OR Like that
$users = User::with('company.branche:id,name')->inRandomOrder()->paginate(24);
So the problem was i had one of my foreign keys pointing to the wrong table. Doh.

Extended User Model in a Package

Could you help me understand the right way to extend existing models? I'm developing a package and want to do as much as possible separated from the main application.
I want to have all existing functionality of the User model, but only add a relation to another model. In my package User I can have several (hasMany) Article. Instead of adding a method to \App\User I created a new model in my package class User extends \App\User:
namespace Package\Sample;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
/**
* Class User
* #package Package\Sample
*/
class User extends \App\User
{
use HasApiTokens, Notifiable;
public function articles()
{
return $this->hasMany(Article::class);
}
}
To make it work I add the configuration for my package auth.php:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \Package\Sample\User::class,
],
],
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
My question: Is it a "best practice" to extend functionality of existing models?
I solved it by using the class_alias() php function.
In my package service provider I setup an alias of the model class defined for Authentication in /config/auth.php like this:
public function boot(){
class_alias(config("auth.providers.users.model"), 'ParentModel');
}
then I use ParentModel class where needed:
use ParentModel;
class Agent extends ParentModel {
...
}
Hope It makes sense for someone
that will prevent edits on the \Package\Sample\User::class. any new method needed will result in a package update.
why not declare a trait in your package containing your methods and use them in the App\User::class like what laravel is using.
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
I tried using the class_alias and although it works for basic usage, when things got more complicated my user class couldn't cut it. For example, my notifications where using the local package user type and not showing in app.
After doing more research I found using a trait IS the proper way like others have mentioned.
I found a comprehensive guide here: https://laravelpackage.com/08-models-and-migrations.html#approach-2-using-a-polymorphic-relationship
the gist:
Create a trait in your package:
Important here you can setup whatever the relationship you need depending on you db modeling.
// 'src/Traits/HasPosts.php'
<?php
namespace JohnDoe\BlogPackage\Traits;
use JohnDoe\BlogPackage\Models\Post;
trait HasPosts
{
public function posts()
{
return $this->morphMany(Post::class, 'author');
}
}
Add the use in whatever user classes it applies to in your app
// 'App\Models\User.php'
<?php
namespace App\Models;
use JohnDoe\BlogPackage\Traits\HasPosts;
class User extends Authenticatable
{
use HasPosts;
...
Lastly, you'll need to add an extra field in the db for the user_type where you are using the user_id.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserTypeToPostTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->tinyText('user_type')
->comment('User class type')
->nullable();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('user_type');
});
}
}
You need to Add config(['auth.providers.users.model' => Myname\Myproject\App\Models\User::class]); to the boot-method inside my package-service-provider.
And Create new Class in your package.
namespace Myname\Myproject\App\Models;
class User extends \App\User
{
public function roles(){
return $this->belongsToMany('Myname\Myproject\App\Models\Role', 'user_role', 'user_id', 'role_id');
}
}

laravel algolia send only specific fields

Is there a way with laravel and algolia package to update to the index not ALL the fields but only the ones i need?
You can use getAlgoliaRecord() method in your model and return array from it with attributes you want to index.
Example:
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
use AlgoliaEloquentTrait;
public function getAlgoliaRecord()
{
return [
'indexedAttribute' => $this->indexedAttribute,
'otherIindexedAttribute' => $this->otherIindexedAttribute,
'nextIndexedAttribute' => $this->nextIndexedAttribute,
];
}
}
#JanPetr answer is correct but only for laravel 4.
For Laravel 5.3 and above,
As mentioned in docs
By default, the entire toArray form of a given model will be persisted to its search index. If you would like to customize the data that is synchronized to the search index, you may override the toSearchableArray method on the model.
<?php
namespace App;
use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use Searchable;
/**
* Get the indexable data array for the model.
*
* #return array
*/
public function toSearchableArray()
{
$array = $this->toArray();
// Customize array...
$array = [
'post_name' => $this->post_name,
'post_author' => $this->author,
'publisher' => $this->publisher,
'publishing_date' => $this->published_at
];
return $array;
}
}

Resources