bwrigley

bwrigley

Member Since 2 Years Ago

Experience Points
6,640
Total
Experience

3,360 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
11
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,640 XP
Dec
27
3 weeks ago
Activity icon

Replied to Best Practice For Passing Parameter To Create Method

Yeah I agree that might be the only way. I just thought this might be a common issue and wondered if there was a way to do it with resource controllers rather than have to create an explicit route.

Thanks for your thoughts!

Activity icon

Replied to Best Practice For Passing Parameter To Create Method

@mushood

But how would you pass the id to your view in the create method if you are using a resource controller?

Activity icon

Replied to Best Practice For Passing Parameter To Create Method

@shez1983

Yes that makes sense, but how to do this with a resource controller which will only accept a GET to create method and which doesn't accept any parameters?

And yes, I agree that user -> profile is usually a 1 - 1 relationship. For this app I have a need to allow multiple profiles.

Activity icon

Replied to Undefined Function: 7 ERROR: Operator Does Not Exist: Character Varying = Integer

@kevin73

any reason you are casting code to string?

what does your migration file for the individu table look like?

Activity icon

Started a new Conversation Best Practice For Passing Parameter To Create Method

Hi everyone,

I'm sure there is a simple answer to this but I'm not finding it anywhere.

So I have a User with a 1-to-many relationship to a Profile with a 1-to-many relationship to Telephone

I am trying to use Resource Controllers wherever possible as I like the convention.

Route::resource('telephone', 'Profile\TelephoneController')->only(['create', 'store', 'edit', 'update', 'destroy']);

my question is that I need to pass the id of Profile into the create and store method so I can attach the new Telephone to the correct Profile when I create it.

What is the best practice here please?

Thanks in advance!

Dec
18
1 month ago
Activity icon

Replied to Running Tests In Homestead Painfully Slow

@talinon

Yes I have some unit tests for testing rules and they don't include my trait above. They take 1.95 seconds to run 4 tests.

When I include my trait above - where the seeding happens - this jumps to 2.85, so not a massive increase actually.

If I leave that trait included but comment out the seeding line and the RefreshDatabase it's back to 1.95 again.

The tests that are the slowest are the HTTP tests (not dusk I hasten to add).

The seeding that I am doing is a basic set of static data used by other models. So as this data doesn't get modified it seems pointless deleting and restoring for each test.

Activity icon

Replied to Running Tests In Homestead Painfully Slow

@tray2

Thanks, but I've already increased to 16096 and 4 cpus, so I'm hoping it's not that

Activity icon

Replied to Running Tests In Homestead Painfully Slow

@goldtaste Thank you, yes I'm aware of the filter, but I like to run y whole suite regularly as part of development process.

Activity icon

Started a new Conversation Running Tests In Homestead Painfully Slow

Hello all,

I'm clearly doing something wrong here that makes my tests run so slowly but I can't get my head around it unless it is the database refresh between tests. My tests are taking between 3 and 5 seconds each to run which is simply unmanageable.

I have a trait that holds some helper methods for my tests and this trait is included in every test suite.

trait TestController
{

    use RefreshDatabase;

    protected function setup(): void
    {
        parent::setup();

        $this->artisan('db:seed', ['--class' => 'TestSuiteSeeder']);

        ///
    }

    ///other helper methods
}

from phpunit.xml

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_CONNECTION" value="sqlite"/>
        <env name="DB_DATABASE" value=":memory:"/>
    </php>

I would be happy to find a solution that only required a single migrate:fresh and db:seed at the beginning of all tests but I'm not having any luck getting that working at the moment.

Any ideas gratefully received.

Dec
08
1 month ago
Activity icon

Replied to Mocking Cashier Methods

@bugsysha thank you. I'd be interested to know more please.

There really isn't any logic in that method that warrants testing, as it's not mine. But I would like to a test to make sure that the route is available and is returning a view and a 200.

Is it that this feel more like a unit test? I guess as it's a controller method, I thought this was really the only to way to test it.

Activity icon

Replied to Mocking Cashier Methods

@bugsysha thanks again for the reply.

Yes it's a really simple test just to make sure the route is working.

I've gone for creating a mock class that extends User like you suggested, thank you.

For anyone who follows this same advice remember to override the $table name to ensure the relationships work:

class MockUser extends User
{

    /**
     * @var string $table
     */
    protected $table = 'users';

    ///

}

Thanks again!

Dec
06
1 month ago
Activity icon

Replied to Mocking Cashier Methods

@bugsysha thanks for your reply.

Actually for the purposes of this test I'm not interested in what Stripe returns, only that the method returns a correct view. I'd prefer it if the test didn't hit the Stripe API at all. So mocking seems the best solution.

However if I add mocking to the test...

        $this->mock(User::class, function ($mock) {
            $mock->shouldReceive('invoices')->andReturn(null)->once();
        })->makePartial();

        $this->get(route('invoice.index'))
            ->assertStatus(200)
            ->assertViewIs('invoice.index');

... it still hits the API.

I think this is the correct syntax though?

Dec
05
1 month ago
Activity icon

Started a new Conversation Mocking Cashier Methods

Hello,

I'm sure I'm missing something obvious here. I'm using Cashier and Stripe for billing and I have a simple method for showing invoices retrieved from Stripe.

I want to write a really simple test to ensure my method is working correctly, Obviously, I'm not trying to test Cashier as that's not mine.

So my test is simply:

    public function test_index_method(): void
    {
        $this->get(route('invoice.index'))
                ->assertStatus(200)
                ->assertViewIs('invoice.index');
    }

and my method is

    public function index(User $user): View
    {
        $invoices = $user->invoices();

        return view('invoices.index', compact('invoices'));
    }

The trouble is that invoices() is on the Billable trait and so it cannot be mocked.

I'd be interested if anyone has a good solution to this? Thanks

Dec
02
1 month ago
Activity icon

Awarded Best Reply on 'Risky' Test

I have just discovered what creates the output:

Test code or tested code did not (only) close its own output buffers

I had a controller method displaying a view and in the view I had forgotten to close my section with @endsection

Activity icon

Replied to 'Risky' Test

I have just discovered what creates the output:

Test code or tested code did not (only) close its own output buffers

I had a controller method displaying a view and in the view I had forgotten to close my section with @endsection

Nov
15
2 months ago
Activity icon

Replied to Strange Relationship Behaviour

@christophharms

Oh yes I can see it's absolutely a feature, I meant an issue in my case.

Yes definitely not happening against MySql DB for some reason.

Thank you for your suggestion. Actually I realise I should just be doing this:

   public function withProfile(): self
    {

        if ($this->user->profile()->exists()) {
         // do something here
        }

        $this->user->profile()->save(factory(Profile::class)->create());

        dd($this->user->profile);

        return $this;
    }

This doesn't cause it to create the Profile.

Thanks again!

Activity icon

Replied to Strange Relationship Behaviour

@christophharms ah that's brilliant thanks. So it's essentially a caching issue? It's only started happening when I run my testsuite in sqllite in memory, so that makes sense.

Incidentally, how would you write this, differently (without using fresh()) to avoid the issue? This is a truer version of what I'm actually hitting.

   public function withProfile(): self
    {

        if ($this->user->profile) {
         // do something here
        }

        $this->user->profile()->save(factory(Profile::class)->create());

        dd($this->user->profile);

        return $this;
    }
Activity icon

Started a new Conversation Strange Relationship Behaviour

Hi There,

I'm having a strange issue when running my test suite.

In brief, I have a User model and a Profile model in a one-to-one relationship with Profile belonging to User.

The code below is a helper method I have in a test suite for creating a Profile and attaching to a User.

So after simplifying my code to illustrate the issue:

    public function withProfile(): self
    {

        $this->user->profile()->save(factory(Profile::class)->create());

        dd($this->user->profile);

        return $this;
    }

This dumps out a full Profile model.

    public function withProfile(): self
    {

        $this->user->profile; // added here to illustrate issue only

        $this->user->profile()->save(factory(Profile::class)->create());

        dd($this->user->profile);

        return $this;
    }

This dumps null

I'm confused why this would happen? Any help would be great, thanks!

Nov
13
2 months ago
Activity icon

Replied to Seeder Factory->each() Updates All Records Not Just New Ones

@tykus

Thank you! Of course, that makes perfect sense. I should have seen that. Thanks again!

Nov
11
2 months ago
Activity icon

Started a new Conversation Seeder Factory->each() Updates All Records Not Just New Ones

Hi There,

I think I have misunderstood something basic here.

I have two database seeders. One to set up 10 random normal users and another to create two specific admin users.

The first one runs fine as expected.

The second one runs but updates all the first ones to make them admins.

 class AdminUsersSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
      collect([
        [
            'first_name' => 'Jim',
            'last_name' => 'Sanders',
            'email' => '[email protected]',
            'notification_frequency' => 'instant',
            'notification_method' => 'none',
            'stripe_id' => NULL,
            'card_brand' => NULL,
            'card_last_four' => NULL,
        ],
        [
            'first_name' => 'Michael',
            'last_name' => 'Johnson',
            'email' => '[email protected]',
            'notification_frequency' => 'instant',
            'notification_mobile' => NULL,
            'stripe_id' => NULL,
            'card_brand' => NULL,
            'card_last_four' => NULL,
        ],
      ])->each(function (array $userDetails) : void {

        factory(User::class)
            ->create($userDetails)
            ->each(function($user) {
                dump($user->id);
                $user->isAdmin(true);
        });
      });

    }

The dump line dumps out the id of every user in the database, twice! I assumed that factory()->create()->each() would only iterate through the models created by the factory?

I'm sure I'm missing something obvious. Any help is much appreciated!

Oct
10
3 months ago
Activity icon

Replied to Correct Way To Assert That Mock Expectations Have Passed.

@sti3bas It wasn't hitting for some reason.

I wondered if it's the fact I'm running in the Homestead environment, so I have halted, reprovisioned, and restarted and it's working now!

Thank you for helping me get there

Oct
08
3 months ago
Activity icon

Replied to Correct Way To Assert That Mock Expectations Have Passed.

@sti3bas wow that's strange. No, no modifications. Thank you so much for testing though.

Oct
07
3 months ago
Activity icon

Replied to Correct Way To Assert That Mock Expectations Have Passed.

@sti3bas we are still on 5.8.31, but I would have expected it to still work

<?php

namespace Tests\Feature\Reports;

use AnalyticsMetric;
use App\Analytics\Contracts\AnalyticsClient;
use App\Analytics\Reports\PageViewReport;
use App\Analytics\Services\TestAnalyticsClient;
use Mockery;
use Tests\TestCase;

class PageViewReportTest extends TestCase
{
    /**
     * @test
     * @group report
     */
    public function test_page_view_report(): void
    {
        $analyticsClient = Mockery::spy(TestAnalyticsClient::class)->makePartial();
        $this->app->instance(AnalyticsClient::class, $analyticsClient);

        $report = new PageViewReport;
        $report->generate();

        $analyticsClient->shouldHaveReceived('withMetrics')->with([AnalyticsMetric::PAGE_VIEWS])->once();

    }

}

PHPUnit 7.5.2 by Sebastian Bergmann and contributors.

R                                                                   1 / 1 (100%)

Time: 1.71 seconds, Memory: 24.00MB

There was 1 risky test:

1) Tests\Feature\Reports\PageViewReportTest::test_page_view_report
This test did not perform any assertions

/home/vagrant/Code/everyone-in-mind/tests/Feature/Reports/PageViewReportTest.php:22

OK, but incomplete, skipped, or risky tests!
Tests: 1, Assertions: 0, Risky: 1.
Activity icon

Started a new Conversation Correct Way To Assert That Mock Expectations Have Passed.

When writing tests and using Mockery to spy on classes, is there a correct way to assert that an expectation has passed?

I have this solution at the moment which is obviously wrong, but is there a right way?

    public function test_page_view_report(): void
    {
        $analyticsClient = Mockery::spy(TestAnalyticsClient::class)->makePartial();
        $this->app->instance(AnalyticsClient::class, $analyticsClient);

        $report = new PageViewReport;
        $report->generate();

        try{
            $analyticsClient->shouldHaveReceived('withMetrics')->with([AnalyticsMetric::PAGE_VIEWS])->once();
            $this->assertTrue(true);
        } catch (Exception $e) {
            $this->assertTrue(false);
        }
    }
Oct
04
3 months ago
Activity icon

Replied to Mock Partial BadMethodCallException

@sti3bas yes I tried with ->andReturnSelf(), but actually yours works! Not sure what the difference is there, but I thought they would do the same.

Thank you!

Activity icon

Replied to Mock Partial BadMethodCallException

@sti3bas good thought, but I just tried that and sadly still the same error.

Interesting I get it for setFromDate and not setCacheTtl which happens first.

So I tried swapping the method calls round:

    public function generate(): ?Collection
    {
        $metrics = [AnalyticsMetric::PAGE_VIEWS];

        $this->result = $this->analyticsClient
            ->setFromDate($this->fromDate)
            ->setCacheTtl(60)
            ->setToDate($this->toDate)
            ->withMetrics($metrics)
            ->run();

and now the error is

BadMethodCallException: Received Mockery_1_App_Analytics_Contracts_AnalyticsClient::setCacheTtl(), but no expectations were specified

I'm clearly missing something here!

Activity icon

Replied to Mock Partial BadMethodCallException

@sti3bas Yeah ok thank you, the fake object makes sense. I'll look at that route.

And I just want to play with mocking out the interface, but I still seem to run into trouble.

So I've changed my test to this now:

        $analyticsClient = Mockery::mock(GoogleAnalyticsClient::class)->makePartial();
        $this->app->instance(AnalyticsClient::class, $analyticsClient);

        $analyticsClient->shouldReceive('setCacheTtl')->once();
        $analyticsClient->shouldReceive('setFromDate')->once();
        $analyticsClient->shouldReceive('setToDate')->once();
        $analyticsClient->shouldReceive('withMetrics')
                        ->with([AnalyticsMetric::PAGE_VIEWS])
                        ->once();
        $analyticsClient->shouldReceive('run')->once();

        $report = new PageViewReport;

        $report->generate();

And getting this error

BadMethodCallException: Received Mockery_1_App_Analytics_Contracts_AnalyticsClient::setFromDate(), but no expectations were specified

which is confusing me as I'm not sure what I'm missing still

Oct
02
3 months ago
Activity icon

Replied to Mock Partial BadMethodCallException

@sti3bas thanks for coming back to me.

Ah, I didn't realise that you can't mock the interface, or rather, I presumed that the binding would mean the bound class would be mocked in place of the interface.

I like the idea of a test implemention, but would you then mock this so that I can get the responses I require for testing?

Oct
01
3 months ago
Activity icon

Started a new Conversation Mock Partial BadMethodCallException

Hello,

I'm sure I'm missing something obvious here but I'm a bit confused about how mocking works.

My Architecture is such that I have an Interface class AnalyticsClient currently bound to GoogleAnalyticsClient in my ReportServiceProvider

        $this->app->bind(
            'App\Analytics\Contracts\AnalyticsClient',
            'App\Analytics\Services\GoogleAnalyticsClient'
        );

I also have an abstract class called AnalyticsReport that all my reporting classes extend. The constructor in the AnalyticsReport is where I resolve the AnalyticsClient

     public function __construct()
    {
        $this->analyticsClient = resolve('App\Analytics\Contracts\AnalyticsClient');
    }

This is all working fine and now I want to test it, but I want to mock out the relevant method in my AnalyticsClient as I don't want to actually make calls to the Google API.

My test looks like this so far:

        $mock = Mockery::mock(AnalyticsClient::class)->makePartial();
        $this->app->instance(AnalyticsClient::class, $mock);
        $mock->shouldReceive('run')->andReturn(collect(collect(['RESULT' => 6])));

        $report = new PageViewReport;

        $report->generate();

and the generate() method in AnalyticsClient (inherited by PageViewReport):

    public function generate(): ?Collection
    {
        $this->setup();

        $this->result = $this->analyticsClient
            ->setCacheTtl($this->cacheTtl)
            ->setToDate($this->toDate)
            ->setFromDate($this->fromDate)
            ->withMetrics($this->metrics)
            ->withDimensions($this->dimensions)
            ->withFilters($this->filters)
            ->run();

        return $this->result;
    }

The error I'm getting is

Mockery\Exception\BadMethodCallException: Received Mockery_0_App_Analytics_Contracts_AnalyticsClient::setCacheTtl(), but no expectations were specified

But I thought that when you create a mock partial, only the named methods are mocked and the unnamed methods run as usual. Am I missing something?

Thank you in advance!

Sep
30
3 months ago
Activity icon

Replied to Binding Interface To Service Container Not Resolving In Constructor

@sti3bas sorry for slow reply. That's perfect thanks and the video really helped.

Sep
11
4 months ago
Activity icon

Replied to Binding Interface To Service Container Not Resolving In Constructor

@sti3bas yeah, I think that's the bit I'm misunderstanding.

So I thought by binding the Interface in the way I have...

        $this->app->bind(
            '/App/Contracts/AnalyticsClient',
            '/App/Services//GoogleAnalyticsClient'
        );

...that was enough for automatic injection. But perhaps there is more I need to add to the container than this to resolve the class?

Activity icon

Replied to Binding Interface To Service Container Not Resolving In Constructor

@sti3bas Sorry, I'm not explaining myself well.

I'm sure there is a way that once a class is bound in the container, I can just type-hint it in the arguments of the constructor of any class and it would bring it into existence. Similar to Route Model Binding.

Sep
10
4 months ago
Activity icon

Replied to Binding Interface To Service Container Not Resolving In Constructor

@sti3bas Thanks again

In that case I have misunderstood the docs here

https://laravel.com/docs/5.8/container#binding-interfaces-to-implementations

Do I need to add something else to the container that this doesn't specify? Sorry for the dumb questions

Activity icon

Replied to Binding Interface To Service Container Not Resolving In Constructor

@sti3bas thanks again for your reply.

in tinker I am simply typing $report = new \App\Reports\ProfileViewReport;

If I understand correctly I the constructor should create AnalyticsClient implicitly so I do not need to pass one as an argument?

Activity icon

Replied to Binding Interface To Service Container Not Resolving In Constructor

Thank you for your reply, and apologies, that was just a typo when writing up my question.

In my application they are correct.

Activity icon

Started a new Conversation Binding Interface To Service Container Not Resolving In Constructor

Hello. I'm sure I'm doing something dumb here and not understanding the docs properly.

I'm trying to write some classes to manage reporting over the Google Analytics API, but want to make sure I can swap it out later if needs be.

So I have my interface:

namespace App\Contracts;


interface AnalyticsClient
{

    public function run();
    public function buildQuery();
    // etc
}

And I have a Google Analytics class which implements this:

namespace App\Services;

use App\Contracts\AnalyticsClient;

class GoogleAnalyticsClient implements AnalyticsClient
{

    public function run()
    {
        //
    }

    public function buildQuery()
    {
        //
    }
}

And a service provider:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class ReportServiceProvider extends ServiceProvider
{

    public function register()
    {
        $this->app->bind(
            '/App/Contracts/AnalyticsClient',
            '/App/Services//GoogleAnalyticsClient'
        );
    }
}

...which is registered in app.php

'providers' => [
    
    //,

    App\Providers\ReportServiceProvider::class,

So my expectation is now that I can just call am analytics client into existence in my report classes:

namespace App\Reports;

use App\Contracts\AnalyticsClient;

class ProfileViewReport
{

    private $analyticsClient;

    public function __construct(AnalyticsClient $analyticsClient)
    {
        $this->analyticsClient = $analyticsClient;
    }

But sadly, when I run this in tinker:

TypeError: Too few arguments to function App/Reports/ProfileViewReport::__construct(), 0 passed in

I suspect I need to do something else to enable the Analytics client to be created implicitly?

Thank you in advance for helping with this.

Aug
13
5 months ago
Activity icon

Replied to Adding Items To An Array In A Collection

This works well, but actually I think that a Collection of Collections is probably more elegant. Is it bad form to mark my own solution as 'Best Answer' 😫

Aug
12
5 months ago
Activity icon

Replied to Adding Items To An Array In A Collection

Sorry our messages overlapped:

So I tried what you suggested in tinker:

$coll->put(
     'metrics', 
     array_push($coll->get('metrics'), 'something')
);

PHP Notice: Only variables should be passed by reference in /home/vagrant/Code/everyone-in-mindeval()'d code on line 1

Activity icon

Replied to Adding Items To An Array In A Collection

Some trial and error suggests that maybe I shouldn't be adding metrics as an array?

$coll = new Collection([
    'metrics' => collect(),
    'dimensions' => collect(),
]);

then I can push with:

$coll->get('metrics')->push('a new thing');

Would be grateful to know if this really is best practice?

Activity icon

Started a new Conversation Adding Items To An Array In A Collection

I'm sure I'm missing something obvious here but I can't seem to find the answer in the docs anywhere.

If I create a new collection like :

$coll = new Collection([
    'metrics' => [],
    'dimensions' => [],
]);

how do I push new values into the metrics array?