madsem

madsem

Member Since 4 Years Ago

Experience Points
11,250
Total
Experience

3,750 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
76
Lessons
Completed
Best Reply Awards
1
Best Reply
Awards
  • start your 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-in-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 Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist 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 3
11,250 XP
Jul
08
2 days ago
Activity icon

Started a new Conversation Eloquent Relationship, Allow Only One Per (single Model) Parent Type.

I have the need to assign an Eloquent model a relationship, where it's only allowed to assign one Model per type. But it's not different Model classes as in a polymorphic, but the same model.

Trying to explain a little better, given we have these Models:

  • Domain
  • Account

Account can be accounts of different sources, indicated by a service column on the model.

Now I need to assign Domain models to Account models, one Domain model can belong to many Account models, but only with unique service column.

I'm sure this isn't unusual, and that I'm simply not seeing the wood because of all the trees in the way... :)

Plz halp! haha

Jun
30
1 week ago
Activity icon

Replied to Undefined Property, But When Dumped It Exists. How Can That Happen?

As so often, shortly after posting I saw the problem haha. It was running a loop and somewhere this was indeed not set!! Sighhhh :)

Activity icon

Started a new Conversation Undefined Property, But When Dumped It Exists. How Can That Happen?

I'm working with an external API, when retrieving a response I get an exception that the property is not defined. But it is, and if I dd it, it also displays... How can that even happen? I'm honestly lost how to even begin debugging this.

 ErrorException

  Undefined property: stdClass::$Campaign

This is the code:

$response = $this->client
            ->call($this->client->getCampaignManagementService(), 'GetCampaignsByAccountId', $request)
            ->Campaigns
            ->Campaign;
dump($response);

As you can see I added a dump there, this is the output: (with some redactions)

array:2 [
  0 => {#1176
    +"AudienceAdsBidAdjustment": null
    +"BiddingScheme": {#1171
      +"Type": "EnhancedCpc"
    }
    +"BudgetType": "DailyBudgetStandard"
    +"DailyBudget": xxx
    +"ExperimentId": null
    +"FinalUrlSuffix": null
    +"ForwardCompatibilityMap": {#2136}
    +"Id": xxx
    +"Name": "xxx"
    +"Status": "Paused"
    +"SubType": null
    +"TimeZone": "EasternTimeUSCanada"
    +"TrackingUrlTemplate": null
    +"UrlCustomParameters": null
    +"CampaignType": "Search"
    +"Settings": null
    +"BudgetId": null
    +"Languages": {#1199
      +"string": array:1 [
        0 => "All"
      ]
    }
  }
  1 => {#1911
    +"AudienceAdsBidAdjustment": null
    +"BiddingScheme": {#2066
      +"Type": "EnhancedCpc"
    }
    +"BudgetType": "DailyBudgetStandard"
    +"DailyBudget": xxx
    +"ExperimentId": null
    +"FinalUrlSuffix": null
    +"ForwardCompatibilityMap": {#2129}
    +"Id": xxx
    +"Name": "xxx"
    +"Status": "Paused"
    +"SubType": null
    +"TimeZone": "EasternTimeUSCanada"
    +"TrackingUrlTemplate": null
    +"UrlCustomParameters": null
    +"CampaignType": "Search"
    +"Settings": null
    +"BudgetId": null
    +"Languages": {#2130
      +"string": array:1 [
        0 => "All"
      ]
    }
  }
]

   ErrorException

  Undefined property: stdClass::$Campaign

  at app/Clients/Platforms/Operations/Bing/Get.php:157
    153|          */
    154|         $response = $this->client
    155|             ->call($this->client->getCampaignManagementService(), 'GetCampaignsByAccountId', $request)
    156|             ->Campaigns
  > 157|             ->Campaign;
    158| dump($response);

So it dumps out the actual response object, just as expected, and then errors out that the property is not defined, which it clearly is though...

This is the call method I'm using:

public function call($service, $method, $args = null)
    {
        try {

            $soapClient = $this->service($service)->GetService();

            return $soapClient->{$method}($args);

        } catch (SoapFault $e) {

            throw new ClientException($e->getMessage(), 0, $e);
        }
    }

Anyone got an idea what is going on here? I have never seen anything like it

Jun
14
3 weeks ago
Activity icon

Replied to Is This A Case For Repository Pattern?

@martinbean I see, thanks!

Is there a pattern/type of class used for jobs like the above?

Activity icon

Started a new Conversation Is This A Case For Repository Pattern?

I have an application that downloads potentially heavy csv files from third-party sources. (10K - 1MM rows) Now because each row in these csv files would need to be imported, a model created along with relationships etc, I decided to first import a file using LOAD DATA LOCAL INFILE, creating a dynamic table and saving this table name along with the model namespace that it should be later updated into.

Because it is possible that there are different reports, with different target models...

protected $reports = [
        TargetModel::class => 'reportType',
    ];

I loop over the above, download file, import and then save it in a table like:

// before here I dynamically get the columns for TargetModel::class
$table = $importer->loadIntoDynamicTable($file, $columns);

$report->table_name = $table;
$report->target_model = $this->import->model;
$report->save();

So now I have a dynamically created table, like tmp_HDkjhhfhddh8588, with data imported into it. Then I have a job that loops over these dynamic tables, the job so far knows only that the data from that table should be updated into TargetModel.

public function handle()
    {
        DB::beginTransaction();

        try {

            DB::table($this->temporary->table_name)->cursor()->each(function ($report) {

                // todo: write some kind of import class that knows how to create relationships on target model
                //$target = (new $this->temporary->target_model);
                //$target->save((array) $report);
            });

            DB::commit();

            $this->dropTable();

        } catch (Exception $e) {

            $this->dropTable();

            // do not re-run this job.
            $this->delete();

            throw $e;
        }

    }

I'm unsure what kind of class I could write that has knowledge of how to update the data and create the relationships.

Now I was reading about the repository pattern, it seems this would be the correct way of handling it? Just calling the repository from inside the above DB transaction.

Am I being on the right track there, or could this be solved in a better/more elegant way?

Jun
07
1 month ago
Activity icon

Replied to Mutator/Cast Set Called Without Accessing It, Or I Don't Understand How They Work!

Ok I solved it, it seems that the setter is indeed called, excessively as they say here: https://github.com/laravel/framework/discussions/31778

and it also didn't help that I checked for $model instead of $value in my MoneyCast.

Happy sunday!

Activity icon

Started a new Conversation Mutator/Cast Set Called Without Accessing It, Or I Don't Understand How They Work!

Something is happening in my code that makes absolute no sense to me right now. Been trying to pinpoint the issue now for over two hours but it proves to be very hard to spot, for me.

I am casting money amounts to int when they're saved, and get them as Money value objects. I have been trying this with a custom cast, as well as mutators/accessors, the issue remains the same.

At some point the Money object is cast to a string, which causes it's toString() method to format it like USD 2.0 for example. Then the money library cannot parse that anymore and throws an exception.

But the thing is, I have no idea how that happens because I don't access it directly.

Here is all of the code involved:

// my test method
// Arrange
        $report = factory(AdGroupCriterionPerformanceReport::class)
            ->state('withRelations')
            ->create();

        dump('factories done');

        // Act
        $report->optimize();

the optimize method on my model:

public function optimize(): bool
    {
        return (new OptimizeAdGroupCriterion($this))->execute();
    }

The class that's called by the optimize method:

public function __construct(AdGroupCriterionPerformanceReport $report)
    {
        $this->report = $report;
        $this->spend = $report->spend;
        dump('spend was accessed');

        $this->something = $report->campaign->max_bid; // when commented out, the issue disappears
        dd($this->spend);

    }

Here is the money cast class:

/**
     * Cast the given value.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  int  $value
     * @param  array  $attributes
     *
     * @return Money
     */
    public function get($model, $key, $value, $attributes)
    {

        if ($key == 'spend') {
            dump('get spend, type: ' . gettype($value));
        }
        dump($model->getTable() . ' - ' . $key . ': ' . $value);
        return Money::ofMinor($value, $this->loadCurrency());
    }


    /**
     * Prepare the given value for storage.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  Money|float  $value
     * @param  array  $attributes
     *
     * @return int
     */
    public function set($model, $key, $value, $attributes)
    {

        if ($key == 'spend') {
            dump('set spend, type: ' . gettype($value));
        }
        dump($model->getTable() . ' - ' . $key . ': ' . $value);
        if ($model instanceof Money) {
            return $model->getMinorAmount()->toInt();
        }

        return Money::of($value, $this->loadCurrency())->getMinorAmount()->toInt();
    }

Here is the output of the dumps in the code above:

PHPUnit 8.5.5 by Sebastian Bergmann and contributors.

"adv_campaigns - max_bid: 65"
"adv_campaigns - min_bid: 6"
"adv_campaigns - max_spend_without_revenue: 495"
"adv_ad_group_criteria - bid: 703"
"set spend, type: integer"
"adv_ad_group_criterion_reports - spend: 77"
"adv_ad_group_criterion_reports - revenue: 210"
"adv_ad_group_criterion_reports - current_cpc: 3228"
"factories done"
"get spend, type: integer"
"adv_ad_group_criterion_reports - spend: 7700"
"spend was accessed"
"set spend, type: object"
"adv_ad_group_criterion_reports - spend: USD 77.00"

Brick\Math\Exception\NumberFormatException : The given value "USD 77.00" does not represent a valid number.

When I comment out this line:

$this->something = $report->campaign->max_bid;

the error doesn't happen, and the dump log's last entry is "spend was accessed".

I absolutely do not understand what is happening there tbh, it shouldn't call the set method at all. Can someone explain to me what my mistake is?

Thanks! :)

Edit To make it a bit clearer, whenever I assign the $report variable or properties of it to something, after I set $this->spend = $report->spend; the Money error pops up because the object was cast to a string.

Jun
06
1 month ago
Activity icon

Replied to Yii Framework - Access Denied For MYSQL

I see your password is empty, try setting MYSQL_ALLOW_EMPTY_PASSWORD in your db config (where ever that is in Yii :) )

Activity icon

Replied to Lookup Table Int Size Defeats Purpose Of Table

You didn't mention anything about a couple hundred million rows :)

Either way, the bigint shouldn't be a big deal. Also:

Corresponding columns in the foreign key and the referenced key must have similar data types. The size and sign of integer types must be the same. The length of string types need not be the same. For nonbinary (character) string columns, the character set and collation must be the same.

https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

Activity icon

Replied to Lookup Table Int Size Defeats Purpose Of Table

Honestly sounds like premature and over-optimisation...

If the tables have very little data in them, just use the default bigInt. Not worth the hassle imho as I really don't see how it would improve anything at all :)

Activity icon

Replied to How To Upload Bulk Questions From Excel Sheet To Database In Laravel

fastest is just to use load data local in file:

https://stackoverflow.com/questions/14127529/mysql-import-data-from-csv-using-load-data-infile

https://dev.mysql.com/doc/refman/5.7/en/load-data.html

You can manually type it in your db management software sql console, or also automate it programmatically ofc

Activity icon

Replied to Laravel Testing Third Party API Responses And Socialite

on my phone atm, so can't type a lot of code. But i just did a similar thing and this link was what helped me the most:

https://stefanzweifel.io/posts/how-i-write-integration-tests-for-laravel-socialite-powered-apps

Activity icon

Replied to How To Create Foreign Key Items From External API And Save Into Local DB

on my phone atm but i'll try my best:

Assuming you have a belongsTo relationship set up for Department on the Employee model, you vould just do:

$employee->department()->updateOrCreate([
 'department_code' => clientdata['DepartmentCode']
], [
 'fields_to_update' => 'here',
...
]);

Or if you don't have a relationship, you can just do it in the same loop you have already, using the model facade directly:


Department::updateOrCreate([
 'department_code' => clientdata['DepartmentCode']
], [
 'fields_to_update' => 'here',
...
]);

First array in updateOrCreate is the values it checks for existence, if found it tries to update the values in second array.

If not found it will create a new row using data from both arrays

Activity icon

Replied to How To Create Foreign Key Items From External API And Save Into Local DB

use updateOrCreate() method instead.

https://laravel.com/docs/7.x/eloquent

Then just loop over the results like you do above, and it will update whatever has changed, or create if it doesn't exist.

Activity icon

Replied to Problem With Where To Put Currency Code, Relationships Problems

For now I solved it by adding a default to the Account.

protected $attributes = [
        'currency' => 'USD',
    ];

and then call all account() relationships on other models with withDefault().

But still interested if there's a better way of doing this, as it kind of feels wonky :)

Activity icon

Replied to Problem With Where To Put Currency Code, Relationships Problems

Thanks a lot @martinbean, that makes a lot of sense, the issue is only that the currency code is used by all models under an Account, so saving the code in all tables seems hard to manage?

And you're right, the issue is that the relationship needs to exist first, but since I need to use the currency code in the get/set of the cast so that money is correctly converted to/from minor (int) amounts, the set is always called so that I think, I can't really set the relationship first eh?

But now thinking of saving the currency code directly in all models, I'm unsure, mhhh.

Because all monetary fields use the minor int amount and currency code to calculate between minor amount and total amount, but the Account model is the one that is tied to a currency code. (I'm mirroring the structure of a third-party, so I don't have influence over what model to relate the currency to)

So with this info, do you still think saving the codes directly on all tables make sense? Or can you think of a way how to solve this with relationships?

Activity icon

Started a new Conversation Problem With Where To Put Currency Code, Relationships Problems

I'm really banging my head a bit on how to add currency codes to my multi currency application in a way that the relationships are always set.

Right now my problem is that no matter how much I think about it and then try something else, at some point I run into the same issue: Models can not be saved because relationship to the model holding the currency is not found/null.

I have an Account model, which holds the currency code. For example my factory looks like this:

$factory->define(Account::class, function (Faker $faker) {
    return [
        'remote_account_id' => $faker->shuffleString('ABCDEFGHIJKLMNOPQRSTUVWXYZ-_'),
        'name' => $faker->userName,
        'email' => $faker->companyEmail,
        'currency' => $faker->currencyCode,
        'tracking_id' => $faker->uuid,
        'status' => $faker->randomElement([
            AccountStatuses::Active, AccountStatuses::Paused, AccountStatuses::Draft,
        ]),
    ];
});

$factory->define(AdGroupCriterionPerformanceReport::class, function (Faker $faker) {

    return [
        'day' => dateRange(Carbon::now()->subDays(30), Carbon::now()),
        'conversions' => $faker->numberBetween(0, 250),
        'conversion_rate' => $faker->randomFloat(2, 1, 100),
        'spend' => $faker->numberBetween(0, 300),
        'revenue' => $faker->numberBetween(0, 300),
        'impressions' => $faker->numberBetween(0, 30000),
        'clicks' => $faker->numberBetween(0, 3000),
        'quality_score' => $faker->numberBetween(0, 10),
        'click_through_rate' => $faker->randomFloat(2, 0, 100),
        'current_cpc' => $faker->numberBetween(0, 6000),
        'average_position' => $faker->numberBetween(0, 100),
    ];
});

$factory->state(AdGroupCriterionPerformanceReport::class, 'withRelations', function (Faker $faker) {
    return [
        'adv_account_id' => factory(Account::class)->lazy(),
        'adv_campaign_id' => factory(Campaign::class)->lazy(),
        'adv_ad_group_id' => factory(AdGroup::class)->lazy(),
        'adv_ad_group_criterion_id' => factory(AdGroupCriterion::class)->lazy(),
    ];
});

When I now try to write a test for example, it errors out because relationship doesn't exist.

// Arrange
        $account = factory(Account::class)->create();
        $report = factory(AdGroupCriterionPerformanceReport::class)
            ->state('withRelations')
            ->create(['adv_account_id' => $account->id]);
ErrorException : Trying to get property 'currency' of non-object
 /opt/project/app/Casts/MoneyCast.php:41

And I have a cast class on the models that have money fields:

<?php


namespace App\Casts;


use Brick\Money\Money;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class MoneyCast implements CastsAttributes
{

    /**
     * Cast the given value.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  string  $value
     * @param  array  $attributes
     *
     * @return Money
     */
    public function get($model, $key, $value, $attributes)
    {
        return Money::ofMinor($value, $model->account->currency);
    }


    /**
     * Prepare the given value for storage.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  string  $value
     * @param  array  $attributes
     *
     * @return string
     */
    public function set($model, $key, $value, $attributes)
    {
        return Money::of($value, $model->account->currency)->getMinorAmount()->toInt();
    }

}

I'm unsure now, is the way I structured this, wrong? Should a currency code have a direct relationship on all models that need it? Or is accessing it through a distant relationship in general okay?

Is there a better way to handle this?

Jun
05
1 month ago
Activity icon

Replied to Access $amount In Factory Possible?

Ok thanks for that, I guess :) I think I know now what you meant! Thanks!

Activity icon

Replied to Access $amount In Factory Possible?

Thanks! But, are you saying when using 'times()' it is possible to get that dynamically inside the closure? Or did you mean i'd have to set a variable inside the definition myself? (which I am doing atm)

Activity icon

Replied to Access $amount In Factory Possible?

lol :) Thanks, but that was just my pseudo code example, sadly that doesn't work

Activity icon

Started a new Conversation Access $amount In Factory Possible?

Is it somehow possible to get the $amount specified in the factory(SomeClass::class, 30) helper, from inside the factory closure?

I need to reset a helper method every xy iterations, and would love if I can simply access that number somehow.... :)

ie:

$factory->define(......, function(Faker $faker) {
 $amount = $factory->amount; // 30
}
Jun
04
1 month ago
Activity icon

Replied to 1292 Incorrect Datetime Value With Protected $dates & Faker

Sorry, I meant I have a custom date field...

When i tinker it, I get a proper date string:

>>> $faker->dateTimeBetween('-6 months', 'now')->format('Y-m-d')
=> "2019-12-23"
>>> 

But whenever I try to seed I get this error.

migration:

$table->date('date');

model:

/**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = false;

    /**
     * The attributes that should be mutated to dates.
     *
     * @var array
     */
    protected $dates = [
        'date',
    ];
Activity icon

Started a new Conversation 1292 Incorrect Datetime Value With Protected $dates & Faker

I'm writing seeders, and I have one model with $timestamps = false. On that model I have a custom timestamp field, and I cast it using the $dates = [] property.

Now in my seeder I have:

'date' => $faker->dateTimeBetween('-6 months', 'now')->format('Y-m-d'),

But I always get an error:

Invalid datetime format: 1292 Incorrect datetime value: '2020-03-07T08:59:07.000000Z' for column 'date' at row 1

Tried a shitload of things, but nothing works, only when I comment out the

protected $dates = [
        'date',
    ];

the timestamp field saves...

What am I doing wrong? Laravel's documentation says that $dates can be passed in various formats, such as a simple date string like 2019-12-23, but it does not work.

Activity icon

Replied to $visitor = Tracker::currentSession(); Return Null Data.

Are you sure you've recorded visits already, do any show up in your database?

Activity icon

Replied to Seeding Only A Few Models & Relationships Takes Close To 2 Min, How To Improve>

Thanks!

I've played around a bit, and moved all the relationship creation into the factories, like:

return [
	'some_id' => factory(SomeClass::class),
];

And now my seeder only has one factory call, for the class that is the lowest in the relationship hierarchy. It is much faster now.

Is this a good practice to get into for seeders?

Seed a class that is the lowest in the hierarchy, have factories create all their relationships, so when you call the lowest hierarchy factory all the relationship created kinda "bubble up" from that point?

Jun
03
1 month ago
Activity icon

Started a new Conversation Seeding Only A Few Models & Relationships Takes Close To 2 Min, How To Improve>

I just started testing and seeding in general, and I'm using the PhpStorm integration in combination with Vessel for Docker.

I have a single seeder atm. which creates only a few models and relationships, but already takes close to 2 minutes to complete.

Is there anything I can do to improve on this, or is it what it is and testing/seeding is always slow?

/**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {

        factory(Platform::class, 2)->create()->each(function ($platform) {

            $customers = $platform->platformCustomers()->saveMany(
                factory(PlatformCustomer::class, 2)->make()
            );

            $customers->each(function ($customer) {
                $accounts = $customer->platformAccounts()->saveMany(
                    factory(PlatformAccount::class, 3)->make()
                );

                $accounts->each(function ($account) {
                    $account->platformCampaigns()->saveMany(
                        factory(PlatformCampaign::class, 3)->make()
                    );
                });
            });

        });

        $campaigns = PlatformCampaign::all();
        $campaigns->each(function ($campaign) {
            $adGroups = $campaign->platformAdGroups()->saveMany(
                factory(PlatformAdGroup::class, 5)->make()
            );

            $adGroups->each(function ($adGroup) {
                $adGroupCriteria = $adGroup->platformAdGroupCriteria()->saveMany(
                    factory(PlatformAdGroupCriterion::class, 5)->make()
                );

                $adGroupCriteria->each(function ($adGroupCriterion) {
                    $adGroupCriterion->platformAdGroupCriterionPerformanceReports()->saveMany(
                        factory(PlatformAdGroupCriterionPerformanceReport::class, 10)->make()
                    );
                });
            });
        });
    }
Jun
01
1 month ago
Activity icon

Started a new Conversation When Testing, And Your App Requires Third-party API Data, How/what To Test First?

When testing, and your app requires third-party API data, how/what to test first?

So I'm finally starting to write tests :) First project where I decide to do this, will get all of it's data (except local users) from third-party apis.

How would you start testing, what tests to write first? Actually having the tests connect via API, get results and then do something with it? Fake all of the data, and once at that point, only test if a connection is successful i.e returns something? What if certain data cannot be faked?

Maybe you guys can give me some good pointers here, I would certainly appreciate any :)

May
30
1 month ago
Activity icon

Replied to Confusion About Naming & Relationships For Models With Same Name But Different Structure/use Case

Thanks @bobbybouwmann, you've hit the nail on the head. What you said makes a lot of sense!

Gives me actually confidence in my latest decision to prefix all models with their domain, ie:

App\Models\Platforms:

  • Platform
  • PlatformCustomer
  • PlatformAccount
  • Platform...

App\Models\Networks:

  • Network
  • NetworkAccount
  • Network...

Then instead of following Laravel's convention for foreign keys, I will leave out the prefix there and set the foreign key names inside each relationship method.

This will result in long model names, but ultimately it might also be nice for auto-suggest in PhpStorm etc. You always get everything related to one domain immediately when typing plat...

Activity icon

Started a new Conversation Confusion About Naming & Relationships For Models With Same Name But Different Structure/use Case

Hello fellow Laracaster's :)

I'm banging my head a little on this one, and hope you can give me some pointers.

Trying to come up with names and proper relationships for models that will have a different use case in my app, but have the same names.

There are two distinctions: Platforms & Networks Each represent a different use case in my app, and consist of multiple child models.

What I have:

Platforms:

  • Platform
  • Customer
  • Account

Networks:

  • Network
  • Account

Now the Account model for each of these use cases, will share just a few column names like name and email, the rest will be completely different, even though they practically represent the same thing (A user/customer owning an account)...

For example the Account model for a Platform will have a column tracking_uuid, and is involved in tracking visitors on websites, while the Network Account model won't have this column and will simply be used to label statistics.

The more I plan relationships now, the more I realize that down the line there will be a lot of confusion with method names, table names and so forth.

Now I've tried multiple things, from moving them into their own namespaces like App\Models\Platforms\Account to trying to prefix all models with either Platform or Network, but in the end the column names of database migrations get simply too long, it becomes messy and ultimately a little confusing.

Now I was thinking if using polymorphic relationships might be the solution, but I'm unsure where I would then move the columns to that are different in each model, and if doing that might get me into trouble down the line somewhere.

Any pointers/ideas how I could improve this?

PS: might be a good idea to also mention the relationships... :)

  • Platform can have many Customer who can own many Account.
  • Network can have many Account

For a Network, the Account model is basically the user/customer, while a Platform has Customers which own Accounts

May
28
1 month ago
Activity icon

Commented on Simpler Code With UseCase Classes

Great explanation @jeffreyway :)

When you created the directory UseCases, I was thinking Features would be a better description, as in Feature tests. Because that is basically what it is, one of the main features of the application.

Or do you think that would be confusing, as features is also terminology that has other meanings in a programming context.

I.e: When naming things, do you try to avoid names that already have other meanings in the Framework, even if you think they would fit better?

Apr
22
2 months ago
Activity icon

Started a new Conversation Service Container - How To Bind Arguments That Come From Database?

I'm trying to bind interfaces to implementations, which have dependencies that require arguments from Eloquent models.

All the examples I find online are just talking about binding parameters that come from a static location, like the config or the request instance. So I'm unsure how to achieve the following:

I have an interface that is bound to a manager class, which builds API clients. The API clients require configuration that comes from the database.

This is what I have so far:

$this->app->singleton(PlatformFactory::class, function ($app) {
            return new PlatformManager($app);
        });

PlatformManager driver creation:

/**
     * Create an instance of the bing driver.
     *
     * @return \App\Integrations\Platforms\Providers\Bing\BingPlatform
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function createBingDriver()
    {

        $config = $this->container->make('config')['platforms.bing'];

        $client = $this->buildClient(
            BingClient::class,
            $config['client_id'],
            $config['client_secret'],
            $config['developer_token'],
            $this->account->customer_id, // comes from database
            $this->account->account_id,  // comes from database
            $this->auth->refresh_token,  // comes from database
            $config['environment']
        );

        return new BingPlatform('bing', $client, $this->account->id);  // id comes from database
    }

BingClient constructor:

/**
     * BingClient constructor.
     * @param $clientId
     * @param $clientSecret
     * @param $developerToken
     * @param $customerId
     * @param $accountId
     * @param $refreshToken
     * @param $environment
     */

BingPlatform costructor:

/**
     * AbstractPlatform constructor.
     * @param string $driver
     * @param \App\Integrations\Platforms\Contracts\Client $client
     * @param $id
     */

I am now trying to somehow bind all this to the service container, but I'm unsure how to work with the parameters that come from the database.

If I remove the constructor, and use setters that would certainly work, but then I would have to write a huge method chain every time I instantiate the BingClient and BingPlatform.

Is there a cleaner, better way of doing this?

Apr
21
2 months ago
Activity icon

Started a new Conversation Relationship Not Saving, Help.

I'm trying to save a relationship, but nothing I do seems to work. This is what I have so far:

PlatformUser model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PlatformUser extends Model
{
    /**
     * The attributes that aren't mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = true;

    /****************************************************************
     *  Relationships
     ***************************************************************/

    /**
     * Get the AuthMethod implementation model for this user
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    function authMethod()
    {
        return $this->belongsTo(AuthMethod::class, 'auth_id');
    }

    /**
     * Get the PlatformAccount models owned by this user
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    function accounts()
    {
        return $this->hasMany(PlatformAccount::class);
    }

}

PlatformUser migration:

public function up()
    {
        Schema::create('platform_users', function (Blueprint $table) {
            $table->id();
            $table->string('driver');
            $table->string('user_id');
            $table->string('full_name');
            $table->string('user_name');
            $table->string('email');
            $table->timestamps();

            $table->bigInteger('auth_id')
                  ->unsigned()
                  ->index()
                  ->nullable();

            $table->foreign('auth_id')
                  ->references('id')
                  ->on('auth_methods')
                  ->cascadeOnDelete();
        });
    }

AuthMethod model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class AuthMethod extends Model
{
    /**
     * The attributes that aren't mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = true;

    /****************************************************************
     *  Relationships
     ***************************************************************/

    /**
     * Get the authentication method implementation model
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function auth()
    {
        return $this->morphTo();
    }

AuthMethod migration:

public function up()
    {
        Schema::create('auth_methods', function (Blueprint $table) {
            $table->id();
            $table->morphs('auth');
            $table->timestamps();
        });
    }

OAuth2AuthMethod model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class OAuth2AuthMethod extends Model
{

    /**
     * The model's table name
     *
     * @var string
     */
    protected $table = 'oauth2_tokens';

    /**
     * The attributes that aren't mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = true;
    /****************************************************************
     *  Relationships
     ***************************************************************/

    /**
     * Get the AuthMethod owning this oauth2 implementation
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphOne
     */
    function authMethod()
    {
        return $this->morphOne(AuthMethod::class, 'auth');
    }


}

PlatformAccount model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PlatformAccount extends Model
{

    /**
     * The attributes that aren't mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = true;

    /****************************************************************
     *  Relationships
     ***************************************************************/

    /**
     * Get the PlatformUser model this account belongs to
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    function user()
    {
        return $this->belongsTo(PlatformUser::class, 'platform_user_id');
    }
}

PlatformAccount migration:

public function up()
    {
        Schema::create('platform_accounts', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('customer_id');
            $table->string('account_id');
            $table->string('currency_code');
            $table->uuid('tracking_id');
            $table->timestamps();

            $table->bigInteger('platform_user_id')
                  ->unsigned()
                  ->index()
                  ->nullable();

            $table->foreign('platform_user_id')
                  ->references('id')
                  ->on('platform_users')
                  ->cascadeOnDelete();
        });
    }

When I'm trying to create all the relationships, the auth_methods table relationship and the auth_id in the platform_users table are all empty/null.

$user = OAuth2::provider('bing')->stateless()->user($responseUri);

            // Create the AuthMethod model
            $oauth2 = new OAuth2AuthMethod();
            $oauth2->refresh_token = $user->refreshToken;
            $oauth2->save();

            $auth = new AuthMethod();
            $auth->auth()->associate($oauth2);
            $auth->save();

            // Create or get the PlatformUser model
            $platformUser = PlatformUser::updateOrCreate(
                ['user_id' => $user->id],
                [
                    'driver'    => 'bing',
                    'full_name' => $user->fullName,
                    'user_name' => $user->userName,
                    'email'     => $user->email
                ]
            );

            // update the AuthMethod relationship for the user
            $platformUser->authMethod()->associate($auth)->save();

            // update or create the relationships for the user's accounts
            $user->accounts->each(function ($account) use ($platformUser) {

                $platformUser->accounts()->updateOrCreate(
                    [
                        'customer_id' => $account->customerId,
                        'account_id'  => $account->accountId,
                    ],
                    [
                        'name'          => $account->accountName,
                        'currency_code' => $account->currencyCode,
                        'tracking_id'   => $this->tracking_id ?? \Illuminate\Support\Str::uuid(),
                    ]);


            });

Where am I going wrong here?

Activity icon

Awarded Best Reply on Confusion How To Set Up One To Many Optional Relationships

I figured it out, here for others with the same problem:

Many thanks to @pmall and @harryg in this thread: https://laracasts.com/discuss/channels/eloquent/dynamic-eloquent-relationship?page=1

I now created a base model AuthMethod, which has polymorphic One To One relationship with OAuth2AuthMethod and AccessTokenAuthMethod.

The account models have a belongsTo relationship with AuthMethod and can now dynamically query the authentication method using the same relationship method, like so:

$accounts = PlatformAccount::with('authMethod')->get();
        $accounts->each(function ($account) {

            dd($account->authMethod->auth);

        });
Activity icon

Replied to Confusion How To Set Up One To Many Optional Relationships

I figured it out, here for others with the same problem:

Many thanks to @pmall and @harryg in this thread: https://laracasts.com/discuss/channels/eloquent/dynamic-eloquent-relationship?page=1

I now created a base model AuthMethod, which has polymorphic One To One relationship with OAuth2AuthMethod and AccessTokenAuthMethod.

The account models have a belongsTo relationship with AuthMethod and can now dynamically query the authentication method using the same relationship method, like so:

$accounts = PlatformAccount::with('authMethod')->get();
        $accounts->each(function ($account) {

            dd($account->authMethod->auth);

        });
Apr
20
2 months ago
Activity icon

Replied to Confusion How To Set Up One To Many Optional Relationships

Or is there a way to use a polymorpic relationship in reverse? So that the id and type columns would be on the Account models?

Or am I overthinking here and a simple belongsTo/HasMany for both User models per Account model is the way to go?

Activity icon

Started a new Conversation Confusion How To Set Up One To Many Optional Relationships

I have Four Models:

  • OAuth2User
  • AccessTokenUser

And:

  • PlatformAccount
  • NetworkAccount

And these are the relationship requirements:

  • A PlatformAccount belongsTo OAuth2User OR AccessTokenUser.

  • A NetworkAccount belongsTo OAuth2User OR AccessTokenUser.

  • An OAuth2User hasMany NetworkAccount OR PlatformAccount.

  • An AccessTokenUser hasMany NetworkAccount OR PlatformAccount.

I'm unsure what's the best relationship here, polymorphic doesn't seem to do what I need, a simple belongsTo/hasMany on each model results in multiple foreign keys in migration, where of course then one will always be null (Which also doesn't seem right?)

I hope you guys can push me in the right direction, thanks! :)

Apr
07
3 months ago
Activity icon

Replied to Prevent Failed Jobs From Being Written To Failed Jobs Table?

Ahhh understand, yes that was what I was asking. Thanks!

I have some jobs that if they fail, don't need to be rerun because another job will pick up shortly after. So I thought it would make no sense to log these jobs and rerun them, in case of failure I would just like to be notified so I'm able to fix it if the cause is an error in code etc.

Activity icon

Replied to Eloquent Attributes Missing On UpdateOrCreate, Help :)

Okay so the problem here is, before the model is persistet the first time the attributes aren't set yet when I reference them in my accessors / mutators.

Specifically the currency_code, when I move the currency code field above the spend & revenue fields inside the updateOrCreate call, it works... It is hacky though of course.

PlatformReport::updateOrCreate(
                [
                    'date'                 => $row[0],
                    'driver'               => $this->platform->driver,
                    'account_identifier'   => $this->platform->accountIdentifier,
                    'adgroup_criterion_id' => $row[4],
                ],
                [
                    'account_id'                 => $row[1],
                    'campaign_id'                => $row[2],
                    'adgroup_id'                 => $row[3],
                    'adgroup_criterion_type'     => CriterionType::KEYWORD,
                    'conversions'                => $row[5],
                    'conversion_rate_percentage' => empty($row[6]) ? 0 : str_replace('%', '', $row[6]),
                    'currency_code'              => $this->platform->account['currency_code'],
                    'revenue_in_cents'           => $row[7],
                    'spend_in_cents'             => $row[8],

                ]
            );
        }

Not a real solution, but that works. Now I have to figure out how I can make this work without depending on the order of fields in Eloquent methods lol ;/

Activity icon

Replied to Prevent Failed Jobs From Being Written To Failed Jobs Table?

Not quite, I asked "Prevent failed jobs from being written to failed jobs table?"

Wasn't clear enough maybe. Since certain jobs are idempotent and don't need to be rerun, it makes no sense to add them to the failed jobs table.

So I wanted to know what the best practice here would be, to not add certain jobs to the failed jobs table and only those that actually need to be run again.

Activity icon

Replied to Prevent Failed Jobs From Being Written To Failed Jobs Table?

Ok thanks, but how does that prevent the failed job from being written to the failed_jobs table? I don't follow, sorry :)

Activity icon

Replied to Eloquent Attributes Missing On UpdateOrCreate, Help :)

So I know now when this happens...

But not how to prevent it. The problem is when a record doesn't yet exist in the database.

Then the attribute currency_code,revenue_in_cents,spend_in_cents are missing, but when the records already exist and are to be updated it works.

Does that have something to do with the data not coming through the Request?! I'm really confused

Activity icon

Replied to Eloquent Attributes Missing On UpdateOrCreate, Help :)

Ok no, actually this doesn't work haha :)

The reason it inserted into the table now was simply that with the snake cased method names, Eloquent didn't trigger the accessors/mutators and wrote values to database without any transformation.

I've also looked at the HasAttributes trait, and according to how the mutator names are formed it should work with my original casing...

When I use setRevenueInCentsAttribute etc again, the methods are actually triggered, but the few attributes from my initial post are missing again.

Activity icon

Replied to Eloquent Attributes Missing On UpdateOrCreate, Help :)

Or well not camel, but Studly, which my method names were I believe?

Activity icon

Replied to Eloquent Attributes Missing On UpdateOrCreate, Help :)

Thanks! I gotta say though, I don't quite understand why this works/doesn't. Read over the documentation, and it says db fields snake case, ie revenue_in_cents and method name camel case i.e getRevenueInCents. So not quite sure why it only works when writing snake case in method?

Activity icon

Replied to Eloquent Attributes Missing On UpdateOrCreate, Help :)

Yup, that was it! Thank you :)

I thought the way I was casing it was Laravel convention, I have to read over that part again.

Activity icon

Started a new Conversation Eloquent Attributes Missing On UpdateOrCreate, Help :)

I'm downloading a csv file, then import it with laravel excel and have accessors & mutators set on my model. But for some reason there a few attributes completely missing, and I'm out of ideas as to why this happens.

Hoping one of you guys can tell me where I'm being stupid :)

PlatformReport::updateOrCreate(
                [
                    'date'                 => $row[0],
                    'driver'               => $this->platform->driver,
                    'account_identifier'   => $this->platform->accountIdentifier,
                    'adgroup_criterion_id' => $row[4],
                ],
                [
                    'account_id'                 => $row[1],
                    'campaign_id'                => $row[2],
                    'adgroup_id'                 => $row[3],
                    'adgroup_criterion_type'     => CriterionType::KEYWORD,
                    'conversions'                => $row[5],
                    'conversion_rate_percentage' => empty($row[6]) ? 0 : str_replace('%', '', $row[6]),
                    'revenue_in_cents'           => $row[7],
                    'spend_in_cents'             => $row[8],
                    'currency_code'              => $this->platform->account['currency_code'],
                ]
            );
public function up()
    {
        Schema::create('platform_reports', function (Blueprint $table) {
            $table->id('id');
            $table->timestamp('date');
            $table->string('driver');
            $table->string('account_identifier');
            $table->string('account_id');
            $table->string('campaign_id');
            $table->string('adgroup_id');
            $table->string('adgroup_criterion_id');
            $table->string('adgroup_criterion_type');
            $table->integer('conversions');
            $table->decimal('conversion_rate_percentage');
            $table->integer('revenue_in_cents');
            $table->integer('spend_in_cents');
            $table->string('currency_code');

            $table->index(['date', 'account_id', 'adgroup_criterion_id'], 'platform_reports_index');
        });
    }
<?php

namespace App;

use App\Helpers\Money;
use Illuminate\Database\Eloquent\Model;

class PlatformReport extends Model
{

    protected $guarded = ['id'];

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = false;

    /**
     * The attributes that should be mutated to dates.
     *
     * @var array
     */
    protected $dates = [
        'date',
    ];

    /**
     * Get revenue in cents as floating amount
     *
     * @param $value
     * @return float
     */
    function getRevenueInCentsAttribute($value)
    {
        return Money::fromBaseToFloat($value, $this->attributes['currency_code']);
    }

    /**
     * Set revenue in cents as currency base amount
     *
     * @param $value
     * @return int
     */
    function setRevenueInCentsAttribute($value)
    {
        dd($this);
        return $this->attributes['revenue_in_cents'] = Money::fromFloatToBase($value, $this->attributes['currency_code']);
    }

    /**
     * Get spend in cents as floating amount
     *
     * @param $value
     * @return float
     */
    function getSpendInCentsAttribute($value)
    {
        return Money::fromBaseToFloat($value, $this->attributes['currency_code']);
    }

    /**
     * Set spend in cents as currency base amount
     *
     * @param $value
     * @return int
     */
    function setSpendInCentsAttribute($value)
    {
        return $this->attributes['spend_in_cents'] = Money::fromFloatToBase($value, $this->attributes['currency_code']);
    }

}

The output of the dd($this) in the model mutator is this:

App\PlatformReport^ {#2326
  #guarded: array:1 [
    0 => "id"
  ]
  +timestamps: false
  #dates: array:1 [
    0 => "date"
  ]
  #connection: "mysql"
  #table: "platform_reports"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: false
  +wasRecentlyCreated: false
  #attributes: array:10 [
    "date" => "2019-12-09 00:00:00"
    "driver" => "bing"
    "account_identifier" => "xxxxx"
    "adgroup_criterion_id" => xxxxx
    "account_id" => xxxxx
    "campaign_id" => xxxxx
    "adgroup_id" => xxxxx
    "adgroup_criterion_type" => "keyword"
    "conversions" => 0
    "conversion_rate_percentage" => "0.00"
  ]
  #original: []
  #changes: []
  #casts: []
  #classCastCache: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  #hidden: []
  #visible: []
  #fillable: []
}
Activity icon

Started a new Conversation Prevent Failed Jobs From Being Written To Failed Jobs Table?

I have a chain of events that trigger jobs, this whole chain of events will be idempotent, so it won't need to be re-run on fail. I only want to be notified.

What is the best practice here to handle scenarios like this?

Apr
01
3 months ago
Activity icon

Started a new Conversation How To Decorate My API Clients - Need Input

Hey guys,

I'm trying to figure out the best/most flexible way to decorate my API client. I have an application that wraps multiple third-party APIs, some of them use OAuth2 while others use REST etc.

namespace App\Integrations\Apis\Platforms;


use App\Integrations\Apis\Contracts\Account;

abstract class AbstractPlatform implements Account
{

    /**
     * The account model of a platform.
     *
     * @var \App\Platform
     */
    protected $account;

    /**
     * Set platform account model
     *
     * @param \App\Platform $account
     * @return $this
     */
    public function with($account)
    {
        $this->account = $account;

        return $this;
    }
}
<?php


namespace App\Integrations\Apis\Platforms;


use App\Integrations\Apis\Clients\BingClient;
use App\Integrations\Apis\Contracts\Client;

class BingPlatform extends AbstractPlatform
{

    /**
     * Client implementation
     *
     * @var BingClient
     */
    protected $client;

    public function __construct(Client $client)
    {
        $this->client = $client;

        // set up client if platform account was set
        if ($this->account) {
            $this->client->setAccountId($this->account->account_id);
        }
    }
}

ServiceProvider:

// Register contextual bindings
        $this->app->when(BingPlatform::class)
                  ->needs(Client::class)
                  ->give(function () {

                      $config = config('platforms.bing');

                      return (new BingClient(
                          $config['client_id'],
                          $config['client_secret'],
                          $config['developer_token']
                      ));
                  });

This is how I instantiate the BingPlatform and pass the account model to it:

$account = PlatformAccount::find(1);
Platform::provider('bing')->with($account);

The account model then has additional fields required to connect to the API, for example account_id, while the app config just has the config required for my app to connect.

The way I am doing it now, would of course work, but it kind of feels wrong to me that I manually set things like $this->client->setAccountId($this->account->account_id); in the BingPlatform.

To reiterate: The app will have multiple Platforms, some require different connections and arguments than others, so I'm trying to make it so that the connection / Client can be flexible.

Is there a better way? I'm unsure how else I could structure it

Jan
08
6 months ago
Activity icon

Started a new Conversation How To Pass A String Argument Across Multiple Classes To Use In A Where Clause

Hey guys,

I'm building a CLI application in Laravel. Currently I'm banging my head against the wall, trying to figure out the best/cleanest way to make sure that multiple event listeners have access to a string argument to use in a DB query as where clause.

Right now, I'm simply passing it along in the constructor of each event so that it is then available in the handle method of the listener, but it kind of feels dirty and not very clean/elegant.

I wonder if you Laracastians can show me a better way?

The whole flow starts of with a command, that runs on a scheduler:

/**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // get platforms from PPC config
        $platforms = array_keys(config('ppc'));

        foreach ($platforms as $platform) {

            // get refresh token for current platform from database
            $oAuth2 = OAuth2::where('platform', $platform)->first();

            // authenticate with platform API
            $ppc = PPC::platform($platform)->token($oAuth2->refresh_token);

            // download report for today and yesterday
            $today = date("Y-m-d");
            $yesterday = date("Y-m-d", strtotime("-1month"));

            $reportFile = $ppc->report()->setdateRange($yesterday, $today)->getKeywordPerformanceReport();

            // import report file to model and delete file
            if ($reportFile) {
                $ppc->import()->queue($reportFile)->allOnQueue('imports');
                unlink($reportFile);
            }

        }
    }

The config is this here:

return [

    'platform-name-1' => [

        12345 => [
                'setting_1' => 10,
                ....
        ],

    'platform-name-2' => [

        123456 => [
                'setting_2' => 10,
                ....
        ],
];

Now the command at the top, loops through the entries in the config file, the first level of array keys.

Those are the strings that I need further down the line, to make where clauses as those same strings are also used in the database as labels.

So in the command, this line $ppc->import()->queue($reportFile)->allOnQueue('imports'); triggers a file download from a third party api, depending on which platform in the config file. (The array keys there are the names of the platforms, select an oAuth2 refresh token to connect to the correct platform api)

Then after those files were downloaded and saved locally, an event is fired that starts loading the file in chunks into jobs which are then queued and processed.

After that is done, some other events and listeners are also fired, and in each one I need the array key which is in the $platform variable in the command.

So currently I am passing it from each event to it's listener, which then troggers another event after the job is done and pass it along there too, always like this:

Event:

class AfterKeywordReportImport
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * The label of the platform used in the database
     */
    public $platformName;

    /**
     * Create a new event instance.
     *
     * @param string $platformName
     */
    public function __construct($platformName)
    {
        $this->platformName = $platformName;
    }

}

Listener:

/**
     * Handle the event.
     *
     * @param AfterKeywordReportImport $event
     * @return void
     */
    public function handle(AfterKeywordReportImport $event)
    {
        DB::table('platform_reports')
          ->select('id','keyword_id')
          ->where('platform', $event->platformName)
          ->distinct()
          ->chunkById(100, function ($ids) use ($event) {

              // pass an array of ids to the job
              $keywordIds =  $ids->pluck('keyword_id');
              array_push($this->calculationJobs, new ProcessKeywords($event->platformName, $keywordIds));
          });

        // grab first job from array to use in dispatch
        $firstJob = array_shift($this->calculationJobs);

        // append the job that fires an 'after event' after all jobs have successfully completed
        array_push($this->calculationJobs, new AfterProcessKeywords($event->platformName));

        // dispatch job chain
        dispatch($firstJob)->chain($this->calculationJobs);
    }

Is there a better way how I could do that, without having to pass this string around between 4-5 events and listeners that all run in sequence?

Jan
07
6 months ago
Activity icon

Replied to Can These Two Query Builder Queries Be Merged?

Yeah maybe that is the cleanest way true :) Thanks!