minaremonshaker's avatar

Question About Adding Custom Methods in Laravel Policies

Hi, I have a question about Laravel policies. Is it possible to define a custom method in a policy, like createOwn, or is it better to stick with the default methods provided in the policy stubs?

I'm asking because, in the method below, I want to ensure that a user can only create their own ticket, so I plan to pass the ticket ID as an argument.

    public function create(User $user): bool
    {
        if ($user->hasPermissionTo('CreateTicket')) {
            return true;
        }

        return false;

    }
0 likes
14 replies
LaryAI's avatar
Level 58

Absolutely, you can add custom methods to your Laravel policies beyond the default ones like view, create, update, and delete.

For example, if you want to add a method like createOwn to only allow users to create resources they "own," you can define it just like any other policy method:

public function createOwn(User $user, SomeModel $model)
{
    return $user->id === $model->user_id;
}

Once you've added a custom method, you can authorize it in your controllers/blades using:

$this->authorize('createOwn', $model);
// or
@can('createOwn', $model)
    <!-- show create button -->
@endcan

So, you are not limited to the default methods. Feel free to add authorization logic that fits your application's needs!

tykus's avatar

I don't understand how the Ticket has a user_id already - how was the Ticket created before the Policy was invoked?

minaremonshaker's avatar

hi , i am making an api i have to pass the user_id to the ticket when creating it

{
    "title" : "my second ticket",
    "description" : "my second",
    "status" : "C",
    "user_id" : "3"
}
tykus's avatar

If you have an authenticated user, then you already have the User ID for the new Ticket. You do not (and should not) be accepting the user_id in the Request payload

martinbean's avatar
Level 80

i want to authorize that the user dose not create the ticket for other users

@minaremonshaker That’s validation, not authorisation. As others have pointed out, you can’t authorise access to a resource (i.e. a ticket) if that resource does not exist yet.

Why are you manually passing a user ID when creating a ticket in the first place? If a ticket should be assigned to the authenticated user when created, then you should set that ID instead of having the user ID being passed via a form.

class TicketController extends Controller
{
    public function store(StoreTicketRequest $request, #[CurrentUser] User $user)
    {
        $user->tickets()->create($request->validated());

        // Redirect...
    }
}

By creating a ticket through a relation on the authenticated user, the foreign key is automatically set, and you don’t need to do any validation and authorisation now.

minaremonshaker's avatar

I passed the authenticated user's ID to the service, so the ticket will be created exclusively for that user. Therefore, I don’t think any additional verification of the user ID is necessary since it’s assigned automatically.

  • Controller Method:
    public function store(StoreTicketRequest $request)
    {
        $this->authorize('create' , Ticket::class);

        $ticket = TicketsService::create($request->validated());

        return TicketResource::make($ticket);
    }
  • Store Ticket Request:
class StoreTicketRequest extends FormRequest
{

    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'title' => ['required' , 'max:100'],
            'description' => ['required'],
            'status' => ['required' , Rule::in(['A', 'C' , 'P'])],
           /* 'user_id' => ['required','exists:users,id'],*/
        ];
    }

    public function messages(): array
    {
        return [
            'status.in' => 'The status field needs to be in A,C,P',
            /*'user_id.exists' => 'There is no user with the provided id'*/
        ];
    }
}
  • Policy:
    public function create(User $user ): bool
    {
        if ($user->hasPermissionTo('CreateTicket') || $user->hasPermissionTo('CreateOwnTicket')) {
            return true;
        }

        return false;

    }
  • TicketService :
    public static function create(array $validated)
    {
        $validated = Arr::add($validated, 'user_id', auth()->user()->id);
        return Ticket::create($validated);
    }

Please or to participate in this conversation.