lambooni

lambooni

Member Since 1 Year Ago

Experience Points
6,900
Total
Experience

3,100 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
38
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start-engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber-token Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer-token Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • lara-evanghelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

Level 2
6,900 XP
Jan
05
2 weeks ago
Activity icon

Awarded Best Reply on Database Encryption At Rest - Amazon RDS Internal Vs. Application Level

From the research I have done, the primary need for at rest encryption is for either database server attacks or physical removal of the hardware storing data (i.e. theft of a hard drive).

When using Amazon RDS with a private network between your webserver and database server, both of the above scenarios are generally considered quite unlikely.

However, it is still a requirement by MWS that you have at rest encryption in place. In this case, there appears to be little difference between using Amazon RDS's in-built at rest encryption vs. encrypting/decrypting at application level.

The complexity of doing it at application level means in most cases RDS only encryption would be preferred.

Amazon MWS have confirmed that this is also the case as far as meeting their requirements.

Activity icon

Replied to Database Encryption At Rest - Amazon RDS Internal Vs. Application Level

From the research I have done, the primary need for at rest encryption is for either database server attacks or physical removal of the hardware storing data (i.e. theft of a hard drive).

When using Amazon RDS with a private network between your webserver and database server, both of the above scenarios are generally considered quite unlikely.

However, it is still a requirement by MWS that you have at rest encryption in place. In this case, there appears to be little difference between using Amazon RDS's in-built at rest encryption vs. encrypting/decrypting at application level.

The complexity of doing it at application level means in most cases RDS only encryption would be preferred.

Amazon MWS have confirmed that this is also the case as far as meeting their requirements.

Dec
31
3 weeks ago
Activity icon

Started a new Conversation Database Encryption At Rest - Amazon RDS Internal Vs. Application Level

We need to ensure our software is compliant with Amazon Marketplace Web Services (MWS) conditions of use. One key area is database encryption at rest for PII.

We use Amazon RDS and have encryption at rest enabled already (https://aws.amazon.com/rds/features/security/). On its own, this is our perfect solution as it allows simple data access and search from without our application.

Additional to the encryption provided by RDS, there are a lot of solutions available to repeat and/or replace this at an application level. i.e. a function is used to encrypt and decrypt the data into and out of the database. We have a simple encryptable trait on our models that used Crypt to encrypt and decrypt models into and out of the database. This is simple and works well for this one purpose but it prevents simple searching of records that is a key part of our application.

My question is... are both of these necessary? Amazon will be able to approve/disapprove our plan either way but I wonder more from a pragmatic viewpoint.

My thoughts are:

  • If the webserver is compromised then either way our data is likely to be exposed.

  • If the database server is compromised; whether we use RDS integrated encryption and/or our own then the data is secure.

Dec
25
4 weeks ago
Activity icon

Replied to Logging In Laravel Vapor (Papertrail, Flare, Sentry - Nothing Is Working!)

I went through a quite a few emails with papertrail and Taylor in regards to this. At least at a few months ago the answer was it is not compatible.

I would love to find a way to get paper trail to work!

Nov
24
1 month ago
Activity icon

Awarded Best Reply on Inject User Into Form Request - Testing Autorization

So I realise now that a unit test, may not be the best way to test this at all... but in answer to the original question:

'How to inject the user into form request, so that you can retrieve the user with $this->user()

$this->subject->setUserResolver(function () use($user) {
   return $user;
});
Activity icon

Replied to Inject User Into Form Request - Testing Autorization

So I realise now that a unit test, may not be the best way to test this at all... but in answer to the original question:

'How to inject the user into form request, so that you can retrieve the user with $this->user()

$this->subject->setUserResolver(function () use($user) {
   return $user;
});
Nov
23
2 months ago
Activity icon

Replied to Form Requests $this->user() Vs. Auth()->user() In Authorization

@nakov OK thank you. I guess in my head I was taking this unit test example and extrapolating it out to something more complex. For me, the main benefits I could see were a faster test and maybe not using so much of the request... but as you have suggested, maybe I am better off just sacrificing the speed and running all my options in a feature test.

So in your opinions for a form request like this, unit tests have no place?

Activity icon

Replied to Form Requests $this->user() Vs. Auth()->user() In Authorization

@tykus I am relitively new to testing so your advice is really appricated. I am following along with the confident laravel (https://confidentlaravel.com/) test training and it seems to suggest that it is OK to test the authorize method in a unit test, with a logged-in user.

You can see testing the unhappy path in this snippet (without user login):

https://recordit.co/d4doqQFyOy

and the happy one here (with user login):

https://recordit.co/eZuJTigv7a

Am I doing something different to what he is suggesting here, or do you just generally disagree with this method?

Activity icon

Replied to Form Requests $this->user() Vs. Auth()->user() In Authorization

thanks, @nakov . I agree I may not 100% understand the official constraints of unit testing. Maybe, in fact, I do want to be mocking a user for this test? Or maybe I just need to run every scenario I can think of through an integration test. My only concern with the integration test is that I am testing the whole flow through the request for every different scenario when all I really want to know is if the authorize passes or not.

Activity icon

Replied to Inject User Into Form Request - Testing Autorization

This is a simple example, that helps to explain my testing methodology:

https://jasonmccreary.me/articles/test-validation-laravel-form-request-assertion/

I also have run through Jasons testing course and found it quite useful, but it does not go into great levels of detail. Maybe these testing opinions are not for everyone, but in summary to validate a form request:

  1. Create a feature/integration test posting to the endpoint. Ensure 200 is returned and the database is populated with the correct data.

  2. Create a unit test/s that ensure the finer details of the form request are working. In the example, he keeps it very simple (almost like a spell checker), but it is quite easy to extrapolate this out a little to test more compex logic in both the authorize method as well as any individual validation rules. I agree we would not ever want to test the laravel built-in rules but there may be more complex custom rules or closures that there would be value in testing.

Activity icon

Replied to Form Requests $this->user() Vs. Auth()->user() In Authorization

Thanks for your input. I think I maybe need to reword the question a bit...

  • The user is logged in, within the application. They have to be. My question here is related to unit testing of the form request (not running through the post route).

  • The authorize method of the form request is boolean. Return true for authorized and false for a 403, not authorized.

More context to my use case below. My form request can be posted to by a number of user types. Admin users and normal users need to provide slightly different parameters into the request. For my Authorize method when unit testing the following works.

public function authorize()
{
    if (! Auth::user()->isAdmin()) {
        return Auth::user()->hasCompany($this->company_id)
            && Auth::user()->can((string) Permission::CREATE_ORDER());
    }

    return Auth::user()->can((string) Permission::CREATE_ORDER());
}

I can now unit test this, and it passes:

public function testAuthorizeForUser()
{
    $this
        ->actingAs(\factory(User::class)->create())
        ->assertTrue($this->subject->authorize());
}

However, if we now use the below it fails because the user is not injected into the request:

public function authorize()
{
    if (! $this->user()->isWarehouseUser()) {
        return $this->user()->hasCompany($this->company_id)
            && $this->user()->can((string) Permission::CREATE_ORDER());
    }

    return $this->user()->can((string) Permission::CREATE_ORDER());
}

Again, this is only in unit testing when I am instantiating the form request manually i.e. $formRequest = new \App\Http\Requests\OrderStoreRequest();. This is never done in the application, but for this particular test I am only trying to confirm the authorize method works for all my user types.

I know I can test this via a post request to the endpoint and whether I use Auth::user or $this->user() it will work fine.

My original question is simply:

Is there any difference using Auth::user() or $this->user() within a form request. All the offical doc examples use the latter... and I am unsure why this is? Are there limitations of using Auth::user() in a form request, is it less secure etc?

Activity icon

Replied to Form Requests $this->user() Vs. Auth()->user() In Authorization

For my unit test, I am trying to do this without hitting the database. Note the orderStoreRequest is instantiated on the fly for this one test.

$this->subject = new \App\Http\Requests\OrderStoreRequest();
$this
     ->actingAs(\factory(User::class)->create())
     ->assertTrue($this->subject->authorize());

In this example, auth()->user() returns a user in the request, while $request->user() does not.

Activity icon

Replied to Inject User Into Form Request - Testing Autorization

I have already got some feature tests setup posting to the endpoint. That is all fine.

What I am trying to get around, is creating 10 - 20 separate feature tests to check every configuration of my user and permission rules. This request, in particular, is quite complicated as depending on the kind of user will change the type of data we can accept. I have admin users and normal users and each has related roles and permissions.

I want to be able to test all of these quickly through a unit test that does not hit the database.

I am seeing this testing as:

  1. Feature tests that post to the endpoints: Used to check everything is wired up correctly and valid data results in the correct new rows in my database.

  2. Unit tests: ideally not hitting the database and can check the more detailed implementation of validation and authorization of the request.

Activity icon

Started a new Conversation Form Requests $this->user() Vs. Auth()->user() In Authorization

Can anyone explain if there is a reason why we should not be using getting the authenticated user within a from request authorize method, via the Auth::user() or auth()->user() helpers vs. the $this->user() method as suggested in docs?

https://laravel.com/docs/5.8/validation#authorizing-form-requests

In my case, I am trying to unit test a form request and auth()->user() allows me to retrieve the user whereas $this->user() does not as I am not making a full request. I am just creating the form request object for my test.

public function setUp(): void
{
    parent::setUp();

    $this->subject = new \App\Http\Requests\OrderStoreRequest();
}

// Acting as has no effect when manually creating the orderStoreRequest object
public function testAuthorize()
{
    $this
        ->actingAs(\factory(User::class)->create())
        ->assertTrue($this->subject->authorize());
}
Activity icon

Started a new Conversation Inject User Into Form Request - Testing Autorization

I have feature tests hitting the post route to my form request and these all work fine.

However, I have some quite complicated authorization logic that I would like to test in isolation.

I am already doing something similar for some validation rules as follows:

public function setUp(): void
{
    parent::setUp();

    $this->subject = new \App\Http\Requests\OrderStoreRequest();

    $this->rules = $this->subject->rules();

    $this->validator = $this->app['validator'];
}

public function test_fields_are_valid()
{
    $this->assertTrue($this->validateField('country_code', 'GB'));
    $this->assertFalse($this->validateField('country_code', 'ZZ'));
}

I would now like to test the authorization method, but cannot work out how to inject a mock user into the form request. This does not work...

public function testAuthorize()
{
    $this
        ->actingAs(\factory(User::class)->create())
        ->assertTrue($this->subject->authorize());
}

Would much appricate any ideas on how this can be done with unit tests.

Nov
07
2 months ago
Activity icon

Started a new Conversation Belongs To Many With Spatie Permissions - Solution Feedback

I have a situation where a user can belong to many teams/companies and within that team/company they can have different roles and permissions depending on which one they are signed into. I have come up with the following solution and would love some feedback!

Note: Currently I am only using the model_has_roles table with Spatie permissions and always use $user->can('Permission') to check permissions.

  1. Our company model has the following relationships and method
class Company extends Model
{
    public function owner(): HasOne
    {
        return $this->hasOne(User::class, 'id', 'user_id');
    }

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(
            User::class, 'company_users', 'company_id', 'user_id'
        )->using(CompanyUser::class);
    }

    public function addTeamMember(User $user)
    {
        $this->users()->detach($user);

        $this->users()->attach($user);
    }
}
  1. We modify the pivot model to have the Spatie HasRoles trait. This allows us to assign a role to the CompanyUser as opposed to the Auth User. You also need to specify the default guard or Spatie permissions squarks.
class CompanyUser extends Pivot
{
    use HasRoles;

    protected $guard_name = 'web';
}
  1. On the user model, I have created the HasCompanies Trait. This provides the relationships and provides a method for assigning the roles to the new company user. Additionally, it overwrites the gate can() method.

A user can belong to many companies, but can only have one active company at a time (i.e. the one they are viewing). We define this with the current_company_id column.

It is also important to ensure the pivot table ID is pulled across (which it will not be as standard) as this is now what we are using in the Spatie model_has_roles table.

trait HasCompanies
{
    public function companies(): HasMany
    {
        return $this->hasMany(Company::class);
    }

    public function currentCompany(): HasOne
    {
        return $this->hasOne(Company::class, 'id', 'current_company_id');
    }

    public function teams(): BelongsToMany
    {
        return $this->belongsToMany(
            Company::class, 'company_users', 'user_id', 'company_id'
        )->using(CompanyUser::class)->withPivot('id');
    }

    public function switchCompanies(Company $company): void
    {
        $this->current_company_id = $company->id;
        $this->save();
    }

    public function assignRolesForCompany(Company $company, ...$roles)
    {
        if($company = $this->teams()->where('companies.id', $company->id)->first()){
            /** @var CompanyUser $companyUser */
            $companyUser = $company->pivot;
            $companyUser->assignRole($roles);
            return;
        }

        throw new Exception('Roles could not be assigned to company user');
    }

    public function can($ability, $arguments = [])
    {
        if(isset($this->current_company_id)){
            /** @var CompanyUser $companyUser */
            $companyUser = $this->teams()->where('companies.id', $this->current_company_id)->first()->pivot;

            if($companyUser->hasPermissionTo($ability)){
                return true;
            }

            // We still run through the gate on fail, as this will check for gate bypass. i.e. Super User
            return app(Gate::class)->forUser($this)->check('InvalidPermission');
        }

        return app(Gate::class)->forUser($this)->check($ability, $arguments);
    }
}

Now we can do something like this:

  1. Create the role & permission
/** @var Role $ownerRoll */
$ownerRoll = Role::create(['name' => 'Owner']);

/** @var Permission $permission */
$permission = Permission::create([
    'name' => 'Create Company',
    'guard_name' => 'web',
]);

$ownerRoll->givePermissionTo($permission);
  1. Create a new company with an owning user and then switch this company to that owner's active company.
public function store(CompanyStoreRequest $request)
{
    DB::transaction(function () use($request) {
        /** @var User $owner */
        $owner = User::findOrFail($request->user_id);

        /** @var Company $company */
        $company = $owner->companies()->create($request->validated());
        $company->addTeamMember($owner);

        $owner->assignRolesForCompany($company, 'Owner');
        $owner->switchCompanies($company);
    });

    return redirect()->back();
}

So this all works, my main concerns are that:

  1. We are overwriting the can method. There may be other authorization methods/gate functions that are not caught.

  2. We have 2 sets of model_permissions. The Auth user and the company user. I think I need to build in some checks to ensure that only the correct kinds of users can be assigned to the roles. At this stage, all administrator users would have permissions assigned to their auth user, while any users who own a company should only have permissions on the company user model

Nov
06
2 months ago
Activity icon

Awarded Best Reply on Task Schedule With Cron Column In Database

Thanks a lot for your research. Interestingly I actually already had an requestIsDue() method on my model - I was just using it in a very convoluted way! I have come up with this for now which seems to be doing the trick!

<?php

namespace App\Traits;

use Cron\CronExpression;
use Illuminate\Support\Carbon;
use Illuminate\Console\Scheduling\ManagesFrequencies;

trait Schedulable
{
    use ManagesFrequencies;

    protected $expression = '* * * * *';

    protected $timezone;

    public function isDue($expression = null)
    {
        $date = Carbon::now();

        if ($this->timezone) {
            $date->setTimezone($this->timezone);
        }

        return CronExpression::factory($expression ?? $this->expression)->isDue($date->toDateTimeString());
    }

    public function nextDue($expression = null)
    {
        return Carbon::instance(CronExpression::factory($expression ?? $this->expression)->getNextRunDate());
    }

    public function lastDue($expression = null)
    {
        return Carbon::instance(CronExpression::factory($expression ?? $this->expression)->getPreviousRunDate());
    }
}

// On model
    public function requestIsDue() : bool
    {
        if(! $this->cron_request){
            return false;
        }

        return $this->isDue($this->cron_request);
    }
// Schedule kernel
$schedule->call(function(){
    ReportSchedule::all()->each(function(ReportSchedule $reportSchedule){
        if($reportSchedule->requestIsDue()){
            ReportRequestNow::dispatch($reportSchedule);
        }
    });
})->everyMinute();

I can now even move this into a seeder job:

$schedule->job(new ReportScheduleSeeder(), 'high')->everyMinute();
Nov
04
2 months ago
Activity icon

Replied to Task Schedule With Cron Column In Database

Thanks a lot for your research. Interestingly I actually already had an requestIsDue() method on my model - I was just using it in a very convoluted way! I have come up with this for now which seems to be doing the trick!

<?php

namespace App\Traits;

use Cron\CronExpression;
use Illuminate\Support\Carbon;
use Illuminate\Console\Scheduling\ManagesFrequencies;

trait Schedulable
{
    use ManagesFrequencies;

    protected $expression = '* * * * *';

    protected $timezone;

    public function isDue($expression = null)
    {
        $date = Carbon::now();

        if ($this->timezone) {
            $date->setTimezone($this->timezone);
        }

        return CronExpression::factory($expression ?? $this->expression)->isDue($date->toDateTimeString());
    }

    public function nextDue($expression = null)
    {
        return Carbon::instance(CronExpression::factory($expression ?? $this->expression)->getNextRunDate());
    }

    public function lastDue($expression = null)
    {
        return Carbon::instance(CronExpression::factory($expression ?? $this->expression)->getPreviousRunDate());
    }
}

// On model
    public function requestIsDue() : bool
    {
        if(! $this->cron_request){
            return false;
        }

        return $this->isDue($this->cron_request);
    }
// Schedule kernel
$schedule->call(function(){
    ReportSchedule::all()->each(function(ReportSchedule $reportSchedule){
        if($reportSchedule->requestIsDue()){
            ReportRequestNow::dispatch($reportSchedule);
        }
    });
})->everyMinute();

I can now even move this into a seeder job:

$schedule->job(new ReportScheduleSeeder(), 'high')->everyMinute();
Activity icon

Started a new Conversation Task Schedule With Cron Column In Database

I have a "reportSchedule" model which contains the report name and a cron_request column such as */15 * * * *.

I want to be able to adjust the cron within the database and affect the times which the report is requested. For example, the following is working from directly within the console/Kernel.php:

ReportSchedule::all()->each(function(ReportSchedule $reportSchedule) use($schedule){
    if(isset($reportSchedule->cron_request)){
        $schedule->call(function() use ($reportSchedule) {
            ReportRequestNow::dispatch($reportSchedule);
        })->cron($reportSchedule->cron_request);
    }
});

However, having the model called from directly within the kernel causes other issues. For example database migrations now do not work and errors are thrown when caching the routes or running route:list. In general, it does not seem to like it!

So my idea was either create a seeder job or put this into its own schedule, however neither work.

// Doesnt work - the every minute schuedle is called but ReportRequestNow is never reached.

$schedule->call(function() use($schedule){
    ReportSchedule::all()->each(function(ReportSchedule $reportSchedule) use($schedule){
        if(isset($reportSchedule->cron_request)){
            $schedule->call(function() use ($reportSchedule) {
                ReportRequestNow::dispatch($reportSchedule);
            })->cron($reportSchedule->cron_request);
        }
    });
})->everyMinute();

// Also does not work

$schedule->job(new ReportScheduleSeeder(), 'high')->everyMinute();

Can anyone suggest a why this does not work or how to get it working?

Nov
03
2 months ago
Activity icon

Started a new Conversation Laravel Illuminate\Support\Collection - FirstOrNew (and Similar) Possible With Extending? (Not Eloquent)

I am using Laravels collection for creating entities within a DDD type (very loose!) environment. It works well but I really miss the helper functions that you can make use of with Eloquent and was wondering if there is a way to get this similar functionality extended into the Collection function.

For example, I am doing something similar this a lot:

final class InventoryAggregateRoot extends AggregateRoot
{
    /** @var Collection | LocationItem[] */
    private $inventoryItems;

    public function __construct()
    {
        $this->inventoryItems = new Collection();
    }

    public function firstOrCreateInventoryItem($id)
    {
        $inventoryItem = $this->inventoryItems->firstWhere('id', $id);

        if(! $inventoryItem){
            $inventoryItem = new InventoryItem($id);
            $this->inventoryItems->push($inventoryItem);
        }

        return $inventoryItem;
    }
...

but would love to do something like this:

$inventoryItem = $this->inventoryItems->firstOrCreate('id', $id);

It seems like this could be quite easily added in... but I feel like I may be missing something. Why is this kind of functionality not in Laravel already?

Oct
31
2 months ago
Activity icon

Replied to Preventing Multiple Form Submissions With Session And Slow Requests. Session Does Not Seem To Write Fast Enough?

Just to note, I know disabling the button with JS will work but too (and this is already implemented) but this is such a critical issue that I want to have a solid front and back end solution in place together.

Activity icon

Started a new Conversation Preventing Multiple Form Submissions With Session And Slow Requests. Session Does Not Seem To Write Fast Enough?

I have a create order request, that is currently a little slow (about 3 - 4 seconds). I am attempting to prevent a duplicate form submission using the CSRF token, or a custom token.

For this instance, I am using valet with a file driver... so this may well be the issue but I am yet to push this code into a production server as it is not working as intended.

It works like this:

  • The token is added to the session and to the submit form in a hidden "custom_token" field.

  • The form is submitted and either within the middleware or the controller itself we do a quick comparison.

if(! hash_equals($request->session()->get('custom_token'), $request->custom_token)){
    flash()->error('Order placed twice');
    return redirect('/checkout/thank-you');
}

$request->session()->put('custom_token', Str::random(40));
  • If they do not match we do a quick redirect (Flash message only there for debugging currently).

The above works if I remove the main create orde call from the controller (i.e. the slow bit) but with this included the hash_equals always returns true.

So my questions are:

  1. Is this likely to be caused by the slow updating of a session file driver?
  2. Surely if this is the case, even in a production environment there is still some risk of this happening.
  3. Is there a better way I can prevent duplicate form submission on the backend?
Oct
25
2 months ago
Activity icon

Awarded Best Reply on L6 Upgrade - Eager Loading Issue With UUID's As ID

Ok, turns out after Laravel 5.7 you need to specify the key type as a string. So setting the keyType in my UUID Trait fixed it.

trait UuidForKey
{
    public function initializeUuidForKeyTrait()
    {
        $this->keyType = 'string';
    }

    /**
     * Boot the Uuid trait for the model.
     *
     * @return void
     */
    public static function bootUuidForKey()
    {
        static::creating(function ($model) {
            $model->incrementing = false;
            $model->{$model->getKeyName()} = (string) Str::uuid();
        });
    }
...

https://github.com/laravel/framework/issues/26582

Activity icon

Replied to L6 Upgrade - Eager Loading Issue With UUID's As ID

Ok, turns out after Laravel 5.7 you need to specify the key type as a string. So setting the keyType in my UUID Trait fixed it.

trait UuidForKey
{
    public function initializeUuidForKeyTrait()
    {
        $this->keyType = 'string';
    }

    /**
     * Boot the Uuid trait for the model.
     *
     * @return void
     */
    public static function bootUuidForKey()
    {
        static::creating(function ($model) {
            $model->incrementing = false;
            $model->{$model->getKeyName()} = (string) Str::uuid();
        });
    }
...

https://github.com/laravel/framework/issues/26582

Activity icon

Started a new Conversation L6 Upgrade - Eager Loading Issue With UUID's As ID

I have just upgraded to L6 from 5.8.

Eager loading is failing to work on some rows with a basic BelongsTo relationship. If I bypass eager then it works every time, but with it, I get failures (null returned) but only on some records. If I query the same relationship/row without eager it then works.

// With Eager loading
$orders = Order::query()->with(['orderAddress'])->get();

foreach($orders as $order){
    dump($order->orderAddress->first_name); // Fails, but only on some rows
    dump($order->orderAddress()->first()->first_name); // works every time
}

// Without Eager loading
$orders = Order::all();

foreach($orders as $order){
    dump($order->orderAddress->first_name); // works every time
}

Relationship

public function orderAddress() : BelongsTo
{
    return $this->belongsTo(OrderAddress::class);
}

When inspecting the eager loading query, it shows the issue:

select * from `order_addresses` where `order_addresses`.`id` in (1, 2, 0, 0, 0, 0, 11189, 0, 122, 140, 199, 1, 1, 1, 100000, 10000, 1, 262, 294409 
...

The ID's are stored as CHAR 32 UUID's but Eloquent is trying to convert them to integers. Any ideas why?

  • I have incrementing = false; already
Oct
05
3 months ago
Activity icon

Started a new Conversation Robust Domain Event Implimentation In Laravel - DDD

I am looking to set up a basic DDD model using a couple of different techniques on the Domain models. Communication between the domain models is important and I would intend to use domain events for this.

One part I am struggling with currently is the robust implementation of the domain events. For example, we have domains in separate bounded contexts:

  • Order
  • Inventory

The new order process is completed within the order domain and an event NewOrderReceived is emitted. At this point, the inventory domain must pick up this event and initiate a FulfilmentProcess.

Assuming everything runs OK then this is quite simple, but what happens if an exception is thrown either during the event emit or in the event recieve.

There could eventually be multiple other domains picking up events so I think the best course of action here would be to queue and run then asynchronously. However, in this case, there is no feedback to the process emitting the event as to whether the listeners were successful. If they fail first time then what would the retry/error handling mechanism look like? For example, An order was created with product x, but actually that product does not exist/could not be found by the inventory domain.

Similarly, there would be some events that need to go both ways. For example, an OrderCancellationWasRequested event is fired by the order domain. The inventory domain would have to both acknowledge, act and then respond with a success/fail. In this case, we actually want to catch the response like in a REST API, but using domain events.

For reference, here are some useful resources that have helped me with the overall ideas and some implementation so far:

The Many Meanings of Event-Driven Architecture

Domain Events vs. Event Sourcing

Laracasts - Commands & Domain Events

Laracats - Consider Domain Events

Sep
25
3 months ago
Activity icon

Started a new Conversation Shared Resources In DDD

I am experimenting with a DDD architecture. I have a number of defined modules but then they also all have quite strong links via 1 or 2 elements. For example:

project
│
└───Domain
│   │
│   └───Account
│   │
│   └───Delivery
│   │
│   └───Fulfilment
│   

This is a warehouse management system. In the above modules:

  • Product is received into the warehouse on a delivery
  • Product is dispatched as fulfilment

Each of these modules have their own set of tables, own routes, jobs, exceptions etc. and work fairly independently from one another, however there is certain logic that requires a shared resource.

Both the delivery and fulfilment modules interact with product and stock. In DDD, should we use shared/global resources or should each of these be a module that can communicate with another?

At this stage I am trying not to get too detailed in this. My app has got fairly big and I want to be able to split out each core function into its on module, partly for readability but also so I can improve and develop each module in as much isolation as possible from the others.

Its maybe a lot more complicated that I first thought! Any comments would be very welcome!

Sep
22
4 months ago
Activity icon

Replied to Logging In Laravel Vapor (Papertrail, Flare, Sentry - Nothing Is Working!)

It appears it may be possible to forward logs from cloudwatch to papertrail like this (not yet tried it)

https://blog.papertrailapp.com/how-to-log-amazon-alexa-apps-and-improve-user-experience/

Activity icon

Replied to Logging In Laravel Vapor (Papertrail, Flare, Sentry - Nothing Is Working!)

I got a reply from Taylor on Vapor. He told me that all logs are stored within cloudwatch... so it seems like at least for now this may be as far as it has been designed. For me, papertrail (or similar) with filtered, live tail logs has been extremely useful for both developing and debugging - especially big data crunching long running scripts in queues. I hope there is a work around to get this function working again with serverless!

Sep
21
4 months ago
Activity icon

Replied to Logging In Laravel Vapor (Papertrail, Flare, Sentry - Nothing Is Working!)

So AWS cloudwatch is already capturing all the logs (along with all the Lambda stuff too, that we do not really care about). There appear to be a few packages that are designed to forward from cloudwatch (which has a fairly quite interface!) through to papertrail. For example:

https://github.com/kenperkins/winston-papertrail

I am not too sure how to go about hooking something like this up though.

Activity icon

Replied to Logging In Laravel Vapor (Papertrail, Flare, Sentry - Nothing Is Working!)

For anyone else having the issue, I solved one part of this with Flare (thanks to Flare support) with the following logging config:

'vapor' => [
    'driver' => 'stack',
    'channels' => ['flare', 'stderr'],
    'ignore_exceptions' => false,
],

Then define the logging channel in your env

Activity icon

Started a new Conversation Logging In Laravel Vapor (Papertrail, Flare, Sentry - Nothing Is Working!)

I have a vapor project and I cannot get any form of logging to work. I have setup flare, sentry and papertrail but nothing registers.

I am using the vapor env:pull production (then push) commands to edit the config with my api keys. I have tested on non-vapor and it works fine there.

Other .env variables such as the database name are being accepted OK so I assume that its an issue to do with these packages running server-less opposed an env issue.

Does anyone have any insights into cause of this?

Sep
18
4 months ago
Activity icon

Replied to PHPUnit Assert Code Completion

Update: Turns out deleting the .idea folder, waiting for it to re-index, setting up the testing environment again AND restarting PHP Storm got them back to autocomplete!

Activity icon

Replied to PHPUnit Assert Code Completion

I have just tested the same setup in another project and that seems to work fine. I deleted the .idea folder and re-setup the first project but still no luck getting auto-completion.

Activity icon

Replied to PHPUnit Assert Code Completion

Thanks for this quick reply!

I have

<?php

namespace Tests\Unit;

use App\MessageSchedule;
use Carbon\Carbon;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class MessageScheduleHashTest extends TestCase
{
    use WithFaker, RefreshDatabase;

    public function setUp()
    {
        parent::setUp();
    }
...
namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
}

Then its into the Framework abstract Test case that extends PHPUnit\Framework\TestCase

Activity icon

Started a new Conversation PHPUnit Assert Code Completion

I am using Laravel valet and have setup my PHP Storm as follows:

  1. Kept the default phpunit.xml file apart from updating the db_connection to sqlite and db_database to :memory:

  2. PHPUnit is installed with composer and setup in the PHP Storm languages and frameworks. PHPUnit version is showing as 7.4.3 so assume this means it is installed correctly.

  3. Set the default configuration file to phpunit.xml

  4. Set a PHPStorm/PHPUnit Run/Debug Configuration. Se the test runner scope to "Defined in the configuration file".

I can now run tests from within phpstorm and they run correctly.

However, as far as I understand I should now be able to see all the phpunit assertions $this->assertTrue(); within my tests under code completion. I cannot... Any ideas why?

I read about a bug in PHPStorm 2016 where you have to press the spacebar first to get the static methos showing in code completion, but this does not help.

Activity icon

Replied to Dynamically Updating Mailgun Configuration

@sti3bas Thanks. I did know that but I do not really want to upgrade at this time. I found a workaround for now.

  1. Create an abstract base listener. My mail sending listeners all extend this.
  2. Set the user_profile variable in the listener.
  3. Call the setUser() method which extends the mailer service and configures the new mailgun settings.

In order to not have to duplicate the setSwiftMailer() and createMailgunDriver() methods I have extended the TransportManager manager within this base class. It is maybe a little messy but I cannot see anything within the TransportManager or Manager which is extends, to cause issues at this stage.

<?php

namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\TransportManager;
use Illuminate\Queue\InteractsWithQueue;

abstract class BaseNotification extends TransportManager implements ShouldQueue
{
    public $queue = 'email';
    public $user_profile = null;

    /**
     * Create the event listener.
     *
     * @throws \Exception
     * @return void
     */
    public function __construct()
    {
        $this->app = app();
        parent::__construct($this->app);

        if(!isset($this->user_profile)){
            throw new \Exception('User must be set');
        }

        $this->setUser($this->user_profile);
    }

    /**
     * Handle a job failure.
     *
     * @param  $event
     * @param  \Exception  $exception
     * @return void
     */
    public function failed($event, $exception)
    {
        \Sentry::captureException($exception);
    }

    /**
     * Set the sending profile. This sets the mail-gun domain and send from address
     *
     * @param string $user
     * @throws \Exception
     */
    private function setUser(string $user)
    {
        if(! in_array($user, ['user_1', 'user_2', 'user_3'])){
            throw new \Exception('User profile is not defined');
        }

        $arr = [
            'user_1' => [
                'domain' => 'mail.abc.co.uk',
                'email' => '[email protected]',
                'name' => 'James',
            ],
            'user_2' => [
                'domain' => 'mail.abc.xyz',
                'email' => '[email protected]',
                'name' => 'David',
            ],
        ];

        $config = $arr[$user];

        \Config::set('services.mailgun.domain', $config['domain']);

        $this->app->extend('mailer', function(\Illuminate\Mail\Mailer $mailer, $app) use($config){
            $swift = new \Swift_Mailer($this->createMailgunDriver());
            $mailer->setSwiftMailer($swift);
            $mailer->alwaysFrom($config['email'], $config['name']);
            return $mailer;
        });

    }

}

Activity icon

Started a new Conversation Dynamically Updating Mailgun Configuration

I have a situation where we need to change the mailgun confiig (domain & secret) on the fly. We need it to be able to be changed both during a normal request and during queue jobs/commands.

I have a solution in place for normal request, but need some suggestions on how this could be done across the whole app.

The configuration should be loaded into the method via variable/request opposed to getting it from the database.

The following middleware works for sending a normal request but I cannot use this within my queues (in L5.8 currently).

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Mail\Mailer;
use Illuminate\Mail\TransportManager;


class MailSwitcherMiddleware extends TransportManager
{

    public function __construct()
    {
        $this->app = app();
        parent::__construct($this->app);
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        \Config::set('services.mailgun.domain', $request->maingun_domain);

        $this->app->extend('mailer', function(Mailer $mailer, $app){
            $swift = new \Swift_Mailer($this->createMailgunDriver());
            $mailer->setSwiftMailer($swift);
            return $mailer;
        });

        return $next($request);
    }

}

Aug
26
4 months ago
Activity icon

Replied to Are The Majority Of The Laravel Contracts/interfaces Overkill?

Thanks for the video. It does not really explain why interfaces are used so much among frameworks, but I guess it leads back to being able to switch out core parts. Although as he said, once you have switched something out (if it was even possible!) then you would probably struggle to upgrade and so on.

Does anyone have any other reasons why they would use interfaces within their own applications?

Aug
25
4 months ago
Activity icon

Started a new Conversation Are The Majority Of The Laravel Contracts/interfaces Overkill?

Looking through a lot of the the Laravel 1st party code, I see a HUGE amount of contract/interface use. I understand the core concepts behind them:

  • Being able to switch out or use to different implementations. i.e. you may want have a payment processor contract that interfaces with both PayPal or Stripe. I see a real advantage of using contracts here.

  • Decoupling your code. Im not too sure what this one is about. The majority of people who are using Laravel are never going to want to switch out the core functionality for something else. i.e. you make a contract for a repository that is using Eloquent. I am sure there are very few people who would ever attempt to switch this out. What other use do contracts have here?

  • Readability - especially within something like Laravel's core code, I find this really useful to review all methods on a class.

So my question to you is:

Assuming:

  • You are not intended to switch out your framework, or any of the core components of it (i.e. Eloquent).
  • You are not writing code that anyone outside your team will need to view/work with.

What do you see the main benefits of writing interfaces, or would you agree they are generally overkill, and why does Laravel use them so so much?