andersb

andersb

Member Since 2 Years Ago

Experience Points
7,520
Total
Experience

2,480 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
68
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
7,520 XP
Nov
01
1 month ago
Activity icon

Started a new Conversation Input For Design Pattern For Multiple External APIs Of Similar Usage

I am wondering what would be a good design pattern (I mean design patters in a more loose definition like good practices) for a case where I have multiple external services which all have their own API specifications, but tend to do the same thing.

Example (made up example)

Say that we already have 3 providers, ProviderA, ProviderB and ProviderC which we can communicate with using an API. The services do the same, they for example send a newsletter to a list of relevant people specified on their platform.

When we have a $post then we often wanna sent it using ProviderA but sometime we wanna use one of the others.

We already know, that we will definitely be adding more providers along the way.

Inspiration

I have looked around and found inspiration from the Queue system of Laravel as described by Mohammed Said here as this is also one factory used to communicated with different systems using the same language.

Current solution

So my current solution is this:

Repositories

I have implemented a class \App\Repositories\ProviderARepository for each provider and let these implement the interface \App\Contracts\NewsletterProviderInterface meaning that I know that each of these classes has the functionality I would like to consume.

Service

I have created a class \App\Services\NewsletterProviderService which also implements the interface \App\Contracts\NewsletterProviderInterface. Now, this class has a few extra methods to set the provider to use:


class NewsletterProviderService implements NewsletterProviderInterface
{
    /** @var string */
    protected $provider;

    /** @var \App\Contracts\Repositories\NewsletterProviderInterface */
    protected $providerRepository;

    public function __construct($provider = null)
    {
        if ($provider) {
            $this->setProvider($provider);
        }
    }

    public function setProvider($provider)
    {
        $this->provider = $provider;
        $providerStudly = Str::studly(strtolower($provider)); // strtolower is required to convert 'FOO' to 'Foo'

        $this->{"set{$providerStudly}Repository"}();
    }

    public function setProviderARepository()
    {
        $this->providerRepository = new ProviderARepository();
    }

    ...

Flaw

It's not a major flaw, but say I wanted to add a new Provider, I would then have to add a new method setNewProviderSomethingRepository() to my service (besides adding a new Repository which I would of cause have to do). I could also assume that the repositories would all be placed in the folder App\Repositories, which would then now require adding a new method to the service.

Making a Facade and a ServiceProvider

I have also been thinking about making a Facade and a ServiceProvider in order to enable usage of the form:

 // Using a default provider:
Newsletter::send();
// or alternatively specifying the provider:
Newsletter::provider('B')->send();
// Compared to the normal way:
(new NewsletterProviderService('B'))->send();

Thoughts

The above solution seems to be relatively general and provides good compatibility with my IDE (PhpStorm) which is a huge plus. I am not completely sure what is the best implementation fo the Facade and Service provider - or if this is even needed or simply add complexity to something that can otherwise be relatively easy.

I would appriciate any inputs or thought about this, interested in hearing about how you have done this in your projects.

Oct
14
1 month ago
Activity icon

Replied to Queued Jobs Handled In Correct Order

@sti3bas I finally got it working. The problem was not in your proposed solution which works like a charm! The problem was somehow linked to my non-failing job $nonFailingItemJob which did not implement the failed() method but instead extended another regular job which of cause had this method implemented.

My final solution was to dispatch the job handling like so:

// $nonFailingItemJobs is a collection of App\Jobs\NonFailingItemJob objects
BulkProcessJob::withChain($nonFailingItemJobs->toArray())->dispatch();

Where NonFailingItemJob implements a try/catch (so that it never fails) which dispatches the main job ItemJob (which can fail):

<?php

namespace App\Jobs;

use App\Jobs\ItemJob;

class NonFailingItemJob
{

    /**
     * Execute the job.
     *
     * @override
     * @return void
     */
    public function handle()
    {
        // We need a try catch for the job chain to proceed with the next job even if this one fails.

        try {
            ItemJob::dispatchNow();
        } catch (\Exception $exception) {
           // Intentionally empty. Doing nothing simply continues processing next item.
        }
    }

    /**
     * The job failed to process.
     *
     * @param  \Exception  $exception
     * @return void
     */
    public function failed(\Exception $exception)
    {
        // Intentionally empty. This job will never fail do to the try/catch in the handle() method.
    }
}

Thanks so much for the proposed solution, it was really helpfull.

Sep
27
2 months ago
Activity icon

Replied to Queued Jobs Handled In Correct Order

Yes, both were done. The queue is handled by Horizon and the error is triggered at /vendor/laravel/framework/src/Illuminate/Queue/[email protected] at line 148:

public function failed(array $data, $e)
{
    $command = unserialize($data['command']);
    if (method_exists($command, 'failed')) {// This is failing
        $command->failed($e);
    }
}

I should mention that App\Jobs\ItemJob is queueable as well. But that should not be a problem as I see it?

Activity icon

Replied to Queued Jobs Handled In Correct Order

@sti3bas I have tried your proposed solution and created a completely empty job BulkProcessJob like so:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class BulkProcessJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        // This job intentionally does nothing. It is simply a job used for chaining item processing in correct order
        // See: https://laracasts.com/discuss/channels/laravel/queued-jobs-handled-in-correct-order?page=1#reply=538416
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

and then I fire the job handling like so:

BulkProcessJob::withChain($itemJobs->toArray()) // $itemJobs is a collection of App\Jobs\ItemJob objects
    ->dispatch()
    ->delay(now()->addMinutes(1));

The problem is that I am getting an error about an incomplete object:

Sentry\Exception\FatalErrorException: Error: is_callable(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "App\Jobs\BulkProcessJob" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
  File "/vendor/sentry/sentry/src/Serializer/AbstractSerializer.php", line 104
    if (\is_callable($value)) {

Do you know what is causing this?

Sep
18
2 months ago
Activity icon

Replied to Queued Jobs Handled In Correct Order

@sti3bas

why it should be processed in order if it can fail? I doesn't make sense to me.

Imagine for example you have a $book with a collection of $pages that need to be processed. For some reason then it's important that each page is processed in the correct order, but the hole processing should not fail just because a single page cannot be processed.

But it would make sense as you write to simply put a try {} catch {} in ProcessItemJob which means that it will never fail. Then once should be sure that all items are being processed even though one fails.

Sep
17
2 months ago
Activity icon

Replied to Queued Jobs Handled In Correct Order

That is definitely part of the solution - thanks. So making a collection of ProcessItemJob's which are being handled by the main BulkProcessItemsJob jobs like so:

$itemJobs = $collection->map(function($item) {
        return new ProcessItemJob($item);
    });
BulkProcessItemsJob::withChain($itemJobs)->onQueue('processing')->dispatch();

Now the only problem is that if one of the ProcessItemJob's fail, then the remaining items will not be processed:

If one job in the sequence fails, the rest of the jobs will not be run

@sti3bas is there a way to circumvent this?

Activity icon

Started a new Conversation Queued Jobs Handled In Correct Order

I have a collection of items where I need to process each item using a queued job. This can easily be done by something like so:

$collection->each(function ($item, $key) {
    ProcessItem::dispatch($item)->onQueue('processing');
});

Challenge

Now the challenge is, that I would like to make sure that the order in which the items are handled is correct, so that the first item is handled before the next one and so on.

If a job fails, then it should still continue to process the next item.

Perfect scenario

It would be ideal if two collections could be processed simultaneously, but the order for each collection was correct. Imagine if user A posts a $collectionA and user B posts another collection $collectionB. Then the system could handle the items like so:

  • $collectionA[0]
  • $collectionA[1]
  • $collectionA[2]
  • $collectionB[0] //Now the two request are both being handled
  • $collectionA[3]
  • $collectionB[1]
  • $collectionA[4]
  • ....
Activity icon

Replied to Conditional Filtering On Related Model

It appears this can only be done using either subquery or a join between the two tables.

Jul
23
4 months ago
Activity icon

Started a new Conversation Saving API Usage For Metered Billing

Do anyone use a good package for saving API usage in Laravel?

We would like to save the API usage for our users and potentially implement a metered billing at some point and are looking for a good solution for saving this.

Imagine for example that we have four endpoints

POST /api/posts
PUT  /api/posts
GET  /api/posts
GET  /api/post/{post}

Then we would like to save when a user requests a post, when they create a post, edit a post and so on.

We could build something for this ourself, but if there is already a package out there that we don't know about then it would be stupid to do so.

Jun
21
5 months ago
Activity icon

Replied to Conditional Filtering On Related Model

@MTHOMAS - The problem with your solution is that it looks from a given date. I am asking about a relative condition.

So the problem is that I want all comments that are posted after a month of the date which the associated post was created.

Can you see the difference? Each post was published on different days, so the condition would be something like “JOIN ... WHERE posts.created_at < DATE_ADD(comments.created_at, INTERVAL 1 MONTH)”

Jun
20
5 months ago
Activity icon

Replied to Conditional Filtering On Related Model

@MTHOMAS - @mthomas This is how you would do it for a given post. So if you would like to find all old comments for post with id=123. But imagine now that you would like to find comments for all posts that fulfill the same criteria.

Activity icon

Replied to Conditional Filtering On Related Model

@RAS1212 - I am aware of the documentation :) Unfortunately, it only includes details about how to query the relationship for a single post. I am trying to dynamically set the "field" of the post so to say.

This could be done in SQL using a JOIN on posts and comments or a subquery for each post, but I am not sure how to do it in Eloquent.

Activity icon

Started a new Conversation Conditional Filtering On Related Model

I have two models A and B with a 1:n relationship and would like to find all B records where the associated A record meets a condition on B.

Example:

Get all comments that were created after a month of the original post being created.

It's possible for a single post to get all the comments meeting the condition using something like:

$post->comments()->whereDate('created_at', '>', $post->created_at->addMonth());

But how do you get all comments (for all posts) that were created after a month of the post being created?

Secondly, how do you get all posts that has a least one comment created after a month of the post being created?

Thanks so much.