minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

2mos ago

Hi everyone, I’m using the Spatie Laravel Permission package in my project, and I’m wondering if it’s considered a best practice to extend the default Role and Permission models and place them inside my app’s Models folder, rather than using the package’s built-in ones directly.

Would this approach make sense for better maintainability or customization, or is it generally better to stick with the package defaults unless I really need custom behavior?

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

2mos ago

What do you mean by reguler web app do you mean app that uses blade or react ?

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

2mos ago

Best systematic way to plan all permissions for Laravel 12 ticketing system API with Spatie?

I'm building a comprehensive ticketing system API using Laravel 12 with Spatie Laravel-Permission for role-based authorization (roles like admin, manager, agent, customer).

I've implemented controllers for:

  • Tickets (CRUD)
  • Roles/permissions management (assign/revoke/view for roles)
  • User search/filtering

Current permissions (snake_case pattern): tickets: view_any_ticket, view_ticket, create_ticket, update_ticket, delete_ticket, assign_ticket roles: view_role_permissions, assign_role_permissions, revoke_role_permissions, update_role_permissions permissions: view_any_permission, create_permission, update_permission, delete_permission

My approach:

  • Map permissions to controller actions (create_ticket, update_ticket_status)
  • Policies + Gates (TicketPolicy::viewAny() checks $user->can('view_any_ticket'))
  • Artisan command to seed permissions

Code example RolesPermissionsController@assign:

public function assign(Request $request, Role $role)
{
    Gate::authorize('assign_permission_to_role', Permission::class);
    $role = RoleService::assignRole($role, $request->permissions);
    return PermissionsResource::collection(PermissionService::getPermissionsOfRole($role));
}

Struggling to identify ALL permissions without missing edge cases or over-engineering.

Questions:

What's the best systematic process to discover/plan permissions for ticketing system? (routes analysis, user stories, audit logs?)

Common permission patterns for ticketing apps?

    Ticket assignment

    Status changes

    Comments/attachments

    Escalations

    Reports/SLAs?

Granularity level?

    update_ticket (all fields)

    OR update_ticket_priority, update_ticket_status, update_ticket_assignee?

Tools/scripts to auto-generate permission seeds from routes/controllers?

Role/permission management auth?

    Direct Spatie: $user->can('view_role_permissions')

    OR Policies wrapping Spatie checks?
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

2mos ago

Hi @tykus,

Thanks for your reply. In this case, will the before callback run by default, or do I need to explicitly call it via Gate::authorize in the controller?

 Gate::athorize("before" , Tickit::class)
minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

2mos ago

I'm trying to get a solid grasp on how Laravel handles route specificity when multiple routes could potentially match a given URI. From what I've read, routes are matched based on the order they're defined, with more specific (static) routes taking precedence over parameterized ones. But I'd love some clarification and examples from experienced devs.

For instance:

  • If I have Route::get('/foo/bar', 'ControllerA') defined before Route::get('/foo/{slug}', 'ControllerB'), does / foo/bar always hit ControllerA first due to specificity?

  • What if both are parameterized, like /foo/{id} vs /foo/{slug}?

  • Any gotchas with route groups, middleware, or API routes?

Also, best practices for ordering routes in routes/web.php or routes/api.php to avoid surprises? php artisan route:list helps verify, but understanding the rules upfront would save headaches in larger apps.

minaremonshaker's avatar

minaremonshaker liked a comment+100 XP

2mos ago

Yes, the Gate::before callback will bypass your TicketPolicy::view() method if it returns a non-null value.

Here's how it works:

  • When an ability is being checked (e.g. Gate::authorize('view', $ticket);), Laravel will first run any Gate::before callbacks.
  • If your Gate::before returns a non-null value (true or false), that value is immediately considered the final answer for the authorization check, and no further policy methods will be called for that ability check.
  • If your Gate::before returns null, Laravel falls through to the associated policy method (like view) and evaluates that as normal.

So, with your code:

Gate::before(function (User $user, $ability) {
    if ($user->hasAnyPermission(['view_any_ticket'])) {
        return true;
    }
    return null;
});

If the user has the view_any_ticket permission, Gate::before returns true, and Laravel grants access for any ability (including 'view'), without ever calling your policy's view method.

To sum up:
If Gate::before returns true, the TicketPolicy::view() method is not called and access is granted immediately.

Reference:
The official Laravel documentation on Gates says:

"If the before callback returns a non-null result that result will be considered the result of the authorization check."

So in your scenario, yes, the global Gate::before will bypass the policy method if it returns true.

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

2mos ago

I’m defining a global Gate::before check in my AppServiceProvider like this:

Gate::before(function (User $user, $ability) {
    if ($user->hasAnyPermission(['view_any_ticket'])) {
        return true;
    }
    return null;
});

In my TicketPolicy, the view method looks like this:

public function view(User $user, Ticket $ticket): bool
{
    if ($user->hasPermissionTo('view_ticket')) {
        return $user->id === $ticket->user_id;
    }
    return false;
}

Then, in my controller, I authorize like this:

Gate::authorize('view', $ticket);

If a user has the view_any_ticket permission through a “moderator” role, will the global Gate::before return true and completely bypass the TicketPolicy::view() method?

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

2mos ago

hi i am using spaite permissions for authorization , I want to ask what are the situation where i can assign direct permissions to users

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

2mos ago

hi thank you for the answer , i will do that of course but i want to ask you about lary`s answer what do you think about it ?

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

2mos ago

hi thank you for the answer ,what i want is to make access control even for the permissions model and roles model where admin user can do every thing and manger can do spacific things in the admin panel

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

2mos ago

I'm building an admin panel using Spatie Laravel Permission and I'm confused about the "right way" to handle authorization in Permission/Role controllers.

Option A (Direct Spatie check):

if (!auth()->user()->hasPermissionTo('view_any_permission')) {
    abort(403);
}

Option B (Laravel Policy):

Gate::authorize('viewAny', Permission::class);
// Policy just wraps: return $user->hasPermissionTo('view_any_permission');

I've seen both approaches but get mixed advice:

  • Spatie docs seem to favor direct checks - Permission/Role models are "internal admin tools"

  • Laravel docs push policies - Consistent authorization pattern across app

  • My current setup: Already created PermissionPolicy ✅ registered ✅ working

Questions:

  • Is PermissionPolicy truly "over-engineering" for admin screens?

  • When Spatie already integrates with Gates ($user->can()), what's the value of wrapping it in a policy?

  • Community standard: Direct Spatie checks vs Policies for Permission/Role management?

Context:

 -  Laravel 12, Spatie v6

 -  Using policies successfully for business models (PostPolicy, UserPolicy, TicketPolicy)

 -  Permissions follow snake_case convention (view_any_permission)

Current working code:

Gate::authorize('viewAny', Permission::class);

// Policy
public function viewAny(User $user): bool
{
    return $user->hasPermissionTo('view_any_permission');
}

Should I keep the policy pattern for consistency, or switch Permission/Role controllers to direct Spatie checks for simplicity?

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

2mos ago

Hi @glukinho, do you mean I should create a field called public and include it in my policy as well?

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

In a Laravel API controller, I return a collection of tickets that belong to a specific user (“author”). The authenticated user may have multiple tickets, and I’m unsure what the best-practice authorization approach is for this index endpoint.

Goal: Allow the request only if the authenticated user has the view_ticket permission and is the same user as the $author route parameter.

What I tried:

  • Looping through each ticket and calling authorize() / Gate::authorize() per ticket.

  • Creating a dedicated gate (show-users-tickets) that receives the $author and checks permission + ownership.

class AuthorTicketController extends Controller
{
    public function index(Request $request, User $author)
    {
        $filters = $request->only(['per_page']);

        Gate::authorize('show-users-tickets', $author);

        $tickets = TicketsService::getAuthorTickets($author, $filters);

        return TicketResource::collection($tickets);
    }
}
Gate::define('show-users-tickets', function (User $user, User $author) {
    if ($user->hasPermissionTo('view_ticket')) {
        return $user->id === $author->id;
    }

    return false;
});

Question: Is this gate-based approach correct for authorizing access to a list of tickets, or should I be using a policy (e.g., TicketPolicy@viewAny / view) and/or authorizing at the query level instead? (Laravel documentation describes policies as a way to organize authorization logic around a particular model or resource.)

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

Hi, I want to prevent non-admin users from accessing other users' tickets. Each logged-in user should only see their own tickets.

For example, when I make a request to http://localhost:8000/api/authors/1/tickets, the 1 parameter represents an admin user. If this isn't the currently logged-in user, I expect to receive an unauthorized exception.

However, the issue is:

  • If user with ID 1 has no tickets, I get an empty array instead of an unauthorized exception

  • If user with ID 1 has tickets, the authorization works correctly and I get the unauthorized exception

I hope that clarifies my question.

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

hi i am doing this because i am using spaite query builder in my service to for searching and feltering

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

In the controller method below, I'm experiencing an authorization issue. When an admin has no tickets, I receive an empty array [] instead of an authorization exception. However, when tickets exist for the admin, I correctly get the unauthorized exception. The expected behavior is that I should receive an authorization exception whenever I try to access admin tickets, regardless of whether tickets exist or not.

NOTE: i have sloved this by creating a gate in the AppServiceProvider in the boot method as below but i don`t know if that is correct or not

      Gate::define('showUserTicketList', function (User $user ,User $author) {

           if($user->hasPermissionTo('ShowOwnTicket')) {
                return $user->id === $author->id;
           }

          return false;
      });
  • controller method :

     public function index(Request $request, User $author)
    {
    
        // $filters = $request->only(['per_page']);
    
        $tickets = TicketsService::findTicketsByUserId($author);
    
        foreach ($tickets as $ticket) {
            Gate::authorize('view', [Ticket::class, $ticket]);
        }
    
        return TicketResource::collection($tickets);
    
    }
    
  • Service method:

    public static function findTicketsByUserId(User $author)
    {
        return QueryBuilder::for(Ticket::class)
            ->whereUserId($author->id)
            ->paginate();
    }
    
  • Policy: (TicketPolicy)

          public function viewAny(User $user): bool
      {
          if ($user->hasPermissionTo('ShowTicket')) {
              return true;
          }
    
          return false;
      }
    
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

Hi, Thank you for your reply. I just wanted to let you know that I’m currently working only on the API and haven’t created the UI yet. But you’re right — I can use a checkbox group when I build it.

minaremonshaker's avatar

minaremonshaker liked a comment+100 XP

3mos ago

Use a multi select dropdown for the roles, or use a checkbox group. They both give you an array of roles.

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

the contains dose not works as expected , i solved the problem by adding :input to the custom message , the :input gets the value as expected

    public function messages(): array
    {
        return [
            "roles.*.exists" => "the role :input dose not exists in our database" ,
        ];
    }
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

Hi, I followed your suggestion and am now sending the roles as a JSON array. However, I am facing another issue related to customizing the validation messages. I need to include the actual invalid values from the submitted array in the error message. When one of the array values fails validation, the error message I receive looks like the default one, but I would like to override it using the value itself.

From the documentation, I found several approaches, such as using the index or position placeholders, or using Rule::forEach, but they still rely on indexes or positions. Is there a better approach to achieve this?

https://laravel.com/docs/12.x/validation#accessing-nested-array-data

https://laravel.com/docs/12.x/validation#error-message-indexes-and-positions

data sent :

{
	"roles": [
		"admin",
		"user",
		"manager"
	]

}

request :

class AssignRoleToUserRequest extends FormRequest
{

    public function rules(): array
    {

        return [
            "roles" => ['required', 'array'],
            "roles.*" => ['exists:roles,name']
        ];
    }

    public function messages(): array
    {
        return [
            "roles.*.exists" => "the roles array contains :attribute that are not exists in our database" ,
        ];
    }


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

validation error message

{
	"message": "the roles array contains roles.2 that are not exists in our database",
	"errors": {
		"roles.2": [
			"the roles array contains roles.2 that are not exists in our database"
		]
	}
}
minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

I have a controller method that assigns roles to users. The request includes a string containing the roles to assign, and I need to validate that each specified role exists in the roles table using a form request. Currently, I created a custom validation rule that converts the string into an array, loops through each role, and checks if it exists in the database—failing if any do not. I’m wondering if there’s an alternative approach to achieve this validation without creating a custom rule, or if that’s the only viable solution.

  • validation custom rule
class UserHasRole implements ValidationRule
{


    public function __construct(protected int $user_id){}
    /**
     * Run the validation rule.
     *
     * @param Closure(string, ?string=): PotentiallyTranslatedString $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
         $roles = explode(",", $value);

         $user = \App\Models\User::find($this->user_id);

         foreach ($roles as $role){
             if($user->hasRole($role)){
                 $fail("user has role $role");
             }
         }

    }
}
  • form request
class AssignRoleToUserRequest extends FormRequest
{
    public function rules(): array
    {
        $user_id = $this->route()->parameter('user');

        return [
            "roles" => ['required', 'string', new UserHasRole($user_id),]
        ];
    }

    public function authorize(): bool
    {
        return true;
    }
}
  • controller method
    public function assign(AssignRoleToUserRequest $request, int $user_id)
    {

    }
minaremonshaker's avatar

minaremonshaker liked a comment+100 XP

3mos ago

It's completely normal.

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

Hi, my routes/api.php file has become quite large, so I’d like to split the routes into separate PHP files inside the routes directory. I don’t want to register them manually in app.php—I just plan to include those files directly within api.php. Is that a good approach, or are there better alternatives?

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

Hi, I’ve created a new version where I need to sort and search the results. Of course, I can normally handle this using the built-in Eloquent model — that’s the current case.

note: this is not the last version i still making updates to it

  • this from the service
    public static function getPermissionsOfRolesName(string $role, ?array $filters)
    {
        extract($filters, EXTR_IF_EXISTS);
        
        return QueryBuilder::for(Role::findByName($role)->permissions())
            ->defaultSort('id')
            ->allowedSorts([
                'name',
                AllowedSort::field('created', 'created_at'),
                AllowedSort::field('updated', 'updated_at'),
            ])
            ->paginate(10);
    }
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

i solved the problem by reading this part of spite permission docs https://spatie.be/docs/laravel-query-builder/v6/advanced-usage/extending-query-builder

and i implemented it like this

    public static function getPermissionsOfRolesName(string $role)
    {
        return QueryBuilder::for(
            Role::findByName($role)->permissions()
        )->paginate(10);
    }

what do you think ?

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

Hi everyone,

In my Laravel API project using Spatie Laravel Permission (with Sanctum guard) and Spatie Query Builder, I'm trying to fetch permissions for a specific role like 'user', but running into an issue with QueryBuilder.

These attempts fail with Call to undefined method Spatie\QueryBuilder\QueryBuilder::findByName():

QueryBuilder::for(Role::class)->where('name', 'user')->permissions()->get()

or

QueryBuilder::for(Role::class)->findByName('user', 'sanctum')->permissions()

However, this direct Eloquent call works perfectly and returns all related permissions:

Role::findByName('user', 'sanctum')->permissions()

Why can't I chain findByName() or similar scopes directly on the QueryBuilder instance?

Is there a proper way to combine Spatie Query Builder with Role model scopes/finders from laravel-permission to get a role by name and then load its permissions? Should I use allowedIncludes('permissions') or a different approach like where('name', 'user')->with('permissions')?

Using Laravel 12, latest Spatie packages. Thanks!

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

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);
    }
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

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"
}
minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

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;

    }
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

i have DataGrip by jetbrains, if you have other please suggest to me

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

what make me surprised that the create got the foreign key but i cant see in in phpmyadmin digram

CREATE TABLE `tickets` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint unsigned NOT NULL,
  `title` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
  `description` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `status` varchar(3) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_USER_TICKETS` (`user_id`),
  FULLTEXT KEY `tickets_title_fulltext` (`title`) /*!50100 WITH PARSER `ngram` */ ,
  FULLTEXT KEY `tickets_description_fulltext` (`description`) /*!50100 WITH PARSER `ngram` */ ,
  FULLTEXT KEY `tickets_title_description_fulltext` (`title`,`description`) /*!50100 WITH PARSER `ngram` */ ,
  CONSTRAINT `FK_USER_TICKETS` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

When I show the digram in phpmyadmin I did not find any relation

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

Hi , But in some cases i like to name the index , what I know that it is suppose to be created in both cases because the constrained method already has this parameter where I can can add the table name and the id and the index name

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

hi , first of all Mary Christmas and hope you are doing well , please can you clarify more, i am adding a forging key to the tickets table cause there are a one to many relation but the problem i that the method above dose not create it in the database tickets table , also for the key name i like to make all of the keys start with specific prefix like FL, UQ , etc...

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

Hi, I’m encountering an issue with a migration that creates a tickets table, which has a one-to-many relationship with the users table. Normally, the tickets table should include a foreign key referencing the users table. However, when I try to define it using: $table->foreignId('user_id')->constrained(indexName: 'FK_USER_TICKETS')->onDelete('cascade'); it only creates the user_id column without actually generating the foreign key constraint in the database, even though I expected it to.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::create('tickets', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained(indexName: 'FK_USER_TICKETS')->onDelete('cascade');
            $table->string('title' , 40);
            $table->text('description');
            $table->string('status');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('tickets');
    }
};
minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

3mos ago

hi @martinbean
What I mean is that without using the Spatie permissions package, I would need to assign specific abilities to each user token, and update those abilities whenever I want the token to perform certain actions. However, when using Spatie permissions, this process is overridden — meaning there’s no need to manually assign abilities to the token.

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

3mos ago

When integrating authorization using the Spatie Permission package alongside Sanctum token-based authentication in my API, should I modify the abilities column in the personal_access_tokens table, or rely solely on the Spatie package for handling authorization?

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

ok , i have extracted the data from the request in the controller using $request->only([]) and passed it to the service method as an array

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

4mos ago

hi Merry Christmas! I have a UsersService class with a method that handles filtering and sorting data from the request. Is it good practice to pass the Request object directly to this service method (or inject it via the service provider), or should I avoid it? If not, what are the better alternatives?

note: i am using spaite query builder package

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

I am sorry community I forgot it's Christmas today، marry Christmas to you all and wish you all happy new year

minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

4mos ago

Hi,
I want to implement sorting on my users table using some columns from related tables — for example, date_of_birth from the profiles table and status from the tickets table — combined with columns from the users table itself.

Currently, I’m constructing the URL like this:
http://localhost:8000/authors?search=Co&searchBy=first_name&sort=profiles.date_of_birth,users.status

In this format, the part before the dot represents the table name, and the part after the dot represents the column I want to sort by. Is this approach correct?

Think also for safety from injection i can make a array inside the class that contains the feilds that i want to sort with and check if value provided is included in the array of sortable other than that i can ignore

Notes:

  1. There’s a one-to-one relationship between the users and profiles tables.
  2. There’s a one-to-many relationship between the users and tickets tables.

included my UsersFilters class where there are sort method

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

I want to add something that I am using MySQL for testing and not SQLite , I don't know if this would change something , also RefreshDatabase trait worked when I switched to SQLite

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

hi i still have the same problem here , below is another test that i have tried , this test dose not work unless i used the DatabaseTruncation triat in my test class , this is confusing

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

hi ,

i have implemented what you said in the post above but it still fails , included in my post here the

1-test method 2-test result from the console

    public function users_search_returns_results_for_existing_data(array $payload)
    {

        $users = User::factory()->createMany($payload);

        $user = $users->find($users[0]->id);

        $response = $this
            ->withHeader("Accept", 'application/json')
            ->actingAs($user)
            ->getJson(route('authors.index', ['search' => 'b']));

        $response->assertStatus(200);

        $response->assertJsonCount(1, 'data');

    }

test Results

/bin/php /home/mina/Desktop/Tickets/vendor/phpunit/phpunit/phpunit --configuration /home/mina/Desktop/Tickets/phpunit.xml --filter "/(Tests\\Feature\\AuthorTest::users_search_returns_results_for_existing_data)( .*)?$/" --test-suffix AuthorTest.php /home/mina/Desktop/Tickets/tests/Feature --teamcity
Testing started at 2:03 AM ...
PHP Warning:  PHP Startup: Unable to load dynamic library 'couchbase' (tried: /usr/lib/php/20240924/couchbase (/usr/lib/php/20240924/couchbase: cannot open shared object file: No such file or directory), /usr/lib/php/20240924/couchbase.so (/usr/lib/php/20240924/couchbase.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
PHPUnit 11.5.46 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.4.15
Configuration: /home/mina/Desktop/Tickets/phpunit.xml

Failed to assert that the response count matched the expected 1
Failed asserting that actual size 0 matches expected size 1.
/home/mina/Desktop/Tickets/vendor/laravel/framework/src/Illuminate/Testing/AssertableJsonString.php:74
/home/mina/Desktop/Tickets/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:1006
/home/mina/Desktop/Tickets/tests/Feature/AuthorTest.php:81

Time: 00:07.109, Memory: 44.50 MB

There was 1 failure:

1) Tests\Feature\AuthorTest::users_search_returns_results_for_existing_data with data set "users_to_create" ([['mina', 'remon', '[email protected]', 'mina20088'], ['beshoy', 'shaker', '[email protected]', 'beshoy20088']])
Failed to assert that the response count matched the expected 1
Failed asserting that actual size 0 matches expected size 1.

/home/mina/Desktop/Tickets/vendor/laravel/framework/src/Illuminate/Testing/AssertableJsonString.php:74
/home/mina/Desktop/Tickets/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:1006
/home/mina/Desktop/Tickets/tests/Feature/AuthorTest.php:81

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
Process finished with exit code 1
minaremonshaker's avatar

minaremonshaker started a new conversation+100 XP

4mos ago

Hello, I want to understand why this test fails specifically with the RefreshDatabase trait but succeeds with DatabaseTruncation. The failing assertion is $response->assertJsonCount(1, 'data')—all other assertions and the complete test method work fine.

I've tested other database traits, but none resolve the issue. Here's the test code:

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

Ok , got the point thank you very mush , its following the standard or not that it

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

As you saw above, some developers say there’s no standard, while others insist that you should follow one. This has confused me since it’s my first time creating APIs, and as you know , I’m used to follow the MVC pattern in all my previous projects.

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

Hi Martin, I used it because I'm following Jeremy's course and he uses it as well. I just wanted to follow along with him, but in my opinion, it's quite complex. So that why I asked can I make more simple and follow the same standard

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

I’m learning how to create APIs because I want to integrate them with Vue.js. Personally, I find frameworks like Vue or React more flexible than Blade, especially since they give me greater control over JavaScript and regular HTML.

minaremonshaker's avatar

minaremonshaker wrote a reply+100 XP

4mos ago

can i know what do you mean by consistent in here with an example if you don`t mind ?