How do i set default value with conditional in laravel migrate? - php

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

Related

Method Illuminate\Database\Eloquent\Collection::addEagerConstraints does not exist LARAVEL

I need help, don't see anything suspicious :c thanks for help !
Error Collection::addEagerConstraints does not exist occurs after the call:
public function show(Request $request, User $user)
{
$user->load('permissions');
dd($with);
return UserResource::make($user);
}
User Model:
class User extends Authenticatable
{
(...)
//////////////////////////////////////////////////////////////////////////////////////////
///
/// Relationships
///
//////////////////////////////////////////////////////////////////////////////////////////
/**
* Relationship to permissions
*
* #return RolePermissions
*/
public function permissions()
{
return $this->role()->first()->permissions;
}
}
if you are using standard laravel user ,
you have to remove your 'permissions' relation and use the ready-made one:
$permissionNames = $user->getPermissionNames(); // collection of name strings
$permissions = $user->permissions; // get the user permissions
if you want a user with its permissions:
$user->load('permissions');
more details in:
https://docs.spatie.be/laravel-permission/v3/basic-usage/basic-usage/

Using custom authentication on Laravel 6

I would like to manually authenticate the users in my company. The issue is that, I have 2 tables, called Student and Staff in the Oracle database.
As for the Student table, I get the idea of overriding the built in Auth method provided through the auth scaffolding command as the username and password are stored right into the table.
As for the Staff table, the password is stored a different column/table and encrypted using a stored procedure/package so the only way to get the user validation is by calling the package which only returns 0 or 1 only.
What I have done,
I wrote my own Routes, and added my own functions in LoginController.
public function loginStaff(Request $req){
$username = Str::upper($req->input('username'));
$password = $req->input('password');
$users = PortalUser::where('ID', $username)->firstOrFail();
if ($users->user_type == 'STAFF'){
$queryResult = DB::select('select PACKAGE.validStaff(?,?) from dual',[$username, $password]);
if($queryResult == 1){
//this is where I would like to auth the user.
//using Auth::Attempt and Auth::Login will only run the default query
}
}
I have successfully returned value of 1 and 0 in the controller.
So is there anything that I am missing?
Or should I manually set the session by myself using the session() method?
Thank you.
If you want to manually authenticate users, you can easily use sessions. Have the following code as reference:
//this is where I would like to auth the user.
//using Auth::Attempt and Auth::Login will only run the default query
// typically you store it using the user ID, but you can modify the session using other values.
session()->put('user_id', user id from database here);
And if you want to check whether user is authenticated, modify RedirectIfAuthenticated middleware to this:
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (session()->has('user_id')) {
return redirect( custom path here );
}
return $next($request);
}
}
When you want to logout the user, simply destroy the session key
session()->forget('user_id');
**Note: ** many broadcasting and addons use Laravel's authentication system (Guards) and you may need to hook into their code if you want to use them with your custom auth system
Laravel provides Custom Session Drivers which you can use to create or delete your sessions
<?php
namespace App\Extensions;
class MongoSessionHandler implements \SessionHandlerInterface
{
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
Hope it helps, if not then comment down below. Will help you out.
###### Update #######
I think then you do have to make custom HTTP sessions from Laravel
Step 1: Create another table in your database for session, like this;
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->unsignedInteger('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
Step 2: Store data in the session, you will typically use the put method or the session helper;
// Via a request instance...
$request->session()->put('key', 'value');
// Via the global helper...
session(['key' => 'value']);
Step 3: Get the key for specific user when your function returns 1
$value = $request->session()->get('key', function () {
return 'default';
});
Step 4: Delete the session, after some time you need to delete the session for security reasons then you can do.
$value = $request->session()->pull('key', 'default');

Retrieve and order data from two columns

I'm starting to get confused. I have an user model and an event models. A user can create an event, he is the owner. But he can also get invited to an event, he is a guest. The first relation is a OneToMany relation and the other one is a ManyToMany relation.
Now, I would like to retrive all the events of an user, owned or guest. Every events and order them by the field date.
This my user model :
class User extends Authenticatable
{
/**
* Get the events of the user.
*/
public function owned_events()
{
return $this->hasMany('App\Event', 'owner_id');
}
/**
* Get the events list.
*/
public function events()
{
return $this->belongsToMany('App\Event')
->using('App\Invitation')
->withPivot('status')
->withTimestamps();
}
}
This is the event model :
class Event extends Model
{
/**
* Get the owner of the event.
*/
public function owner()
{
return $this->belongsTo('App\User');
}
/**
* Get the guests list.
*/
public function guests()
{
return $this->belongsToMany('App\User')
->using('App\Invitation')
->withPivot('status')
->withTimestamps();
}
}
This is what I tried (inside an EventRepository)
/**
* Return all the events (owner and guest) of a user ($id).
*/
public function all($id)
{
$guested = $this->event->guests()->where('user_id', $id)->get()->load('owner', 'guests');
$own = $this->event->where('owner_id', $id)->get()->load('owner', 'guests');
return $guested->merge($own)->sortBy('date');
}
It works... but it gives me only the owned events, not where my user is the guest... I think that there is a much better way to do it. Two calls for one request is pretty bad and two loads is even worse no?
I think I found the solution :
$user = Auth::user()->load('owned_events', 'events'));
$events = $user->events->merge($user->owned_events)->sortBy('date');
return view('events.index', compact('events'));
Go throught the event model was way too hard while go throught the user model is much easier :)

Laravel Voyager overwrite BREAD controller

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.

Symfony Restful API - Expose virtual property isLiked by current logged in user

There are two entities Restaurant and Users. Restaurant entity has many-to-many relation with user, field name favoriteBy.
<many-to-many field="favoriteBy" target-entity="UserBundle\Entity\Users" mapped-by="favoriteRestaurants"/>
I am using JMS Serializer along with FOSRestfulAPI. In restaurant listing API I have to expose one extra boolean field "isFavorited", which will be true if current logged in user has in array collection favoriteBy.
How I can find whether current user has favorited the restaurant or not within entity?
/**
* Get is favorited
* #JMS\VirtualProperty()
* #JMS\Groups({"listing", "details"})
*/
public function isFavorited()
{
// some logic in entity
return false;
}
One way I am thinking is to inject current user object to entity and user contains method to find out, but its look like not good approach.
Please suggest me some method, or guide me to right direction.
You could implments an EventSubscriberInterface as described here in the doc.
As Example:
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
...
class RestaurantSerializerSubscriber implements EventSubscriberInterface
{
protected $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public static function getSubscribedEvents()
{
return [
[
'event' => 'serializer.post_serialize',
'class' => Restaurant::class,
'method' => 'onPostSerialize',
],
];
}
public function onPostSerialize(ObjectEvent $event)
{
$visitor = $event->getVisitor();
$restaurant = $event->getObject();
// your custom logic
$isFavourite = $this->getCurrentUser()->isFavourite($restaurant);
$visitor->addData('isFavorited', $isFavourite);
}
/**
* Return the logged user.
*
* #return User
*/
protected function getCurrentUser()
{
return $this->tokenStorage->getToken()->getUser();
}
And register, as YML example:
acme.restaurant_serializer_subscriber:
class: Acme\DemoBundle\Subscriber\RestaurantSerializerSubscriber
arguments: ["#security.token_storage"]
tags:
- { name: "jms_serializer.event_subscriber" }
Hope this help
PS: You could also intercept the serialization group selected, let me know if you neet that code.
Entity should know nothing about current logged in user so injecting user into entity is not a good idea.
Solution 1:
This can be done with custom serialization:
// serialize single entity or collection
$data = $this->serializer->serialize($restaurant);
// extra logic
$data['is_favourited'] = // logic to check if it's favourited by current user
// return serialized data
Solution 2
This can be also achieved by adding Doctrine2->postLoad listener or subscriber after loading Restaurant entity. You can add dependency for current authenticated token to such listener and set there Restaurant->is_favorited virtual property that will be next serialized with JMS.

Categories