I've started to use Voyager and I've problems with a controller.
I've create a new table in database called Progress, voyager by default create a BREAD form to browse read delete and add items .
I like to put a default value into a field when the user go to add a new item. The default value that I like to put is authentication user_id
How can I do that?
Thanks.
You can do that completely outside of Voyager.
First exclude the authentication_user_id from the Add form (in Voyager's database interface). If the field doesn't take a null value you can set some temporary default, or modify your migrations - whichever is most convenient.
Next create a model observer and then utilise the created() function. For example:
<?php
namespace App\Observers;
use App\Models\Project;
class ProgressObserver
{
/**
* Listen to the Progress created event.
*
* #param Progress $progress
* #return void
*/
public function created(Progress $progress)
{
$progress->authentication_user_id = WHATEVER_YOU_DO_HERE;
$progress->save();
}
}
You can do that by creating a model for your bread, as shown in image
after you have done creating a model for your bread you can create a function named save
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Traits\Translatable;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Auth;
class MyViewModel extends Model
{
//
protected $table = "my_view";
public function save(array $options = [])
{
$this->user_id = \Auth::user()->id;
parent::save();
}
}
now whenever you save any record in administration of voyager, you will see current login user id is getting saved in your database table.
I think you can create a migration to write a default value for that field
You have to add following code into the model like this,
//assign created_by loggedin user
public function __construct(array $attributes = [])
{
$this->creating([$this, 'onCreating']);
parent::__construct($attributes);
}
public function onCreating($row)
{
// Placeholder for catching any exceptions
if (!\Auth::user()->id) {
return false;
}
$row->setAttribute('created_by', \Auth::user()->id);
$row->setAttribute('assign_to', \Auth::user()->id);
}
i have adding this because of my project need this. you can also add your field in onCreating() function.
Related
I am using Laravel Filament and made a Resource for User model which works fine.
I have a is_admin field in users table which return 0 and 1. I need users with is_admin = 0 but for now , i am getting all of them.
Can i add a where condition in filament to get only required fields.
The proper way to add additional where conditions with the built-in eloquent query are as follows:
public static function getEloquentQuery(): Builder
{
return static::getModel()::query()->where('is_admin', 1);
}
A bit late for the answer, bit here's an in depth guide.
There are two ways to go about it
#1 Pre-filtering query inside the resource
Inside your resource, override the following method:
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->where('is_admin', 0);
}
#2 Global Scope
Filament uses the eloquent interface, so applying a global scope will do the job aswell.
First, create a global scope class inside App\Models\Scopes\ (not a required path, only a suggestion):
<?php
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class AncientScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('is_admin', 0);
}
}
Then, modify your user model to apply the scope:
<?php
namespace App\Models;
use App\Models\Scopes\AncientScope;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::addGlobalScope(new AncientScope);
}
}
you can put ->where('role', '0') after return nameModal::query() at getTablequery(). \
like this
return nameModal::query()->where('role', '0');
Yes you can. You can extend getEloquentQuery() function at related resource class.Since you are talking about User model you can add above function as in the below code example to UserResource.php.
public static function getEleouentQuery () {
return User::where('is_admin',0);
}
Check this for more
So i create a column with
$table->enum('role', ['admin', 'customer'])->default('customer');
and i want a table with
if email with #domain.com then assign into role admin
else go to customer.
is there a way to do this in migration? or do i need to set up in model?
i'm a beginner in php and Laravel so please give me detailed instruction.
I invite you to create an observer on your Eloquent model.
You can read the doc at: https://laravel.com/docs/9.x/eloquent#observers
Remember to create a PHP enum to check your roles. This will allow you to more easily add roles or do additional checks in your code without having magic values:
<?php
enum Role : string
{
case ADMIN = 'admin';
case CUSTOMER = 'customer';
}
The creating event seems to be the most suitable since it will be observed during insertion :
<?php
namespace App\Observers;
use App\Models\User;
class UserObserver
{
/**
* Handle the User "creating" event.
*
* #param \App\Models\User $user
* #return void
*/
public function creating(User $user)
{
// Your logic here
if(str_ends_with($user->email, '#domain.com')) {
$user->role = Role::ADMIN->value;
} else {
$user->role = Role::CUSTOMER->value;
}
}
}
i want to access to data in the function of the controller using relationships on Laravel.
I will explain first my code:
I have 3 tables, projects, client and client_project.
At this moment, client_project don't have any relationship, i just add it manually.
Now i want to use relationships on laravel, but it's a bit confusing (for me at least).
I think it's not too much important the code of projects and clients table, just have id like primary key, and some fields more.
My migration of client_project looks like here:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateClientProjectTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('client_project', function(Blueprint $table)
{
$table->increments('id');
$table->integer('client_id');
$table->integer('project_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('client_project');
}
}
Client_Project model looks like here:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Client_Project extends Model
{
protected $fillable = ['client_id','project_id'];
public $table = 'client_project';
public function clients()
{
return $this->hasMany('App\Models\Project');
}
public function projects()
{
return $this->hasOne('App\Models\Client');
}
}
One client can have more than one project, but one project is only created by one client. I think relationships are declared good.
(At first, i think with relationships i don't need to make the client_project table), but i think that's a wrong idea. I want to make it with this table too.
So, now, the problem it's when i try to call on the function controller, i think i can access to data using por example:
App\Models\Project::find(1), like doc of laravel says.
The function is this:
$client = new Client();
$client->name = $request->input("nameClient");
$client->slug = $request->input("slugClient");
$client->priority = $request->input("priorityClient");
$client->save();
$client_project = new Client_Project();
$client_project->client_id = App\Models\Client::max('id');
$client_project->project_id = App\Models\Projects::max('id');
$client_project->save();
The part of the client, is working. I just take the value of some inputs and i create a new one.
The problem is with $client_project. I want to make it dynamic. I create the client and the project, and my code get the last one(the bigger id), and the last one(the bigger id too) of projects.
How can i access them using relationships?
Maybe need edit migration of client_project and put some key in project_id or client_id?
If need more information, please ask it.
Any help will be appreciated!
Here is your ans. You are going good way you created pivot table for client and project so you can attached as many projects to any client. Here is relationship with model.
Client Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
public function projects() {
return $this->belongsToMany(Project::class,'client_project');
}
}
Project model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Projects extends Model
{
public function client() {
return $this->belongsToMany(Client::class,'client_project');
}
}
?>
For Save project id use following way in controller method
$client = new Client();
$client->name = $request->input("nameClient");
$client->slug = $request->input("slugClient");
$client->priority = $request->input("priorityClient");
$client->save();
$project = new Project();
//include fields as per your table
$project->save();
$client->projects()->attach($project->id);
.
I need to do all url ids encrypted like :
user/edit/1
items/edit/35
posts/details/52
to
user/edit/sdfjk54dfds
items/edit/sdfjk54dfds
posts/details/sdfjk5s4dfds
there is lots of areas like blade files and in controllers that id used url('items/edit/2') and also in controller some function are passed by objects like public function itemedit(Items $items).
I tried $encrypt_val = Crypt::encrypt($value) and $decrypt_val = Crypt::decrypt($encrypt_val ); but I need to do it everywhere.
There is any short way or Middleware function to do it ?
Use Laravel Hashids
You can encode id like below
$encoded_id = Hashids::encode($id);
Your URL will be like below
<url>/users/edit/sdfjk54dfds
Hash ID installation guide
https://github.com/vinkla/laravel-hashids
You can use Uuid instead of using integer id. For this please follow the instruction:
Just create a trait:
trait Uuids
{
/**
* Boot function from laravel.
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->{$model->getKeyName()} = Uuid::generate()->string;
});
}
}
and in your model use above trait:
use SomeNamespcaeOfTrait;
class User extends Eloquent
{
use Uuids;
/**
* #var bool
*/
public $incrementing = false;
}
and in your migration use uuid instead of integer.
There's a package called Laravel HashSlug that acts as desired. Similarly to the one in sumit's answer, it's built on Hashids, but design specially to work with urls.
Using the above package all you need to do is add a trait and typehint in controller:
class Post extends Model {
use HasHashSlug;
}
// routes/web.php
Route::resource('/posts', 'PostController');
// app/Http/Controllers/PostController.php
public function show(Post $post){
return view('post.show', compact('post'));
}
Im trying to learn laravel 5 with help of this wondefull website.
For my activity model I want to generate slugs before I save one to my database so I've created the following model.
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Activity extends Model {
protected $table = 'activitys';
protected $fillable = [
'title',
'text',
'subtitle'
];
// Here I want to auto generate slug based on the title
public function setSlugAttribute(){
$this->attributes['slug'] = str_slug($this->title , "-");
}
//
}
But when I save an object with help of the Activity model slug is not filled, i tried changing it to $this->attributes['title'] = "test" for testing but it didnt run. Also I tried adding parameters $title, $slug to setSlugAttribute() but it didnt help.
What am I doing wrong and could someone explain the parameter that is used in some examples for setSomeAttribute($whyParameterHere).
Note : there is a slug field in my database.
As suggested by user3158900 I've tried :
public function setTitleAttribute($title){
$this->title = $title;
$this->attributes['slug'] = str_slug($this->title , "-");
}
//
This makes my title field empty but saves the slug the way I want it, why is $this->title empty then ?
If I remove $this->title = $title; both title and slug are empty
I believe this isn't working because you aren't trying to set a slug attribute so that function never gets hit.
I'd suggest setting $this->attributes['slug'] = ... in your setTitleAttribute() function so it runs whenever you set a title.
Otherwise, another solution would be to create an event on save for your model which would set it there.
Edit: According to comments, it's also necessary to actually set the title attribute in this function as well...
public function setTitleAttribute($value)
{
$this->attributes['title'] = $value;
$this->attributes['slug'] = str_slug($value);
}
You got 2 ways:
1. Add localy in your controller method this line:
$request['slug'] = Str::slug($request->title);
Example:
//use Illuminate\Support\Str;
public function store(Request $request)
{
$request['slug'] = Str::slug($request->title);
auth()->user()->question()->create($request->all());
return response('Created!',Response::HTTP_CREATED);
}
2. Add it in your model to check it every save in db
//use Illuminate\Support\Str;
protected static function boot() {
parent::boot();
static::creating(function ($question) {
$question->slug = Str::slug($question->title);
});
}
Example:
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
use App\User;
use Illuminate\Support\Str;
class Question extends Model
{
protected static function boot() {
parent::boot();
static::creating(function ($question) {
$question->slug = Str::slug($question->title);
});
}
//The rest of methods
In each way you have to add this code before class declaration:
use Illuminate\Support\Str;
One way to accomplish this would be to hook into model events. In this instance, we want to generate a slug upon creating.
/**
* Laravel provides a boot method which is 'a convenient place to register your event bindings.'
* See: https://laravel.com/docs/4.2/eloquent#model-events
*/
public static function boot()
{
parent::boot();
// registering a callback to be executed upon the creation of an activity AR
static::creating(function($activity) {
// produce a slug based on the activity title
$slug = \Str::slug($news->title);
// check to see if any other slugs exist that are the same & count them
$count = static::whereRaw("slug RLIKE '^{$slug}(-[0-9]+)?$'")->count();
// if other slugs exist that are the same, append the count to the slug
$activity->slug = $count ? "{$slug}-{$count}" : $slug;
});
}
You will also need to add the following to your applications list of aliases (app.php):
'Str' => Illuminate\Support\Str::class,
You could use this package which I use https://github.com/cviebrock/eloquent-sluggable or check how it applies an observer on the model saving and how it generates a unique Slug, then do the same.
You want to set the slug based off the title when the title attribute is being set.
public function setTitleAttribute($value)
{
$this->attributes['title'] = $value;
$this->attributes['slug'] = str_slug($value);
}
/// Later that same day...
$activity->title = 'Foo Bar Baz';
echo $activity->slug; // prints foo-bar-baz
Another alternative would be to use a ModelObserver and listen to the saving event. This will allow you to generate the slug right before the model is written to the database.
class ActivityObserver {
public function saving($activity)
{
$activity->slug = str_slug($activity->title);
}
}
In both cases you probably want to add some logic to test if the slug already exists in the DB, adding an incrementing number if it does. ie foo-bar-baz-2. The safest place for this logic would be in the ModelObserver as it is executed immediately prior to the write action.
You can use this method. This is one that I am using to get unique SEO friendly slug. This will work in all laravel versions. https://stackoverflow.com/a/72137537/7147060
It's an old post, but this is what you find these days when searching for modern solutions, so here is a modern solution:
When using Laravel ^9.x, the Attribute mutator can be used, and must look something like this:
use Str;
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function name(): Attribute
{
return Attribute::make(
set: fn($value) => ['slug' => Str::slug($value), 'name' => $value]
);
}
Setting it with $this->slug inside the closure won't work as the result vanishes in a merge.