Roni

Roni

WINNIPEG, MANITOBA

Member Since 4 Years Ago

Experience Points 71,420
Experience
Level
Lessons Completed 796
Lessons
Completed
Best Reply Awards 5
Best Answer
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.

19 Dec
4 weeks ago

Roni left a reply on Add Packages To Tests

@d9705996 this is perfect! Thank you!!!!

Roni left a reply on Add Packages To Tests

Looks good, I'll give it a read through and mark this best if I can get through it. Thanks @

18 Dec
4 weeks ago

Roni started a new conversation Add Packages To Tests

Hi All, I made a nifty little package to make testing / scaffolding a new project easier. It's my first package and it's basically only made for me. Perhaps it might help you learn to write your own small package too.

However, I have no idea how to go about adding tests to a package, and more importantly how to develop a package with TDD.

If anyone knows a good resource for that or has some advice, please let me know.

Thanks,

Here is the package if it helps or just if you are interested.

https://github.com/roni-estein/quicktools

Roni left a reply on Extend A Blade View And Yield In The Same File.

Well lucky I posted here :( I never noticed the missing quote. Too much staring at the screen. So in fact this does all just work. Cheers

Roni started a new conversation Extend A Blade View And Yield In The Same File.

I've been playing with really unifying my code structure to make maintaining different projects a bit less time consuming, so I've been spending some time on structures lately. I always have a bunch of layout files, that eventually get added to the project, and was wondering if I'm approaching this wrong,

I typically find a in resources/layouts a bunch of very similar repeated code. For example:


app-with-nav.blade.php
app-with-nav-single-screen.blade.php
app-without-nav.blade.php
app-without-global-vue.blade.php
the list goes on

These are all almost the same, they'll have a base head section but with some modifier around the @yield('content')

I've been trying to look at having them all do something like extending a middle page, but, so far laravel doesn't like it. Here is an example from a new 5.7 project fresh install:

app.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!-- Fonts -->
    {{--<link rel="dns-prefetch" href="//fonts.gstatic.com">--}}
    {{--<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet" type="text/css">--}}

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    @yield('page-stuff')
</body>
</html>

app-without-nav.blade.php

@extends('layouts.app)

{{-- PRESUMABLY SOMETHING HAPPENS HERE THAT MAKES THIS PAGE DIFFERENT FROM OTHERS BUT NOW DOESN'T NEED TO TOUCH / REPRODUCE ANYTHING OTHERTHAN IT'S SPECIFIC TARGET MATERIAL--}}

@section('page-stuff')
    <div class="something">
        @yield('content')
    </div>
@endsection

Now, if something extends app-without-nav it dies a horrible death.

Idea's are welcome. And organizing schema's appreciated.

12 Dec
1 month ago

Roni left a reply on Using A Global Php Helper Functions When Developing A Package

@jlrdw yeah, it's easier in my opinion after looking at both, instead of wondering where the magic test_path function came from, I used BaseProject::testPath() which I feel is very clear and readable.

Thx

Roni left a reply on Using A Global Php Helper Functions When Developing A Package

Makes sense, I think I'll go with this method, I'll try it out momentarily

11 Dec
1 month ago

Roni left a reply on Using A Global Php Helper Functions When Developing A Package

@cronix, that does work, but seems un-composer-y. However it's better than the ugly static on the service provider. If I can't find a better solution the award is yours. Cheers and thanks for all the help.

Roni left a reply on Using A Global Php Helper Functions When Developing A Package

yeah, putting it in mine, but it still errors out saying it can't find the function. :( I've tried autoload and autoload-dev for the file. I'm looking for some example projects that do it in the mean time.

Roni started a new conversation Using A Global Php Helper Functions When Developing A Package

When in laravel, to add a "helpers.php" to the global scope so you can use it's functions, you can add a line like this to your composer.json


 "autoload": {
        "psr-4": {
            "App\": "app/"
        },
        "files": [
            "app/Helpers/BaseHelpers.php"
        ]
    },


However, when trying to develop a package, I've wanted to make a couple of helper functions to be used in multiple files like function test_path() for example.

When I create the same autoload or autoload-dev entry it can't seem to find the function.

I've resorted to adding it in the service provider as a static function which feels gross in some instances like PackageServiceProvider::test_path('stuff.php');

Is there a way I can create a global function so I can use it in multiple places in the package?

Thanks

05 Dec
1 month ago

Roni left a reply on Developing Packages

@moesaid thx, glad it helped. any chance of an award? I don't sneak them by very often :)

Roni left a reply on Developing Packages

Doing the same thing, look at the wink package, for a really simple package. Source dive it, it's really small yet powerful. https://github.com/writingink/wink Or for a more robust package I would maybe look at something close to what you might want to do. I've been source diving https://github.com/JosephSilber/bouncer, mainly for his structure.

You could also try anything spatie. Look at their smaller packages.

Good luck but start with source diving and read that packages form. Oh and the most helpful thing I've found is go to laracon.net and watch the taylor otwell keynote. It's awesome for laravel but at 43 minutes in he talks about how he develops packages locally, it's awesome and a huge time saver.

04 Dec
1 month ago

Roni left a reply on Composer Assistance For Autoloading A File In A Package

@jlrdw I've been thinking about what you've said perhaps this is an option, I'm not sure about the pros and cons of this as opposed to the require:

https://github.com/JosephSilber/bouncer/blob/master/tests/helpers.php

I think it creates a function only if the function does not exists and limits it to the Tests\ namespace. I might have to rewrite it to work for example in a factory which I believe has no namespace. I'm also not that familiar with adding testing directly in packages. That will be my question for you after I've had a chance to do some research on it this weekend. :)

Roni left a reply on Composer Assistance For Autoloading A File In A Package

@jlrdw , Thanks for the update,There are a couple of reasons.

I'm replacing some functions already widely in use in my projects. I'd like to go back and include the package in them one at a time. But it has some ubiquitous functions. I have a ddf() function that wraps around dd but also tells me the calling function and arguments for example. (I've left one or two in a test suite before and when I was just using dd it took a while to track down the offending file. Since it's a global function used in factories, controllers, tests, I'm not requiring it anywhere.

Other things I'm only using in some places, but again, it just seemed easiest. I thought of making a command to overwrite some of the offending versions of the file, but I thought it might make for a painful transition if make a mistake in how a project was implementing something. This seemed like a really graceful way to transition the code bases, first with a composer update to add the new package and remove the helpers, and then move back forth as I massage out the bigs and differences.

I also want it to be very easy to source dive so on joint projects other can easily adapt to it.

Roni left a reply on Composer Assistance For Autoloading A File In A Package

@jlrdw thanks for the quick response,

One sec, to clarify,

I want to move my helpers.php out of my project and into my package. Right now it IS in my package, but without the require statement, everything fails. Are you saying composer dump autoload should find non namespaced php files and include them globally? I haven't tried it, but it doesn;t make sense to me. What I want to do is remove it from my proejcts as they all have it but there are 20 different version that are each a little different, missing a function or one has a capital letter in a name etc... and I always copy it form place to place.

The package idea of standardizing it and cleaning it and 10-15 other things that I ALWAYS use seems like a great idea. In fact I can't believe I waited until now to do it.

But after testing that theory, I can tell you that for me at least it needs to be required. It just seems like other people have found a way to do it with autoload which I believe would be more maintainable and clearer to another user. Here is an example where someone got it to work. (I haven't tested it. However they also don;t have any namespaces.

https://github.com/djaxho/laravel-cats

Roni started a new conversation Composer Assistance For Autoloading A File In A Package

I've found an ugly solution to this already but i was hoping there was a better one.

I'm working on my first package, it's a time saver for me, but I'll publish it when it's a bit more complete for anyone who might want it. Right now, It simply adds a series of commands and a few files that address quickly starting up a project.

I have a number of functions that I use in global scope in my projects as well. Now in my project I simply add it in composer as follows.


 "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\": "app/"
        },
        "files": [
            "app/Helpers/helpers.php"
        ]
    },


However, if I want my package to include it, much like a global dd() function, I haven't figured that out. I've tried adding a files parameter to the autoload section of the package but it doesn't work. Oddly it doesn't even throw an error if you give it a purposely wrong name.

I've been able to make it work it by adding a require statement in the package service provider. But that seems hackish:


<?php

namespace Package;

require ('Helpers/helpers.php');

use Illuminate\Support\ServiceProvider;

class PackageServiceProvider extends ServiceProvider {

Any Advice welcome

Cheers and thanks.

18 Nov
1 month ago

Roni left a reply on Live Pair Programming

@drfraker that looks AWESOME! I'm so stoked to try it out, I guess its finally time to try out VScode

Roni left a reply on Is There A Way To Make A Form Request From Another Request

Love Taylor Otwell, his video on the laracon.net is so jam packed full of goodies. It gives all the hints about where to look to solve this, but basically you can create one form request from another, since all form requests extend Illuminate\Http\Request, they have a static method called "createFrom"

So you can code something like this to pass on a more specific version of your request:

$questionAForm = QuestionAForm::createFrom($request);
$this-> storeQuestionA($questionAForm, $topic_slug);

Roni left a reply on Is There A Way To Make A Form Request From Another Request

Hi @JeffreyWay, The form seems to still be doing something odd with the timezones. I just posted this and it's 57 min old. Which is weird. Seems like it should be correct or some function of 60 min old.

Roni started a new conversation Is There A Way To Make A Form Request From Another Request

This may be a silly solution and there are others I could already make however I have this route set:

// This won't work unless you add some functionality to the root controller
// but this ins't the question. It's based on some tweets from spatie.be 
// with some adamwathan comment ideas thrown in there.
// just putting this note in, incase any one tries this and breaks their "web.php" 

Route::post('account/topic/{topic_slug}/type/{question_type}/' , TopicQuestionController::at('store'))->name('topic.question.store');

Route::get('account/topic/{topic_slug}/type/{question_type}/create' , TopicQuestionController::at('create'))->name('topic.question.create');


This store lets me respond to all question types, and depending on the "question_type", I would like to make a new form request out of the request data.

  1. simple solution is to just change question type into a hard coded path for example:

Route::post('account/topic/{topic_slug}/type/question-a/' , TopicQuestionAController::at('store'))->name('topic.question.a.store');

Route::post('account/topic/{topic_slug}/type/question-b/' , TopicQuestionBController::at('store'))->name('topic.question.b..store');

//etc ...

But this is a hobby project where I want to push the edge of my knowledge so ...

I have this store method:

public function store(Request $request, $topic_slug, $question_type)
    {
        if($question_type == 'questionA'){
            $this->storeBasicFact($request, $topic_slug);
        }
    }

    public function storeQuestionA(QuestionAForm $form, $topic_slug )
    {
        dd($form);
    }


Now clearly this won't work I'm trying to pass a request object into another differing object even though it extends request. However if I asked for a QuestionAForm, laravel would have autowired it for me in the original store method.

anyone know where laravel does that or how I could implement that middlestep of converting the request to another form request object?

14 Nov
2 months ago

Roni left a reply on Elegant Way To Authorize A Form Request

Thanks @ahmeddabak @mushood, I've used the middleware on route and just in the controller before, but I have never used the actual overwritten form request before which I thought might be a really easy place to put these concerns since it's baked in. I just thought I was missing something.

Thanks for the answers, since you are both correct I'm just picking the first.

13 Nov
2 months ago

Roni started a new conversation Elegant Way To Authorize A Form Request

Hi All, I'm playing with FormRequests and Looking at my first authorization. It feels like there should be a cleaner way and I'm missing something. Is there a better way to accomplish this? It already works.

I'd like to update this topic if, the topic account_id is the same as the $this->account_id which is coming from a form but could come from auth()->user()->account->id or a convenience method i have auth()->accountId().

The problem is that when the authorize function is called, I don't have the topic yet, that gets resolved after as I understand it in the controller. Since I'm not directly calling authorize(), I can't pass it a parameter, so I need to use the string URL

If someone is manipulating this, maybe a malformed ajax request the find method wont find anything, which will trigger an trying to access a member on null, or I could use find or fail and catch a ModelNotFoundException, but they both mean I'm unauthorized. I could just return true and deal with this in the update persisting method once I have the topic passed in, but it's just deferring this to look cleaner and then I have am authorize method that just returns true...

Am I looking at this in the wrong way?


 public function authorize()
    {
        if ($this->isMethod('POST')) return true;

        if ($this->isMethod('PATCH')){

            try{
                $topic = Topic::find($this->segment(2));
                return !! $topic->account_id == $this->account_id;
            }catch (\Exception $e){
//      return false;
                Throw new UnauthorizedException('You Are Not Authorized to Edit this Topic');
            }

        }
    }

Here is the controller


    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(TopicForm $form, Topic $topic)
    {
        $form->update($topic);
    }


The update method in the topic form


    public function update($topic)
    {
        // we could more easily implement authoization here
        // but it seems like I'm missing the point if I
        // do it that way.
        $topic->update($this->input());
    }

Thanks

Roni left a reply on Exists In A Table Validation Issue

@talinon you are the king, I must need yet another coffee.

Roni started a new conversation Exists In A Table Validation Issue

It's Tuesday morning and I'm under the weather, so my brain must be missing something jsut a validation request where my last rule is causing an issue. I need to validate that the incoming account_id is a valid id in the accounts table. I added them rest of the tests just to make sure that data was indeed coming in and in the end the two dumps showing that the ID in the Accounts table was there, and that the input matched the id ( I doubled that first test becuase my dump with a concat made the data look a bit funny and I didn't want to confuse anyone:


 public function rules()
    {
    dump(Account::all()->pluck('id'));
        dump('ACCOUNTS TABLE: '. Account::all()->pluck('id'));
        dump('INPUT ACCOUNT : '. $this->input('account_id'));

        return [
            'name' => 'required',
            'min_age' => 'required|numeric|min:3',
            'requires_group' => '',
            'public_visible' => '',
    // this line is the issue and it looks right to me !
            'account_id' => 'required|numeric|integer|min:1|exists:accounts, id',
        ];
    }


here is the test output


Testing started at 10:13 AM ...
/usr/local/bin/php /Users/roni/code/php/laravel/5.7/pie/vendor/phpunit/phpunit/phpunit --configuration /Users/roni/code/php/laravel/5.7/pie/phpunit.xml --filter "/(::a_valid_topic_can_be_created_in_the_database_by_an_authenticated_user)( .*)?$/" Tests\Feature\Topic\CreateTopicTest /Users/roni/code/php/laravel/5.7/pie/tests/Feature/Topic/CreateTopicTest.php --teamcity
PHPUnit 7.4.3 by Sebastian Bergmann and contributors.

Illuminate\Support\Collection {#1077
  #items: array:1 [
    0 => 1
  ]
}
"ACCOUNTS TABLE: [1]"
"INPUT ACCOUNT : 1"
"Tests\DomainTestCase\errorsArray([])"
"-------------------------------------------"
Illuminate\Support\MessageBag {#1092
  #messages: array:1 [
    "account_id" => array:1 [
      0 => "The selected account id is invalid."
    ]
  ]
  #format: ":message"
}

Process finished with exit code 1

Thanks for any assistance

12 Nov
2 months ago

Roni started a new conversation Visual Issue On Profile Section In Site

Hi @jeffrey_way, on the profile section where is lists your badges, unless your scree size is over xl, the mouse over descriptions on badges on the left and right sides bleed over the edge of the viewport. So on the far left and the far right, first 2-3 on each side the text and background box is cut off.

Clearly not a high priority, but thought I'd let you know.

08 Nov
2 months ago

Roni left a reply on Making Model Macroable

Well Damn Me! You can't the macroable trait because you are overwrittingt he macro's array! Because model IS macroable! I couldn't source dive find where it happens, but I removed everything and the macro's never stopped working.

I hope this saves you a few hours.

Cheers.

Roni started a new conversation Making Model Macroable

Hi, I've found it super helpful under certain circumstances to make model macroable. However I'm finding some drawbacks. I'm hoping someone might have a little deeper knowledge on this.

The only place I use it is in testing, and it's amazingly helpful. When faced with a nasty query, being able to throw the array, table, or collection into a console table printout has been a real go to. Taking what was a much longer process and shrinking it to a minute or two as the information pops out at you.

The main reason for doing this is to have access to the attributes array externally under test that you won't have access to in the actual app. It keeps the app code clean and the testing fast.

However, checking the rest of the test suite showed some conflicts with commands from the builder like "find" or "where", which is kind of a big deal. Has anyone properly implemented Macroable in a non conflicting way?

Here are the files for clarification with some examples, all are properly visible and working, it's not a composer autoload issue.

My Model


namespace App\Helpers;

use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Support\Traits\Macroable;


class Model extends EloquentModel
{

    use Macroable {
        __call as myMacroCall;
    }

    public function __call($method, $parameters)
    {
        if (static::hasMacro($method)) {
            return $this->myMacroCall($method, $parameters);
        }

        return parent::__call($method, $parameters);
    }

    protected $guarded = [];

}

I use it as follows for example Game.php :


namespace App;

use App\Helpers\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class Game extends Model
{

//rest of class

}

In my test class I've set up a macro:


Model::macro('tableHeaders', function(){
    return array_keys($this->attributes);
});


It works perfectly. But now, my test suite is throwing new errors like this:

  1. Tests\Unit\GameTest::a_game_has_many_turns BadMethodCallException: Method App\Game::find does not exist.

or

  1. Tests\Unit\GameTest::a_question_set_can_be_filtered_by_a_user BadMethodCallException: Method App\Turn::where does not exist.

These all vanish as soon as I comment out the use Macroable from the parent model class.

Thanks for any advice you might have.

07 Nov
2 months ago

Roni left a reply on What About New Look @laracast.com

Looks awesome, performing a bit slow, but more than likely because we are all here at the same time looking at the new site :)

06 Nov
2 months ago

Roni left a reply on Anyone Ever See M:N Sync Do Some Ordering?

I updated it with results for clarity:


public function setPlayers($players)
    {
        $shuffled = $players->shuffle()->pluck('id')->all();

        dump($shuffled);

        $this->players()->sync($shuffled);
        dd($this->players->pluck('id')->values()->all());
    }



//RESULTS

PHPUnit 7.4.3 by Sebastian Bergmann and contributors.

array:5 [
  0 => 5
  1 => 3
  2 => 2
  3 => 1
  4 => 4
]
array:5 [
  0 => 1
  1 => 2
  2 => 3
  3 => 4
  4 => 5
]

Process finished with exit code 1

Roni started a new conversation Anyone Ever See M:N Sync Do Some Ordering?

It's been a long day and maybe my brain is used up but running this test always gives me back ordered id's even though I'm attempting to randomize the order they are stored in.


public function setPlayers($players)
    {
    //players are in order here
        $shuffled = $players->shuffle()->pluck('id')->all();
    //dd($shuffled); //everything is nicely shuffled here

        $this->players()->sync($shuffled);
        dd($this->players); //everything is back in order here!!!

    //Mind => blown

    }

Roni left a reply on Validating An Array

I find this super confusing and perhaps I'm not testing this correctly,

this validation rule works perfectly in all cases that I've tested (again I've left in commented lines:

I hate using this even though it passes every test because I'm not exactly sure what is going on.

I'm missing where each item is pulled to compare. But I can tell you without any hesitation that it IS doing it.


    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required',
//            'players' => 'required|array|min:1',
            'players' => [
                'required',
                'array',
                'min:1',
                Rule::exists('players', 'id')->where('account_id', auth()->accountId())
            ]
//                'int',
//                Rule::exists('players')->where(function ($query) {
//                    $query->where('account_id', auth()->accountId());
//                }),
//            ]
        ];
    }

If anyone could shed some light it would be appreciated.

Here is the updated test lines broken out for easy commenting


 /** @test */
    public function a_valid_game_will_be_stored() {
        $this->accountSignIn();

        $validPlayer1 = create(Player::class, ['account_id'=>auth()->accountId()]);
        $validPlayer2 = create(Player::class, ['account_id'=>auth()->accountId()]);
        $invalidPlayer = create(Player::class);
        $this->withExceptionHandling()
            ->submitValidGame([
                'players'=>[
                    $validPlayer1->id,
                    $validPlayer2->id,
//                    $invalidPlayer->id
                ]
            ])
//        dd(session()->get('errors')->getBag('default'));
        ->assertOk();

        $this->assertDatabaseHas('games', [
            'name' => 'Valid Game Name']);
    }


Roni started a new conversation Validating An Array

Hi Guys,

I'm trying to figure out validating a single field that contains an array

the data for the field will be generated by a vue components that will produce an array of integers


[1, 2, 3]

I want to validate that the input is in fact an array, (that part is fine) AND that each item in the array is an integer and in in a table with a specific account_id

Here is my code, I've tried a number of variations on based on the docs, but I can't seem to find the right one.

I'm calling this from a unit test so that the backend is all hooked up before I setup the visuals, I can't see that making a difference, but in case it does, now you know.


 public function rules()
    {
        return [
            'name' => 'required',  //Works
            'players' => 'required|array|min:1', //Works
            'players.*' => [
                'required',
                'int',
                Rule::exists('players')->where(function ($query) {
                    $query->where('account_id', auth()->accountId());
                }),
            ]
        ];
    }

I'm calling it from this unit test, I've left some of my hackery in trying to dig into this one.


    /** @test */
    public function a_valid_game_will_be_stored() {
        $this->accountSignIn();
        $player = create(Player::class, ['account_id'=>auth()->accountId()]);
        $this//->withExceptionHandling()
            ->submitValidGame(['players'=>[$player->id]] );

//        dd(session()->get('errors')->getBag('default'));
        //->assertOk();

        $this->assertDatabaseHas('games', [
            'name' => 'Valid Game Name']);
    }

here is the helper function submitValidGame


  protected function submitValidGame($overrides = [], $update = false)
    {
        return $this->post(route($update ? 'setup.update' : 'setup.store'),
            $this->validGameFields($overrides));
    }

    /**
     * @param $overrides
     * @return array
     */
    protected function validGameFields($overrides = []): array
    {
        try{
            return array_merge([
                'name' => 'Valid Game Name',
                'players'=> [1],
                'account_id' => auth()->accountId(),
            ], $overrides);
        }catch(\Exception $e){
            return [];
        }

    }

just in case, here is a snippet from the players migration

          
            $table->integer('account_id')->unsigned();
            $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');

and the relationship


    /**
     * Get the account that owns the Player.
     */
    public function account()
    {
        return $this->belongsTo(Account::class);
    }

the only thing I can't seem to make run is the players array specific item validation .

Thanks.

Roni left a reply on Add Custom Function To Auth Facade

@Edgar.Hauf , thanks!

I've noticed this won't work in a unit test


// WONT WORK in phpunit
auth()->user()->account

however this will work in a unit test and I think is very clear


SessionGuard::macro('account', function(){
    return auth()->user()->load('account')->account;
});


So you could use it like this in your unit tests


auth()->account()


Instead of the AppServiceProvider (I may add it there too for constancy) I jsut add it in my DomainTestCase file, setUp() method, just where I add macros that are specific to the project I'm working on, you could add it directly to TestCase and accomplish the same thing.

23 Oct
2 months ago

Roni left a reply on Additional Prepended Data Showing Up On My Cookie

@Borisu , @jlrdw Sometimes after too many coffees and too many hours, my brain turns to mush :) Thanks for pointing out the obvious ... and the video.

Roni left a reply on Use Function From Model In Notifications

I was looking at something unrelated when this popped up... This was what I was referring to before:

https://laracasts.com/discuss/channels/general-discussion/laravel-view-presenter

Roni left a reply on Sessions Seem To Always Be Empty And Regenerated

Ok, so to test a request with session data, you actually have to set the session in the request. Counter intuitive (for me at least)! Nice that this sessions and cookies don't seem to be covered in any testing course! Yes please show me how to mock mail for the hundredth time :/.

You probably don't need the local variable but I left it in for clarity.


 /** @test */
    public function a_guest_cart_is_reused_between_pages()
    {
        ObjectFactory::validInventoryProduct();

        $oldResponse = $this->get('/');
        $oldCart = session('cart');
        $oldCart->add(1);

        // Go back to the any page under the middleware and
        // the cart should be regenerated from the session.
        // set the session data needed for the request as
        // it will be purged on the new request.

        $session = session()->all(); //store session state
        $newResponse = $this->withSession($session)->get('/');

        // you can find more info about trait InteractsWithSessions
        // here: https://laravel.com/docs/5.7/http-tests#session-and-authentication 

        $newCart = session('cart');
        $newCart->add(1);

        $this->assertSame($oldCart, $newCart);
    }


Roni started a new conversation Sessions Seem To Always Be Empty And Regenerated

I've been playing with cookies on a laravel test app that I keep coming back to and just when I thought everything was working, I may have killed my sessions. Here are some unit tests on a middleware app to make sure it's working.

Otherwise this is in a regular laravel 5.7 application

middleware:


<?php

namespace App\Http\Middleware;

use App\Orders\Cart;
use Closure;
use Illuminate\Support\Facades\Cookie;

class SessionHasCart
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(Cookie::has('cart') && ! session()->has('cart')) {

            $cart = Cart::restoreFromCookie();
            $this->dumpSession('cookie had cart');
        }elseif( session()->has('cart')){
            $this->dumpSession('cart existed in session');
        } elseif(! session()->has('cart')) {
            Cart::makeInMemory(session()->getId());
            $this->dumpSession('creating new cart');


        }

//        Cookie::queue('cart',session()->getId(),Cart::LIFETIME);

        $response = $next($request);
        return $response->withCookie(cookie()->make('cart', session()->getId(), Cart::LIFETIME));


    }

    private function dumpSession($title = '')
    {
        $sessionData = session()->all();

        dump('dumping session: '. $title);
        dump('-------------------------------------------------');
        dump('_token           : '. $sessionData['_token']);
        dump('cart: id         : '. (isset($sessionData['cart']) ? $sessionData['cart']['id']:''));
        dump('cart: session_id : '. (isset($sessionData['cart']) ? $sessionData['cart']['session_id']:''));
        dump('=================================================');
    }
}


unit test CartTest.php

/** @test */
    public function a_guest_cart_is_regenerated_from_cookie_when_there_is_no_session()
    {
        ObjectFactory::validInventoryProduct();
        $oldResponse = $this->get('/');
        $oldCart = session('cart');

        $oldResponse->assertCookie('cart');
        $oldSessionId = session()->getId();

        session()->invalidate();

        //NOTICE THIS, you can preset the cookie, but only if you use the "call" method, not the "get" shortcut
        $cookie = ['cart' => \Crypt::encrypt($oldSessionId)];
        $newResponse = $this->call('GET','/',[],$cookie);
        $newCart = session('cart');

        $newResponse->assertCookie('cart');
        $this->assertSame($oldCart->id, $newCart->id);

    }

That test finally works it first hits the creating new cart segment in middleware and then hit's the restoring from cookie section.

As, I then went on to make sure the session segment was working, and it always restores from cookie! Yikes! Here is the test for that and results,


    /** @test */
    public function a_guest_cart_is_reused_between_pages()
    {
        ObjectFactory::validInventoryProduct();

        $oldResponse = $this->get('/');
        $oldCart = session('cart');
        $oldCart->add(1);

        //Go back to the any page under the middleware and the cart should be regenerated from the session. 
        
        $newResponse = $this->get('/');
        $newCart = session('cart');
        $newCart->add(1);

        $this->assertSame($oldCart, $newCart);
    }

// __________________________________
// RESULTS
// __________________________________

"dumping session: creating new cart"
"-------------------------------------------------"
"_token           : 3iZ6HcwK5Lno8Uc7pFIwrMjy3Wkb2EFYMEWDP5yv"
"cart: id         : 1"
"cart: session_id : bII3wpaBqeTHOSotraVLrl7onGjArpdCZ5zpKvt3"
"================================================="
"dumping session: before restoring cookie"
"-------------------------------------------------"
"_token           : elGVNleQwPNaTKnjt0vzmYZlTUO7NxYQTJVgVVpl"
"cart: id         : "
"cart: session_id : "
"================================================="
"dumping session: cookie had cart"
"-------------------------------------------------"
"_token           : elGVNleQwPNaTKnjt0vzmYZlTUO7NxYQTJVgVVpl"
"cart: id         : 1"
"cart: session_id : giBdIW4aFBVcrn7ptmWZM7V88s9iVDpDqfLK5vOq"
"================================================="

Time: 452 ms, Memory: 28.00MB

OK (1 test, 3 assertions)

Process finished with exit code 0

notice that it's using the cookie even though the session should in fact be set. Also the session is empty before restoring the cookie.

Here is the cart setting and restoring functions


 const LIFETIME = 60 * 24 * 30;

    public static function makeInMemory($sessionId)
    {


        $cart = self::create([
            'session_id' => $sessionId,
        ]);

        \Cookie('cart', $sessionId,self::LIFETIME);

        session()->put('cart', $cart);
        return $cart;

    }


    protected static function cleanCookieSession($value)
    {
        $sections = explode('"', $value);
        if(count($sections) == 3 )
            return $sections[1];
        return $value;
    }

    protected static function saveCurrentState($cart)
    {
        $cart->session_id = session()->getId();
        $cart->save();

        session()->put('cart', $cart);

        \Cookie('cart', session()->getId(),self::LIFETIME);
    }


    public static function findBySessionId($sessionId)
    {

        return self::where('session_id', self::cleanCookieSession($sessionId))->first();


    }
    public static function restoreFromCookie()
    {

//        dd('here:' . request()->cookie('cart'));
//        dump('searching for this cart: '.Cookie::get('cart'));
        $cart =  self::findBySessionId(Cookie::get('cart'));
        self::saveCurrentState($cart);

//        dd(session()->all());
        return $cart;

    }

Any insights would be helpful

22 Oct
2 months ago

Roni started a new conversation Additional Prepended Data Showing Up On My Cookie

I'm setting a cookie in middleware, and in the DB / session everything looks good when it is set, however, when I try to retrieve it from a cookie I get a prepended type attached to it.

Here are multiple way of setting it they all have the identical effect:


\Cookie('cart', $sessionId,self::LIFETIME);

Cookie::queue('cart',session()->getId(),Cart::LIFETIME);

$response = $next($request);

return $response->withCookie(cookie()->make('cart', session()->getId(), Cart::LIFETIME));


When I try to retrieve it from the cookie I end up with the prepended type, in my case a 40 character string:


dump(request()->cookie('cart'));
dump(Cookie::get('cart'));

They all give out the same data


"s:40:"8QdA0CymbSRllnttonOCvtYj90TErujQ4EmvecKQ";"

// when what the variable should actually get is simply

8QdA0CymbSRllnttonOCvtYj90TErujQ4EmvecKQ



$tmp = json_decode($sessionId, true);
dd($tmp);

// seems to just yield a blank. any advice welcome on the proper way.


Roni left a reply on Use Function From Model In Notifications

ok, I'm missing the "connective tissue" where are you creating the notification. In notify_comment.blade.php what is the $notification? How are you passing it to the view? Please share that or (and worse in my opinion)

move the following function to the comment class.

// remember you'll have to reset what
// $this->author is in the new class.
// and import PrivacySetting


public function displayAuthorName(){


       if( auth()->id() == $this->author->id ||
            in_array($this->author->privacy, PrivacySetting::CAN_SEE_USERNAME)||
            $this->author->isFollowed()) {
    
           return $this->author->username;

       }
       return 'AC';
     
   }



then you should be able to access it here


{{ $notification->data['comment']->displayAuthorName() }}

I'm not against using a base model to detail how its data should be look, however, I think it should be on some middle ground area. I used to use view models (I'm reaching into the past for terminology there, I think I forgot what they were called) there are lots of lessons here on laracasts. But I look at that spatie package. Consider some helper classes that do all your formatting.

If I have a ton of UI options like that I will always defer to a helper class, all you have to really do is pass in your relevant model or models, and then make your logical functions with all the ugly display logic.

I have a couple of HUGE projects (for me that is) and the thought of going back through all the forms and making UX changes in 100+ places would make me cry.

When people advise deferring that to a wrapper function it's not just giving you an opinion of meaningless A vs meaningless B is better. It's the horrible pain of correcting the mistake that they wish someone had passed on to them before they got into the mess.

Sorry I'm on my phone watching a kids tae kwon-do class so I got talkative.

So find whats driving that notification, it's not the NotifyComment Object or you would already have had access to it. Then look at your blade flies and pull out those conditionals.

if you get stuck you can always try a dd(get_class($notification)); Next year when you upgrade, you'll be thankful you did.

And post that route controller where you are actually passing around the data please if either of those refactors won't work.

18 Oct
2 months ago

Roni left a reply on Use Function From Model In Notifications

ok @slickness I'm trying to help as much as I can but you aren't giving me a whole lot to help you with. Do you want to post it to a public repo? Can you tell me the steps you actually took?

Where exactly you put what? It's probably an easy fix, but I can't address it other than in generalities because all I can see is the comments and not the code.

That error tells me you put the function somewhere, and it's not where it needed to be. So... either I don't understand your file structure.

When you make a notification, the content of the notification class that is public to the class can be accessed by the mail or view. you can move that function to the comment class itself if you like, and then call it directly from the class.

You still need to know oop php scope resolution to know where you have visibility and where you don't. I don't have time to guess at it. If its a private repo, then good luck or post actual files with explanations.

If it's a public repo link it here, and I'll clone it and check it.

Good luck either way.

Roni left a reply on How To Get Sum Score When Checked The Checkboxess?

@Cronix just trying to pay it forward. I'm sure my questions are often confusing too. And yet you still take the time to answer them :)

17 Oct
2 months ago

Roni left a reply on How To Get Sum Score When Checked The Checkboxess?

It's really unclear what exactly you are asking... Can you clarify what you are looking for? What JS are you using? Vue, Vanilla, React etc... Do you need to calculate it in javascript? Or do you want some sort of API endpoint in your laravel backend. What models/tables are involved? Etc... As it reads now it's pretty hard to identify what you are doing now, and what you can't figure out.

Roni left a reply on Use Function From Model In Notifications

@slickness, a suggestion. You look like you are coming from a procedural style background (me too) where you first look at blade and thing awesome and hack it apart with heavy logic.

My first suggestion is actually to read up a bit on what @D9705996 mentioned.

But if you want to go this route of heavy logic in a blade file, maybe turn your Notification into a view model of sorts, and abstract this behavior behind a semantic function.

1. Add some constants to create a more readable request


//these are made up guesses 

//maybe in \App\Privacy

const PUBLIC_VISIBLE = 1;
const GROUP_VISIBLE = 2;
...

const CAN_SEE_USERNAME = [
    self::PUBLIC_VISIBLE,
    self::GROUP_VISIBLE
];


// etc...

then in your notify comment




use App\Privacy; // import constants


//change your constructor

protected $comment;
protected $author; //only to clarify your understanding a bit

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($comment)
    {
        $this->comment = $comment;
    $this->author =-$comment->user(); //you probably have that relationship on your model
    
    // actually you should name it better
    $this->author = $comment->author(); //much more clear
    }


public function displayAuthorName(){


    if( auth()->id() == $this->author->id ||
         in_array($this->author->privacy, Privacy::CAN_SEE_USERNAME)||
         $this->author->isFollowed()) {
    
        return $this->author->username;

    }
    return 'AC';
     
}

Then maybe in your view just render it instead of that whole pile of stuff


{{ $notification->displayAuthorName() }}


Please consider separation of concerns as you grow as a developer. You want your designers designing, and your backend easily upgradable. Look at spatie view models here is a link when you for when you bloat your models and controllers.

https://github.com/spatie/laravel-view-models

in fact look at spatie everything.

Cheers -Roni

Roni left a reply on Regenerating Cart From A Cookie

Hours and a ton of googling later, here is the half way mark...

/** @test */
public function a_guest_cart_is_regenerated_from_cookie_when_there_is_no_session()
    {
        ObjectFactory::validInventoryProduct();
        $oldResponse = $this->get('/');

        $oldCart = session('cart');
        $oldCart->add(1);

        $oldResponse->assertCookie('cart');
        $oldSessionId = session()->getId();

        dump('old session id: '. $oldSessionId);
        dump($oldCart);

        session()->invalidate();

        //NOTICE THIS, you can preset the cookie, but only if you use the "call" method, not the "get" shortcut
        $cookie = ['cart' => \Crypt::encrypt($oldSessionId)];
        $newResponse = $this->call('GET','/',[],$cookie);

        $newCart = session('cart');

        $newResponse->assertCookie('cart');
        $newSessionId = session()->getId();

        dump('new session id: '. $newSessionId);
        dump($newCart);

    }

There are no assertions yet because I can see from the output the second cart is never restored from the session. I can't currently figure out how to restore the old session from the cookie... yet.

Here is the handler now

`` `

16 Oct
3 months ago

Roni left a reply on Use Function From Model In Notifications

there's alot missing to answer this question, however,


return $this->followers()
                ->where('follower_id', auth()->id())->exists();

is returning a boolean based on if the data exists in the DB.

  1. from the code shown above, isFollowed doesn't take a parameter. And if you are only using this function for the authorized user, it doesn't need to so don't add it in your call.

  2. guessing only from the view that


$notification->data['user']['id']

is an integer, it's the user's id not the user object. Is notification->data a collection of users? An array?

If for example it was a collection or array of user objects you could instead use"


foreach (notification->data['user'] as $user) {
    //then do something with the user
    <div>$user->isFollowed()</div> 
}


//you could extract the specific user stuff to a to a view partial or use some functional helpers

$notification->data->pluck('user')->map( function ($user) {
    @include('path.to.user.display')
}


Hope that helps.

Roni started a new conversation Regenerating Cart From A Cookie

Hey, I keep circling back to testing Cookies. I haven't had to use them since I started using TDD, and I feel like I'm missing something.

Right now, I'm trying to perform this test on a middleware that should for guests force a cart on the session.

Using this criteria...

  1. If there is a cart on the session, simply update the expiry of the cookie so it's lifetime is reset.
  2. if there isn't a cart on the session, but there is a session_id stored on the cookie in the cart key, then restore that session (or restore the cart portion of the session, right now . I'm just doing the whole thing, but if you know how to do both options please let me know).
  3. if neither is present (first time on the site) set the session and the cookie.

here is the failing unit test: lots of dumps for clarity, the output will fail and show two different cart objects


   /** @test */

    public function a_guest_cart_is_regenerated_when_they_come_back_to_the_site() {
        $response = $this->get('/');
        $oldCart = session('cart');
        dump($oldCart);
        dump(Cookie::get('cart'));
        session()->invalidate();
        $response = $this->get('/');
        $newCart = session('cart');
        dump($newCart);
        $this->assertInstanceOf(Cart::class, session('cart'));

        $this->assertSame($oldCart, $newCart);
    }

Here is the middleware, which is working, for the no session or cookie phase. Middleware is firing correctly (registered) and routes are properly enclosed in a middleware group. I left all my hacking in there commented out


<?php

namespace App\Http\Middleware;

use App\Orders\Cart;
use Closure;
use Illuminate\Support\Facades\Cookie;

class SessionHasCart
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        if(Cookie::has('cart') && ! session()->has('cart')) {
            session()->setId(Cookie::get('cart'));
            session()->start();
        } elseif(! session()->has('cart')) {
            session()->put('cart', new Cart());
        }

//        $cookie = Cookie::make('cart',session()->getId(),Cart::LIFETIME);
//        dd($cookie);

        return $next($request); //->cookie('cart',session()->getId(),Cart::LIFETIME));
    }
}


Any advice appreciated

09 Oct
3 months ago

Roni left a reply on TDD Cookies

Thanks, very helpful, I should have checked there first.

Roni started a new conversation TDD Cookies

Hi, never had a use for a cookie before, but I never really work on shopping sites. Right now, I have a specialized cart for a series of products that can only be put in by staff, and that is all implemented, but I now need to add in a section of products that can be simply ordered online. So presumably a guest can select items and add them to a cart with no registration. I was thinking about just implementing something simple in a session or in the DB when the user is logged in.

However it seems like a good use case for cookies. So possibly just adding an "cart" key to the site cookie, and putting the value of a cart DTO that looked something like


cookie: { 
    id: session_id,
    cart: {
        products: {
            id: product_id,
            qty: product_id
            price: price
        }
    }

and just setting it either in the controller or on an event listener each time the cart was changed.


Cookie::queue(Cookie::make('cart', $cart, Cart::MINUTES_PER_MONTH));

I haven't implemented it yet, however, I'm not sure how to tdd testing if a cookie is present, or not present. Does anyone know how to test that?

I know response has assertCookie($cookie) and assertCookie expired. Is there a Cookie::fake()?

Any doc references or tutorials appreciated.

29 Sep
3 months ago

Roni started a new conversation Add A Macro To Arrays For Test Assertions

Hey, just a quick question on array assertions. Does anyone know if I can wrap a test in a method/macro that runs on an array?

Right now, I'm using assertTrue(in_array($needs, $responseArray)), but I'd much rather macro it and add something like $responseArray->assertContains($data) and $responseArray->assertDoesNotContain($data);

Is there a way to accomplish that?

Using laravel 5.7

Thanks