longestdrive

longestdrive

Member Since 5 Years Ago

Experience Points 7,425
Experience Level 2

2,575 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 51
Lessons
Completed
Best Reply Awards 0
Best Reply
Awards
  • Start Your Engines Achievement

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • First Thousand Achievement

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • One Year Member Achievement

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • Two Year Member Achievement

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • Three Year Member Achievement

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • Four Year Member Achievement

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • Five Year Member Achievement

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • School In Session Achievement

    School In Session

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

  • Welcome To The Community Achievement

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • Full Time Learner Achievement

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • Pay It Forward Achievement

    Pay It Forward

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

  • Subscriber Achievement

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • Lifer Achievement

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • Laracasts Evangelist Achievement

    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 Achievement

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • Laracasts Veteran Achievement

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • Ten Thousand Strong Achievement

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • Laracasts Master Achievement

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • Laracasts Tutor Achievement

    Laracasts Tutor

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

  • Laracasts Sensei Achievement

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • Top 50 Achievement

    Top 50

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

18 Feb
1 month ago

longestdrive left a reply on Accessing FormRequest Values During Testing

Hi - That's what I was trying to avoid and focus only on testing the FormRequest not the rest of the controller method that uses the request.

I'll revert back to that if I need to but assumed I could test in isolation - as a unit

longestdrive started a new conversation Accessing FormRequest Values During Testing

Hi I’m trying to test the effectiveness of a rule within a form request.

The rule is:

[
‘date’ => [
    Rule::unique('orders')->where(function ($query)  {
            return $query->where('user_id', $this->user_id)
            ->where('order_id', $this->order_id);
        }),

And I’m trying to test this using this test:

attributes = [ 'date' => '2019-02-16', ‘user_id’ =>1, ‘order_id’=>1 ]; $request = new TestRequest(); $rules = $request->rules(); $validator = Validator::make($attributes, $rules); $fails = $validator->fails(); $this->assertEquals(false, $fails);


The problem I’m having is that the values that would normally appear to be in the `FormRequest` are all null.

I’m trying to avoid using a call to the URL and post a form and test this in isolation.

How should I access the values within the formrequest to make this work?

Thanks
02 Feb
1 month ago

longestdrive left a reply on Laravel Scheduled Jobs Consuming All Server Resources

Hi - yes I think now though that queue:work runs as a daemon by default.

My understanding is that a daemon keeps the process running? If I'm then running this command every 5 minutes am I then running it multiple times in parallel hence the build up of resource use?

longestdrive started a new conversation Laravel Scheduled Jobs Consuming All Server Resources

Hi

I've recently upgraded a site to Laravel 5.5. The site (like others I have) use a cron job on the deployed server to run the scheduled commands. The CRON runs every minute.

One of the commands is to run the queue jobs and I use this command:

$schedule->command('queue:work')->everyFiveMinutes();

I've had no problems up until now. But now it gradually consumes all the server resources to the point where other sites I run on the vps start falling down and affecting mysql connections across all sites.

I regularly get failed mysql connections.

On checking the server process the queue:work consumes alot of resources.

Is there something I'm doing wrong or a better way to run the queue jobs? Pulling my hair out on this

27 Jan
1 month ago

longestdrive started a new conversation Testing Laravel Mail View

Hi

I can now successfully test that a mail is sent using Mail::fake() using a test like this:

       Mail::assertSent(Contact::class, function ($mail) use ($request) {
            $mail->build();

            return $mail->subject == "Website Contact";
        });

But this doesn't appear to extend to testing that the view is rendered correctly.

I know I can view a mailable using Route::get('\mailable)and I can use that to check it renders correctly but I want to be able to do this within myphpunit` test.

For example running the above test on a mail passess as long as I have called Mail::fake() but Iif I then remove that call and rerun the test (and remove the fake assertions` the test fails with errors if I haven't passed the correct data over.

So how I can correctly test the email view is rendered correctly and sent in a test using Mail::fake()?

Thanks

20 Jan
2 months ago

longestdrive left a reply on Testing A Secure Route Laravel 5.5 NotFoundHttpException

Hi

Yes the route is available from the browser but not in testing. The route specifies Https and after a bit of digging the url the test forms specifices Http instead.

In the end the solution was to use the route() helper to create the test url from the route name:

$response = $this->call('GET',route('contact.secure.page'));

This then generates the correct Https url and the page is found

Thanks

19 Jan
2 months ago

longestdrive started a new conversation Testing A Secure Route Laravel 5.5 NotFoundHttpException

Hi

Today's testing question is on secure routes.

Within my routes file I have:

if (App::environment() == 'deployed') {
\URL::forceScheme("https");
}

Route::get('/contact', array(
    'https',
    'as' => 'contact.secure.page',
    'uses' => '[email protected]'
));

This works on the live server. On my testing development machine I don't have any certificates installed so always get an error message about security etc but ignored until now as it didn't affect my development.

Now I'm trying to write a test to ensure the page is visible and here's my test:

    namespace Tests\Feature;
 
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ContactFormTest extends TestCase
{

    use DatabaseMigrations;

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

        $this->disableExceptionHandling();

    }

    public function test_visitor_can_see_contact_form()
    {

        $response = $this->get('/contact');

        $response->assertResponseStatus(200)
            ->assertSee('CONTACT US');
    }


    }

But the test fails because with an httpNotFound exception

In earlier versions of Laravel I could use

$response = $this->callSecure('GET', '/contact');

But this no longer works in Laravel 5.5.

How can I specify the test creates and calls an https url for this test?

Thanks

13 Jan
2 months ago

longestdrive left a reply on Test Mail And Number Of Emails Send

FOund the answer - again in the API! (Will I never learn)

You need to pass a numeric value to the AssertSent callback as a numeric which then calls the protected method AssertSentTimes

longestdrive left a reply on Using Variables In Controllers

When you say "picked" what do you mean? After the sliders are rendered what's the next step? Are you expecting a user to click on the slider and then do something? Not clear what you expect to happen.

longestdrive left a reply on Test Mail And Number Of Emails Send

I've tried to implement the solution but come up with this error:

Error : Call to protected method Illuminate\Support\Testing\Fakes\MailFake::assertSentTimes() from context 'Illuminate\Support\Facades\Facade'

How can I call this method correctly?

I'm importing the class using:

use Illuminate\Support\Facades\Mail;

longestdrive left a reply on Test Mail And Number Of Emails Send

@JONASSIEWERTSEN - That's great. Thank you.

Will give the api a good read, I often forget about that resource as it rarely comes up in the searches I do.

Thanks again

?

12 Jan
2 months ago

longestdrive started a new conversation Test Mail And Number Of Emails Send

Hi

My Laravel 5.5 testing journey continues

How do I test how many emails were sent by my test.

I'm trying to test that multiple emails were sent in a test. The method I'm testing against is only sending to the first recipient so I need to find a way of building a test

My current test is this:

    public function testUserCanSendBroadcastMessageToMultiplePlayers()
    {
    $this->disableExceptionHandling();

    Mail::fake();

    factory(Player::class, 4)->create();

    $players = Player::get()->pluck('id')->toArray();

    $request = [
        'recipients'=>$players,
        'subject'=>"test subject",
        'message'=>'test message'
    ];

    $response = $this->actingAs($this->user)
        ->call('POST', 'broadcast/create', $request);

    $subject = "test subject";
    $message = "test message";

    Mail::assertSent(NewBroadcastMessage::class, function ($mail) use ($subject, $message) {
        $mail->build();
        return $mail->subject === $subject;
    });
    
    }

I don't know where I should count() the emails sent. H

How do I build my test correctly?

longestdrive left a reply on Testing Laravel Mailables And Passing Data

Thank you - I've changed the approach now and trigger the email send via a controller method and can now get the test to fire and produce results.

I'm still developing my testing abilities - learning all the time

Thanks

11 Jan
2 months ago

longestdrive started a new conversation Testing Laravel Mailables And Passing Data

I'm trying to test email for a Laravel 5.5 app - that uses Mailables. I'm not sure how I go about testing when the Mailable receives data as the examples I've seen don't seem to include data.

Here is the test I'm developing:

    public function testBroadcastMailable()
    {
    $this->disableExceptionHandling();

    Mail::fake();

    $subject = "test subject";
    $message = "test message";

    Mail::assertSent(NewBroadcastMessage::class, function ($mail) use ($subject, $message) {
        $mail->build();
        return $mail->subject === $subject;
    });
    }

The assertion currently fails.

This is the Mailable class:

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class NewBroadcastMessage extends Mailable
{
use Queueable, SerializesModels;
public $message;
public $subject;

/**
 * Create a new message instance.
 *
 * @param $subject
 * @param $message
 */
public function __construct($subject, $message)
{
    //
    $this->message = $message;
    $this->subject = $subject;
}

/**
 * Build the message.
 *
 * @return $this
 */
public function build()
{
    return $this->markdown('messages.newBroadcastMessage')
        ->subject($this->subject);
}
}

What is the correct way to pass data in a test and test mailables?

01 Jan
2 months ago

longestdrive started a new conversation Testing Laravel HTTPNOTFOUND Exception On Second Pass

Hi I'm trying to set up some simple tests for an app to check a user can view specific pages etc.

Most of the tests I can set up ok but one set of tests is coming up with strange behaviour - If I run each test individually it passes and the expected page is viewed but if I run them in sequence the second test fails giving an HttpNotFound exception.

Here's the tests:

public function testUserCanSeeLeagueIndex()
{
    $this->disableExceptionHandling();

    $response = $this->actingAs($this->user)
        ->get('leagues');

    $response->assertStatus(200)
        ->assertSee('Leagues');

}

public function testUserCanSeeEclecticLeagueIndex()
{
    $this->disableExceptionHandling();

    $response = $this->actingAs($this->user)
        ->get('leagues');

    $response->assertStatus(200)
        ->assertSee('Eclectic Leagues');

}

The second test fails but if I run it on it's own it passes as expected

For now I've deliberately set the URL the same just to get past this test.

I've checked the routes for any declared twice.

What do I need to do to overcome this problem?

17 Dec
3 months ago

longestdrive left a reply on Inserting Line Breaks Into Mysql Txt

Hi @realrandyallen - thank you - been going round in circles on this one!

It works now - the mistake I made when I experimented with \nwas to use single quotes not double - persevered after your comment and tried again with double quotes - phew

Thanks for the great steer

longestdrive started a new conversation Inserting Line Breaks Into Mysql Txt

Hi

I have a form with a text area. When a user adds notes they can add new lines as expected whilst they edit.

I want to be able to add new lines to this text in my code but whilst I can add the new text I can't create new lines.

The code to add new text is:

$notes .= date('d/m/Y h:i') . ": Booking created by " . $this->user->present()->fullName() . "<br/ >";

I have also tried \n instead of <br /> but it makes no difference

When I try and display it back in a form text area all I see is the charactersL (<br /> or \n) and no new lines

I have tried:

<textarea>{!! $reservation->notes !!}<textarea/>

<textarea>{!! e($reservation->notes) !!}<textarea/>
{!! nl2br(e($reservation->notes)) !!}

and same combinations for {{ }}

How can I add text to existing text on a new line so it appears correctly as a new line in the textarea?

27 Mar
11 months ago

longestdrive left a reply on Cross Browser Errors With HTTP And HTTPS For Same Domain Name

Hi - thank you. That has done the trick with all working as expected through the https.

Brilliant!

longestdrive started a new conversation Cross Browser Errors With HTTP And HTTPS For Same Domain Name

Hi

I'm a bit confused about an error that appears to be popping up and I'm not sure of the nest way to resolve

I have a SSL certificate on the main site

When a user visits a particular page a feed for a calendar is request via ajax get method.

my routes do not specify the route as secure and generally just use the Route::get or Route::post methods.

In my routes file I have added:

if (App::environment() == 'deployed') {
 \URL::forceScheme("https");
}

Route::get('eventslist', array('uses' => '[email protected]', 'as'=>'calendar.feed'));

I can't get the url of the call to the feed to work properly and align itself with the parent page. ie the parent at the moment can be called as either https or http - I can't seem to force always as https.

so at anyone time the parent page may be called as https whilst the feed gets called as http so it gets blocked

I've researched CORS but don't fully understand the solution and if I install the CORS package does that make my site less secure with no CSFR?

Thanks

23 Mar
11 months ago

longestdrive left a reply on Laravel Dusk - Fails Test But How Can I See What Test Sees?

Resolved - I hadn't appreciated the assertSee is case sensitive. All working now - thank you - on to my next problem!!!

longestdrive left a reply on Laravel Dusk - Fails Test But How Can I See What Test Sees?

Hi @m-rk thanks for the link and suggestion

I've looked in the folder and can see a screenshot that shows exactly what I would expect to see and the expected text - so I would expect the test to pass :(

longestdrive started a new conversation Laravel Dusk - Fails Test But How Can I See What Test Sees?

Hi I'm getting started with Laravel Dusk (v2) with a Laravel 5.5 app

I'm starting small and want to test that a user can log in so have created this test:

public function test_user_can_browse_to_login_page_and_log_in()
    {
//        $this->logout();

        $this->browse(function (Browser $browser) {
            $browser->visit('/')
                ->assertSee('You have arrived')
                ->click('@dashboard-link')
                ->assertSee('login')
                ->type('email', '[email protected]')
                ->type('password', 'password')
                ->click('@login-button') 
                ->assertPathIs('/dashboard')
                ->assertSee('seven days');

        });
    }

It all works fine until the last assertion - it doesn't see seven days which should be on the dashboard page.

So, to debug how can I see what the test is seeing? Is there a method to view the results?

Also, I don't see a browser opening (which I understand is correct) - I've followed another post and removed --headless from the DustTestCase.php but that then hangs completely. So I'm unable to watch the tests. (I have replaced the --headless option)

New to this so be kind!!

11 Mar
1 year ago

longestdrive left a reply on Redirect Test Passes When Run On It's Own But Fails When Run After Other Tests

Yay - found the answer!

The error was caused by me organising my routes into seperate files to keep them manageable.

Following the answer on a similar thread I found this solution worked:

rbtmtn 2 years ago (1,475 XP) I was having this same issue. In my service provider I had

require_once('routes.php'); 

I changed it to

require('routes.php');

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

longestdrive started a new conversation Redirect Test Passes When Run On It's Own But Fails When Run After Other Tests

I'm trying to do a simple test to check that a user is redirected if not logged in.

When I run the test on i'ts own it passes but if I run it as part of a series of tests on a feature it fails.

here is my test:

<?php

namespace Tests\Feature\createReservation;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class CreateReservationFormTest extends TestCase
{
    use DatabaseMigrations;

    /**
     * A basic test example.
     *
     * @return void
     */
    public function test_user_can_see_greenfee_form()
    {
        $user = factory(\App\Models\User::class)->create();



        $response = $this->actingAs($user)
            ->get('bookings/create');

        $response->assertStatus(200);
    }

    public function test_not_logged_in_user_is_redirected()
    {

        $response = $this->get('bookings/create');

        $response->assertRedirect('login');
    }
}

My route is protected by the basic auth middleware and works as expected when using the app as normal:

Route::group(array('middleware'=>['auth']), function () {

    Route::resource('bookings', 'Booking\BookingController');

});

When I inspect $response I can see the header has:

<!DOCTYPE html><!--


InvalidArgumentException: Route [bookings.create] not defined. in file /home/vagrant/code/golfmanager18/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php on line 305

What do I test for. TestCase.php has not been changed

I don't know where to start solving this - any ideas?

07 Mar
1 year ago

longestdrive left a reply on Unable To Get Testing To Use A Testing Database Sqlite L5.5

And now resolved!!!

I cleared the config cache - this appeared to work for the database but not changed the environment variable - still at local when I do this:

dump(app('env'));

Switching back to phpstorm I also specified the default configuration file and pointed it to the phpunit.xml in the project root - aghhh

So I think sorted for now

longestdrive left a reply on Unable To Get Testing To Use A Testing Database Sqlite L5.5

And checking the version on command console I get:

PHPUnit 7.0.2 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.1.10-1+ubuntu16.04.1+deb.sury.org+1 with Xdebug 2.6.0
Configuration: /home/vagrant/code/golfmanager18/phpunit.xml

longestdrive left a reply on Unable To Get Testing To Use A Testing Database Sqlite L5.5

And a bit more information:

Looking at the console I have the following:

ssh://[email protected]:2222/usr/bin/php /home/vagrant/code/golfmanager18/vendor/phpunit/phpunit/phpunit --no-configuration 

So I assume that means it's not picking up the configuration file?

How Can configure this correctly to use the configuration file at the root of my project?

longestdrive left a reply on Unable To Get Testing To Use A Testing Database Sqlite L5.5

A bit of further testing:

If I include the following in my test set up I get:

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

        dump(env('APP_ENV'));
        dd(DB::connection()->getDatabaseName());
}

The environment is shown as local and the database name is: manager (which is on my mysql connection

so it appears the values in phpunit.xml are not being used?

longestdrive started a new conversation Unable To Get Testing To Use A Testing Database Sqlite L5.5

I thought I had this set up cracked but I haven't. It seems no matter what I do I'm unable to get my tests to use an sqlite database to use for tests and instead keeps going to my default mysql database.

I think I've done everything as suggested in all the threads and tutorials but absolutely no luck in Laravel 5.5

In my database config I have:

'default' => env('DB_CONNECTION', 'mysql'),


'connections' => [

        'sqlite' => [
            'driver' => 'sqlite',
            'database' => env('DB_DATABASE', database_path('database.sqlite')),
            'prefix' => '',
        ],
        'sqlite_testing_memory' => [
            'driver' => 'sqlite',
            'database' => ':memory:',
            'prefix' => '',
        ],
        'sqlite_testing' => [
            'driver' => 'sqlite',
            'database' => database_path('database.sqlite'),
            'prefix' => '',
        ],

        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],

In my Phpunit.xml I have the following:

<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_testing"/>
        <env name="DB_DEFAULT" value="sqlite_testing" />
        <env name="DB_DATABASE" value="/database/database.sqlite"/>
    </php>

I have a file - database.sqlite in my database directory

I also tried placing that file in the storage folder and changed the path to the storage folder but still didnt work.

So - what's wrong with my set up and how can I check before my tests run which database it's using?

Thanks

03 Mar
1 year ago

longestdrive left a reply on Learning Testing And Mocking Classes

Ok - I think I've managed to successfully get the mock to be used by my class. I changed the test to the following:

public function test_booking_created()
    {

        $attributes = $this->createAttributes();

        $user = \App\Models\User::find(1);

        $mock = \Mockery::mock(Cart::class);

        $mock->shouldReceive('getCartGroupSize')
            ->with('greenfee')
            ->andReturn(1)
            ->shouldReceive('getCartCostsTotal')->with('greenfee')
            ->andReturn(10)
            ->shouldReceive('total')
            ->andReturn(10)
        ->shouldReceive('instance')->with('greenfee');

        $reservationRepository = \App::make(ReservationRepository::class);
        $customerRepository = \App::make(CustomerRepository::class);

        $this->booking = new CreateBooking($reservationRepository, $customerRepository, $mock);


        $booking = $this->booking->handle($attributes, $user, 'greenfee');

        $this->assertEquals(1532, $booking->customer_id);
        $this->assertEquals(1, $booking->user_id);
        $this->assertEquals(10, $booking->group_size);

    }

I initiated the dependencies for my class under test and passed those when initiating the class

My problem now is the mocked class has private methods which I understand will still run.

This one in particular is giving me problems:

private function setSaleTotal()
    {
        $this->saleTotal = $this->cart->instance('greenfee')->total();
    }

It calls on the methods within the parent class to grab the contents of the cart and then total them.

Now, because I've mocked the object there isn't actually any data there so I get an error Error : Call to a member function total() on null

What I thought I was doing was to check the call to total is made ->shouldReceive('total') and then get it to return a value '->andReturn(10)`

So I'm still very confused with mocking to avoid creating a real cart object and integrate that into my test (I've been working on the basis most unit tests should be isolated?)

Any help appreciated on my testing journey

02 Mar
1 year ago

longestdrive started a new conversation Learning Testing And Mocking Classes

I'm starting to learn testing - my laravel 5.5 app and gradually overcoming obstacles.

This is day 4 so a new challenge for me.

I'm trying to test a database record is created - I can do this and the tests work.

However the class that creates the record interacts with another class (a Cart class)- sends it some parameters and gets back a value.

I'm trying to isolate the test to this class so have tried to mock the class but I'm fairly sure I don't know what I'm doing here,

This is my test class:

class CreateBookingTest extends TestCase
{
    private $booking;

    public function setUp()
    {
        parent::setUp();
        $this->booking = \App::make(\App\Golfmanager\Booking\CreateBooking::class);

    }

    public function test_booking_created()
    {
        $attributes = $this->createAttributes();
        $user = \App\Models\User::find(1);
        $mock = \Mockery::mock(Cart::class);
          $mock->shouldReceive(['getCartGroupSize', 'instance'])
              ->with('greenfee')
              ->andReturn(1);

        $booking = $this->booking->handle($attributes, $user, 'greenfee');

        $this->assertEquals(1532, $booking->customer_id);
        $this->assertEquals(1, $booking->user_id);
        $this->assertEquals(1, $booking->group_size);

    }

    private function createAttributes()
    {
        $attributes = [
            'customer_id'=>1532,
            'play_date'=>'01/02/2018',
            'am_tee'=>'10:00 AM',
            'howBooked'=>'Drop In',
            'cartCount'=>1
        ];

        return $attributes;
    }
}

Here's the class I'm testing:

class CreateBooking
{
    /**
     * @var ReservationRepository
     */
    private $reservationRepository;
    /**
     * @var CustomerRepository
     */
    private $customerRepository;
    private $customer;
    private $groupSize = 0;
    private $costs = 0;
    private $saleTotal;
    private $booking;
    /**
     * @var Cart
     */
    private $cart;

    /**
     * CreateBooking constructor.
     * @param ReservationRepository $reservationRepository
     * @param CustomerRepository $customerRepository
     * @param Cart $cart
     */
    public function __construct(
        ReservationRepository $reservationRepository,
        CustomerRepository $customerRepository,
        Cart $cart
    )
    {
        $this->reservationRepository = $reservationRepository;
        $this->customerRepository = $customerRepository;
        $this->cart = $cart;
    }

    public function handle(Array $attributes, $user, $type = 'greefee')
    {

        $this->setUpBooking($attributes)
            ->createBooking($attributes)
            ->attachUser($user)
            ->attachCustomer();

        return $this->booking;
    }

    private function setUpBooking($attributes)
    {
        $this->setCustomer($attributes['customer_id']);
        $this->setGroupSize();
        $this->setCosts();
        $this->setSaleTotal();

        return $this;
    }

    private function setCustomer($customer_id)
    {
        $this->customer = $this->customerRepository->findById($customer_id);
    }

    private function setGroupSize()
    {
        $this->groupSize = $this->cart->getCartGroupSize('greenfee');
    }

//    Review: should this be here?
    private function setCosts()
    {
        $this->costs = $this->cart->getCartCostsTotal('greenfee');
    }

//    review: Should this be here?
    private function setSaleTotal()
    {
        $this->saleTotal = $this->cart->instance('greenfee')->total();
    }

    private function bookingAttributes($attributes)
    {
        $baseAttributes = array_only($attributes, ['play_date', 'am_tee', 'howBooked']);

        return array_merge($baseAttributes, $this->createTypeSpecificAttributes($attributes));
    }

    private function createTypeSpecificAttributes($attributes)
    {
        $typeSpecificAttributes = [
            'booked_date' => $attributes['play_date'],
            'group_size' => $this->groupSize,
            'sale_total' => $this->saleTotal,
            'costs_total' => $this->costs,
            'notes' => "Direct sale from `green fee\n",
            'status' => 'invoiced',
            'directSale' => 1,
            'event_type' => 'Golf',

        ];

        return $typeSpecificAttributes;
    }

    private function createBooking($attributes)
    {
        $this->booking = $this->reservationRepository->create($this->bookingAttributes($attributes));

        return $this;
    }

    private function attachCustomer()
    {
        $this->customer->reservation()->save($this->booking);

        return $this;

    }

    private function attachUser($user)
    {
        $user->reservation()->save($this->booking);

        return $this;
    }


}

I wanted to assert that first the class is called within the class I'm testing - makes use of the instance method and the getCartGroupSize method and returns a value

When running the test I can see 5 assertions but get one failure - because the value being returned by the mocked class doesn't appear to be used in the class I'm testing

Very confused how to correctly implement

I've tried moving the initiation of the class I'm testing after I've created the Mock but no change

ANy help appreciated

01 Mar
1 year ago

longestdrive left a reply on Learning Testing - Using Classes With Dependency Injection

Thanks @ohffs - yes that did the trick! (now kicking myself!)

longestdrive started a new conversation Learning Testing - Using Classes With Dependency Injection

Hi - my ongoing battle to learn testing in Laravel 5.5 continues.

I've created a class that extends a package to add functionality to it that counts certain items depending on different conditions

My thoughts in testing were to:

  1. set up and create the class
  2. populate a cart
  3. carry out my assertions

So - stumbling block number 1. The parent class of my class needs dependencies injected, which in turn has classed that need dependencies. Laravel normally takes care of this. I'm getting errors in setting up the class.

Question 1. Am I approaching this in the right way - should I be doing something else? Question 2. How can I initiate a new class that has DI - it all feels very complicated at the moment

My class Cart I'm trying to build tests for:

namespace App\Golfmanager\Cart;

class Cart extends \Gloudemans\Shoppingcart\Cart
{
    public static function destroyCart($carts = array('greenfee', 'main', 'payment', 'resource'))
    {
        foreach ($carts as $strCartName) {
            Cart::instance($strCartName)->destroy();
        }
    }

    /**
     * @param string $cartName
     * @return int
     */
    public function getCartGroupSize($cartName = 'main')
    {
        $cart = $this->instance($cartName)->content();

        $groupSize = 0;

        foreach ($cart as $row) {

            if (in_array($row->options->type, array('Green Fee', 'Society Package'))) {
                $groupSize = $groupSize + $row->qty;
            }
        }

        return $groupSize;
    }

    /**
     * @param string $cartName
     * @return int
     */
    public function getCartCostsTotal($cartName = 'main')
    {
        $cart = $this->instance($cartName)->content();

        $costs = 0;

        foreach ($cart as $row) {
            $costs = $costs + $row->options->cost;
        }
        return $costs;

    }
}

The parent class - constructor only

    public function __construct(SessionManager $session, Dispatcher $events)
    {
        $this->session = $session;
        $this->events = $events;

        $this->instance(self::DEFAULT_INSTANCE);
    }

And finally my test:

class CartTest extends TestCase
{

    private $cart;

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

    }

    public function before()
    {
        $this->cart = new Cart(new SessionManager, new Dispatcher);
    }

    public function test_group_size_calculation()
    {

//        $this->cart = new Cart();

        dd($this->cart);
//        clear any existing cart entries
        $this->destroyCart('greenfee');

//        add 1st green fee product
        $options = $this->createAttributes();
        $this->addToCart(8, "test product", 1, 25, $options);

        $this->assertEquals($this->cart->getCartGroupSize('greenfee'), 1);

//        add non green fee product
        $options = $this->createAttributes(['type'=>'Something Else']);
        $this->addToCart(10, "test other product", 10, 25, $options);

        $this->assertEquals($this->cart->getCartGroupSize('greenfee'), 1);
    }

    private function createAttributes($attributes = [])
    {
        $base = [
            'cost'     => 10,
            'type'     => 'Green Fee',
            'mealQty'  => 1,
            'dateTime' => Carbon::now()
        ];

        return array_merge($base, $attributes);
    }

    private function addToCart($id, $name, $people, $salePerHead, $options)
    {
        $this->cart->add(
            $id,
            $name,
            $people,
            $salePerHead,
            $options
        );
    }

    private function destroyCart($string)
    {
        $this->cart->instance('greenfee')->destroy();
    }
}

All help appreciated to get me over this testing learning curve

28 Feb
1 year ago

longestdrive left a reply on Testing Laravel Form Request With Custom Rules

Thanks - yes I am testing too much and will change these tests.

I think the redirect occurs at the end of the store method in the controller - it's redirecting to an index page so that makes sense

25 Feb
1 year ago

longestdrive left a reply on Testing Laravel Form Request With Custom Rules

Yes, you're right in controller I have:

public function store(CreateGreenFeeSaleRequest $request)
    {
// create the records needed

return redirect()->route('greenfees.index');
}

I've now updated the test as suggested - with valid attributes:

public function test_form_validation_passes_used_ticket_this_reservation()
    {
        $attributes = $this->createAttributes(['ticket'=>967, 'reservation_id'=>1554]);

        $this->post(route('greenfees.store'), $attributes)->assertStatus(200);
}

The test though fails - I'm getting a response code of 302

Question - by doing it this way I assume the records get created in the store method and the rest of the method is applied? So is this test testing too much in one go? ie if there's something wrong in the store method this will affect the test so I don't know if it's the store logic or the request logic that has the problem?

Sorry for my lack of understanding and thanks for the help

longestdrive left a reply on Testing Laravel Form Request With Custom Rules

Hi - the rule checks whether this ticket has already been allocated to a reservation by reservation_id and if it is is the reservation this reservation.

If it is the same reservation it should pass and if not it should fail

If the reservation_id for this ticket is null then it means it's not been allocated so passes.

So I think unique would work I don't think it takes into account that it could be used for this record.

Reservations are in one table, tickets are in another - tickets contain the reservation_id

I'll look at your approach (do you have an example test you could show me?) - I think I assumed with the test to try an isolate to the method (in this case the rule) but then I don't yet understand what to test and how to test

Thank you

longestdrive started a new conversation Testing Laravel Form Request With Custom Rules

I'm trying to get my head around testing (again) and in particular test a form request with a custom rule. I'm using Laravel 5.5.

My rule needs a variable from the request to compare the field value under validation.

Whilst I can get this to work in the app I can't create the test correctly and pass the values.

Here's the custom rule (stripped down to essential info):

 class TicketNumberIsNotUsed implements Rule
{
    
    public function __construct($reservation_id)
    {
        $this->reservation_id = $reservation_id;
    }



    public function passes($attribute, $value)
    {
        $ticket = TicketAudit::where('ticketnumber', '=', $value)->first();

        if($ticket) {
            return (is_null($ticket->reservation_id) || $ticket->reservation_id == $this->reservation_id ? true : false);
        }
        return false;
    }

  
    public function message()
    {
        return 'This ticket has already been used for another booking.';
    }
}

Here's the form request which uses the custom rule:

class CreateGreenFeeSaleRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return Auth::user()->hasRole('sales');
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'play_date'=>'required',
            'am_tee'=>'required',
            'howBooked'=>'required',
            'ticket'=>[
                'required',
                'exists:ticket_audits,ticketnumber' ,
                new TicketNumberIsNotUsed($this->reservation_id)
            ] ,
            'pay_method'=>'required',
            'customer_id'=>'required:exists:customers,id'

        ];
    }

    public function messages()
    {
        return [
            'ticket.required' => 'A valid ticket is required',
            'ticket.exists'  => 'This ticket does not exist',
        ];
    }

}

and here is my test:

class CreateGreenFeeTest extends TestCase
{
    protected function setUp()
    {
        parent::setUp();

    }

    private function createAttributes()
    {
        $faker = \Faker\Factory::create();

        $attributes = [
            'play_date' => $faker->date('d/m/Y'),
            'reservation_id' => null,
            'am_tee' => $faker->time('H:m a'),
            'howBooked' => 'drop in',
            'ticket' => 905,
            'pay_method' => 'cash',
            'customer_id' => 1532
        ];

        return $attributes;


    }

    public function test_form_validation_passes()
    {
        $attributes = $this->createAttributes();
        $request = new \App\Http\Requests\CreateGreenFeeSaleRequest();
        $rules = $request->rules();
        $validator = Validator::make($attributes, $rules);#
        $passes = $validator->passes();
        $this->assertEquals(true, $passes);
    }

    public function test_form_validation_fails_unused_ticket()
    {
        $attributes = $this->createAttributes();
//        make change to a used ticket
        $attributes['ticket']=967;
        $request = new \App\Http\Requests\CreateGreenFeeSaleRequest();
        $rules = $request->rules();
        $validator = Validator::make($attributes, $rules);#
        $fails = $validator->fails();
        $this->assertEquals(true, $fails);
    }

    public function test_form_validation_passes_used_ticket_this_reservation()
    {
        $attributes = $this->createAttributes();
//        make change to a used ticket
        $attributes['ticket']=967;
        $attributes['reservation_id']=1554;
        $request = new \App\Http\Requests\CreateGreenFeeSaleRequest();
        $rules = $request->rules();
        $validator = Validator::make($attributes, $rules);#
        var_dump($validator->errors());
        $passes = $validator->passes();
        $this->assertEquals(true, $passes);
    }
}

So:

  1. How do I pass the reservation_id to the custom rule from the test
  2. How should I correctly mock that an authorised user is logged in?

I am struggling with tests despite hours reading and trying to learn - it doesnt stick until I can apply it - I cant apply it till I get it!! (catch 22) So any help appreciated especially on how to construct the tests properly

Thank you

longestdrive left a reply on How Can I Establish Whether Controller Method Was Hit From A Redirect

Thank you

I decided to look at the session status on the basis that if the validation fails there should be _old_input as an entry in the session. This is what I did:

if (!request()->session()->has('_old_input')) {
            // Do stuff
        }

This seems to work

20 Feb
1 year ago

longestdrive started a new conversation How Can I Establish Whether Controller Method Was Hit From A Redirect

Hi I'm validating a form using a form request which as you would expect returns to the form following a failed validation and has $errors available in the view.

However in my controller method which creates the view etc my method empties a cart before the view is created (in case of any orphaned data etc from a cancelled request).

I'd like to be able to check - before this empty method is called - whether the method is being called as a result of a redirect.

I thought about adding a value to the redirect but as this is being handled by the form request I'm not sure how to go about this

Any suggestions?

Thanks

longestdrive left a reply on Create Custom Validation Rule With Additional Parameters - Implement In Request

Thanks @Snapey . Yes, I did that in the final implementation to pass the id as you've shown. My struggle was trying to mix dot syntax and instantiating the rule class. T

19 Feb
1 year ago

longestdrive left a reply on Create Custom Validation Rule With Additional Parameters - Implement In Request

Found the answer = my lack of understanding of the dot syntax :(

Changed the rules to:

public function rules()
    {
        return [
            'play_date'=>'required',
            'am_tee'=>'required',
            'howBooked'=>'required',
            'ticket'=>['required', 'exists:ticket_audits,ticketnumber' , new TicketNumberIsNotUsed] ,
            'pay_method'=>'required',
            'customer_id'=>'required:exists:customers,id'

        ];
    }

And now the rule fires

longestdrive started a new conversation Create Custom Validation Rule With Additional Parameters - Implement In Request

Hi I'm trying to add a custom validation rule to a Laravel 5.5 app.

I've created a rule using php artisan make:rule and am struggling getting it to work so I can build on it. I've looked at the docs here: https://laravel.com/docs/5.6/validation#custom-validation-rules

This goes on to use this in a controller, implies you can use it in a request but doesn't say how.

My rule will check whether the ticket has been used and if it has pass if it is for this id or fail if it is for another id. So it needs the ticket number and the parent record id.

Here's the rule skeleton:

    <?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class TicketNumberIsNotUsed implements Rule
{


    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        dd($value);
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The validation error message.';
    }
}

and here's how I'm trying to implement in my request:

    public function rules()
    {
        return [
            'play_date'=>'required',
            'am_tee'=>'required',
            'howBooked'=>'required',
            'ticket'=>['required|exists:ticket_audits,ticketnumber' , new TicketNumberIsNotUsed()] ,
            'pay_method'=>'required',
            'customer_id'=>'required:exists:customers,id'

        ];
    }

The error I get is Method [validateRequired|exists] does not exist.

so by including the way I have corrupts the rules.

I've tried looking for tutorials which all point towards extending the validator class and using the AppServiceProvider but trying to avoid this route and follow the guidance in the docs.

Any help appreciated

26 Nov
1 year ago

longestdrive left a reply on Refactoring Messy Store Method - Need Help Understanding Use Cases From Tutorial Lesson 2

Thank you. That was the bit I was getting confused about, I was worried about needing to keep passing dependencies on to the class from a high level which didn't feel as if I was simplifying anything I've been looking at the container and think that is the way to go - next lesson to learn Thank you

25 Nov
1 year ago

longestdrive left a reply on Homestead V6.5.0 Bad Gatweway Error 502 Trying To Use Php 5.6

Just tried installing using:

sudo apt-get install php5.6-fpm --fix-missing

and I got this message: php5.6-fpm is already the newest version

So this must be in a different location? So, do I need to update a config file for this version of php-fpm?

longestdrive started a new conversation Homestead V6.5.0 Bad Gatweway Error 502 Trying To Use Php 5.6

Hi I'm using the latest version of homestead v6.5.0. The set up is working well for my Laravel 5 sites but not for a laravel 4.2 site.

I've set the php version to 5.6 for the site in homestead.yaml as detailed in the guidance. However when I try to access the site I get a bad gateway 502 error

checking the nginx log file I found this error:

connect() to unix:/var/run/php/php5.6-fpm.sock failed (2: No such file or directory) while connecting to upstream

Checking that directory none of the php5.6-fpm files are there.

How do I install these to the homestead machine?

Thanks

19 Nov
1 year ago

longestdrive started a new conversation Refactoring Messy Store Method - Need Help Understanding Use Cases From Tutorial Lesson 2

Hi I'm upgrading an app from 4.2 to 5,5 and whilst doing this refactoring alot of the app. I've followed the tutorial whip monstrous code and trying to implement the approaches in lesson 2 (use cases) and lesson 7 (tasks) but I'm having trouble implementing the approaches due to my lack of understanding of some basics...

Tried to ask a question on another forum but got frankly no help and a steer away from laravel so hoping for some humane responses here...

So

In using lesson 2 - use cases I;ve tried implementing this code:

abstract class BaseBookingHandler

{

public static function perform(Request $request)
{
    return (new static(
        ))->handle($request);
}

abstract public function handle(Request $request);

}

Then in my work class I have:

class BookClubEvent extends BaseBookingHandler

{ public function handle(Request $request) { //do stuff } }

All - ok and following the tutorial. But then my work class needs dependencies - I've tried injecting them in the work class but then get php errors around not passing them correctly ie not passing any.

So some questions:

Where should I inject my dependencies? In the parent class and then if there how do I initiate the classes correctly or in the child work class and then call parent::__contstruct?

Very confused with late static binding and how to intiate correctly

Secondly - looking at tasks (lesson 8) using an array of classes and working through them - how do I hand off variables to each class to work through the tasks in hand and secondly what if these classes need dependencies such as repositories - where and how do I inject them then

Thanks

10 Jul
1 year ago

longestdrive left a reply on Install Latest Homestead - Which Version?

I found this article: https://laravel-news.com/homestead-v5

and assumed there was a later version than I have at present. I'm easily confused!

Thanks

longestdrive started a new conversation Install Latest Homestead - Which Version?

Hi I want to install homestead as the latest version. I had version 2.1 installed and understand there is version 5 available?

I've uninstalled existing version and tried to re-install but doing vagrant box add laravel/homestread only wants to download version 2.1 again

If I do an vagrant update box there is a version constraint of 2.0.

I'm confused about the version numbers in the first place - what version number is the latest version and if it's higher than I have how can I remove the version constraint?

Thanks

09 Jul
1 year ago

longestdrive started a new conversation Best Practice To Initiate Object

Hi

I'm after some best practice to initiating objects to try and refactor some code.

In my Laravel app I generally have followed this approach to structure a class:

<?php
/**
 * Created by PhpStorm.
 * User: ray
 * Date: 05/07/2017
 * Time: 17:34
 */

namespace app\Libraries\Generators;

use App\Models\Fixture;
use App\Libraries\Repositories\FixtureRepository;

class FixtureMatrixGenerator
{
    protected $fixture;
    protected $fixtureRepository;

    /**
     * FixtureMatrixGenerator constructor.
     * @param $fixture
     */
    public function __construct(Fixture $fixture, FixtureRepository $fixtureRepo)
    {
        $this->fixture = $fixture;
        $this->fixtureRepository = $fixtureRepo;
    }

}

But then if in say a controller I try to initiate the object like this:

`$leagueMatrixGenerator = new FixtureMatrixGenerator();`

I get an error `Too few Arguments to function` Which I expect.

So what's the best practice for loading dependancies into a class? In some of my controllers for example I end up with 6-7 dependcies (generally models or repositories) which seems to bloat the __constructor method. Is there a better method for creating new objects only when I need them?

Sorry, likely a basic oop question but I've got stuck down one route that now seems messy






19 Jun
1 year ago

longestdrive left a reply on Cutsom Attribute On Model Available Without Being In $appends Array

Thank you. Def have the package installed on the live server - as soon as I remove the $appends it no longer works and provides a null value - strange!