miwal

miwal

Uppsala

Member Since 2 Years Ago

Experience Points 45,780
Experience
Level
Lessons Completed 433
Lessons
Completed
Best Reply Awards 0
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.

09 Dec
6 days ago

miwal left a reply on Return Redirect From Function Called By Controller - What Am I Doing Wrong?

I've got this but it's truly horrid:

        if ($redirect = $this->setVoucherIfCodeSupplied($request)) {
            return $redirect;
        }
        if ($redirect = $this->checkUserNotAlreadySubscribed()) {
            return $redirect;
        }
        if ($redirect = $this->createCharge($request)) {
            return $redirect;
        }

then four functions after those that don't need this. the second of the above has this pattern nested inside it (once).

i avoided returning anything from the latter method, instead adding a member variable. ('global state' between the functions).

It works, but I don't like this code at all! Going to look for some other pattern... Suggestions welcome. (and thanks by the way)

miwal started a new conversation Return Redirect From Function Called By Controller - What Am I Doing Wrong?

I have a controller that had to perform about eight different steps and was about 300 lines of code. I knew it's not the only or even the best method, but I decided to break it into a series of functions in the controller and call those functions sequentially. I've set the state they need to share as properties on the controller. Problem is, in some of the steps (now functions), I've assumed that if some check doesn't pass, I can just return a redirect, the same way you would in the controller itself. It turns out this doesn't work.

Problem is I'm already relying on return values from some of those functions.

It looks like I could fix this by handling the return values from the functions appropriately, but that may completely defeat the purpose of simplifying the code.

If this is a fundamental error, I'd like to understand why I've made it.

What are my options?

20 Nov
3 weeks ago

miwal left a reply on Running A Shell Command From Laravel Controller - Is This Code Safe?

Updates: I realised that since the contents of $before and $after are being saved to files, escapeshellarg() is irrelevant. The arguments are the filenames, which are not user input.

Thus, the security question, it seems, is now "Is there any kind of user input which when passed as contents of files to the diff command, would create a vulnerability".

miwal left a reply on Running A Shell Command From Laravel Controller - Is This Code Safe?

thanks @lostdreamer_nl. i'll look into that. would quite like to know how to call a shell command safely though too, so i have the method to reach for if needed in future.

everything's done now for this new feature... would love a code review though of the above before i deploy it ... :)

miwal started a new conversation Running A Shell Command From Laravel Controller - Is This Code Safe?

I have a CMS where I need a simple means of recording changes in case they need to be undone. Rather than store versions which would generate more data than I want, I thought I'd store diffs. Hence I thought of using the shell diff command to compare the text field of a model as currently in the database, with the updated version of that text field as just submitted in the $request, by a user.

What I arrived at was using symfony's Process, and I found it easier to save model fields' before and after state to a file before calling the shell's diff, because diff expects files rather than some incantation using echo, which I tried but couldn't get to work via Symfony's Process.

So, the function I'm calling with model fields looks is as in the listing below. It generates a diff which I then store for later use (e.g. sending an email to an editor who needs to review what has just happened to the content) (a retrospective review - which is fine in this case).

The thing is, this is passing user generated input into the shell, which is potentially dangerous (e.g. injection attacks). I know that's what escapeshellargs() is for -- what I'd really appreciate is a quick code review from experienced hands. Is the below safe?

As a footnote, if I include the if $process->isSuccessful(), it always throws that Exception, even when the diff does seem to work. I'm not sure why that is, which is why I commented it out.

    // IS THIS SHELL EXEC SAFE?
    // - this method is called in a controller
    // - $before and $after are text fields of an eloquent model
    public function diff($before, $after)
    {
        file_put_contents('tmp/before.txt', escapeshellarg($before));
        file_put_contents('tmp/after.txt',  escapeshellarg($after));
        $process = new Process(array('diff', 'tmp/before.txt', 'tmp/after.txt'));
        $process->run();
        // seems to be being thrown unnecessarily: 'general error':
        // if (!$process->isSuccessful()) {
        //     throw new ProcessFailedException($process);
        // }
        return $process->getOutput();
    }
    // https://symfony.com/doc/3.4/components/process.html
    // http://php.net/manual/en/function.file-put-contents.php

miwal started a new conversation Laravel's Json Serialization Vs. Php Serialize()

Is it correct to say that while php does have it's own serialize() function which produces its own form of serialised objects & arrays, e.g., in tinker:

>>> $arr = [1, 2, [ 3, 4]]
=> [
     1,
     2,
     [
       3,
       4,
     ],
   ]
>>> serialize($arr)
=> "a:3:{i:0;i:1;i:1;i:2;i:2;a:2:{i:0;i:3;i:1;i:4;}}"

that laravel in fact doesn't use that, but in fact when it talks about 'serializing' it instead always(?) converts to json, since that's the more popular format at this point. Just wanted to get that ambiguity clear in my head - have I got this correct? thanks.

15 Nov
1 month ago

miwal left a reply on Customise Output Of Queue:work Command?

I tried piping as above but it has not worked correctly and I'm still not clear why despite contacting heroku support. They suggested moving the piped command to a shell script and calling that instead, but that makes no difference. Hence, to close this and move on I've overriden Illuminate\Queue\Console\WorkCommand as you suggested and accept that answer as the best. While it is more code it does have the merit of addressing the issue closer to source. Much thanks @D9705996.

09 Nov
1 month ago

miwal left a reply on Customise Output Of Queue:work Command?

will do when i get the procfile working properly...

miwal left a reply on Customise Output Of Queue:work Command?

Thanks. I'd wondered if a too-specific regex would every really in practice be a performance drag. I guess it depends. While the sed filter does do the match I need, I haven't yet got this really working yet; the log line isn't showing up on logplex, can't find why. I've emailed heroku support -- almost conquered it, but not quite... :-P Thanks for your help :)

miwal left a reply on Customise Output Of Queue:work Command?

Here's the answer!

To strip the timestamp by piping schedule:run to sed in Procfile:

clock: php artisan custom-clock-process | sed 's/\[.*\] /''/'

This is just a simple regex to remove any thing enclosed by [ ].

This would also strip out the job id which > 5.5 puts into stdout, so would need a more detailed regex for that.

custom-clock-process is a daemon that calls schedule:run at the start of each minute, very like cron.

miwal left a reply on Customise Output Of Queue:work Command?

Thanks so much for helping me identify the source - easy when you know where to look! You've given me an idea. Dyno (process) output can be redirected in the Heroku Procfile. e.g. I could send output from scheduler:run (in fact I have a clock process that calls that but it doesn't matter) to > /dev/null if I wanted on heroku. Likewise, I wonder what unix invocation can take that stream and strip out a regex matching the timestamp before it reaches the log multiplexer :) Am going to have a go at this. Thank you so much! (on 5.5. there is only one set of square brackets in the output - the second set enclosing the job_id as in the source you quoted isn't present on 5.5 so my regex will be different/simpler).

miwal started a new conversation Customise Output Of Queue:work Command?

I'm on Heroku and heroku already prefixes timestamps to every log entry when it multiplexes them together from different sources. Hence, I've added a custom monolog configuration as per the laravel docs to remove the double timestamp. This works fine for output which is via the Log:: facade, i.e. monolog. However, queue:work is a command and the output you see in the terminal comes from its own stdout, not via a monolog instance (as far as I can tell). Hence, the app wide custom monolog configuration does not impact it.

Does anyone know a way I can adjust what queue:work will print out? I know there is an event but that would again let you Log:: but not affect the stdout of the command. I guess I could send the command output to > dev/null and remake my own in the event but that sounds a bit dodgy and I need to understand the source.

Any hints much appreciated.

08 Sep
3 months ago

miwal left a reply on What Does Laravel Store In The Payload Field Of The Jobs Table For A Queued Mail?

Thanks martin. I don't currently have any client code that uses laravel queues at all, so it would take more work than that. Thanks for your answer. I was also curious in case anyone wanted to discuss the design questions I raised above, which is the other reason thought it worth making this post.

miwal started a new conversation What Does Laravel Store In The Payload Field Of The Jobs Table For A Queued Mail?

This is a simple question for someone who is already using laravel queues... It's just a question more or less of fact.

I haven't set up the laravel queue system, I've been relying on a rather, I admit, round about method of checking for evidence of mail that needs sending once an hour (on a one off dyno on heroku), rather than actually using any kind of queue.

I'm planning to transition to my own custom queued_mail table, because this will make it a lot more straightforward to schedule mails to be sent incorporating a specified time delay. (It's possible with my fully normalised current method, but I don't look forward to the complexity of the code needed especially if I want to purge the 'queue' often).

I've sketched my own pretty simple queued_mail table, which is going to incorporate some mailgun webhook data on it too to show delivery. I couldn't do that with the laravel jobs table of course, which is more general than simply for 'mail' jobs. I plan to build a focussed queue representation, just for mail.

But with all this, I did php artisan queue:table and am wondering how the jobs table does its stuff. I see it has a payload field. In my own case I could just store the 'name' of the mail I want sent. But what is in payload when the laravel queue is live and running? Is it something large and serialised? Am I right in saying it's not just some flag or other to say which mail (mailable?) needs sending?

I couldn't find this explained in the docs, but there's no real reason it should be, and it would be easy for someone to find by querying the jobs table if they are already running a live queue. Thanks for any info & discussion on this idea!

27 Jul
4 months ago

miwal started a new conversation OK To Mix Web And Api Routes In Same Controller?

Hi,

As a mini-project I'm attempting to reverse engineer the very forum on which you're reading this message. (I know there are series on this, but I'm doing it on my own at this point without referencing a step by step guide: just using the goal I see in front of me (though being honest I have peeked at the schema on jeff's lets build a forum github page)).

Jeff has used web routes for the vast majority of things, rather than ajax. So I have a RepliesController that handles all the crud type web routes.

The first place where he's using ajax I am coming across, that I want to go with, is to toggle the thumbs up mark to mark a question as helpful.

The ajax routes are barred of course from using the web auth (because by definition cookies are not accessible to javascript, that being a foundation of security -- is this the clearest way of putting it?), so must use the JWT via passport, which I'm fine with, but my question is simpler.

I have a controller for Replies, which contains store, update and destroy actions, and want to add toggleHelpful() and toggleBest(). toggleHelpful() is the one that really merits going in as an ajax request as stated above (for the thumbs up). Reason is its just a tiny thing so avoiding a page reload is a tiny bit nice and I'm happy to go with that.

Such a simple question really: is it OK to point an api route to a method in a controller that has mainly web routes in it? Looking at my past projects I've used separate API controllers, like 'API/LessonsApiController'.

My proposed position is: putting the toggleHelpful() method (returning json and using api auth) right in the RepliesController which has all my webroutes seems absolutely fine, as long as its clearly marked that it returns json, not html.

What differentiates the api route other than this is the middleware, but that's defined in the routes file, and it seems fine to put it in the same controller that serves the web routes, rather than create a new api controller for solely this purpose.

Does this sound OK? Any comments from experienced hands here on any aspect of this?

Thanks very much!

26 Jul
4 months ago

miwal left a reply on How To Pass An Array To Vue Through Blade?

I have this kind of thing working, and like you @CGuy, to me using ajax is unnecessary when all we want to do is populate menu items.

As willvincent says, it's good to only print the fields you need into your html and certainly not entire objects including ids (laravel of course has some fields hidden by default, and you can adjust this in the relevant eloquent model - just view page source to see exactly what is going in to your html.)

Hope you got it fixed.

07 May
7 months ago

miwal started a new conversation Use Of Attach() In Method On Model (returns 'void')- Good Style?

I've found that attach() on a belongsToMany returns void: https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Relations/BelongsToMany.html#method_attach

I can either write my method like this:

public function agreeToCurrentTerms() { $this->termsAgreed()->attach(Terms::currentTerms()); } or like this:

public function agreeToCurrentTerms() { return $this->termsAgreed()->attach(Terms::currentTerms()); }

As far as I can tell these are exactly equivalent to the outside world, since the return value is void, and (therefore?) the caller sees 'null' in either case. Is that strictly correct?

Is one better style than the other? Or does it simply not matter?

Thank you!

05 May
7 months ago

miwal left a reply on Session Key Being Set Even For Unlogged Visits? (Redis Session Driver)

Thanks @Cronix for another great answer.

So, if I understand correctly, session only needs an extant client (e.g. a browser), not a logged state. A logged user just means to add authentication on top. And even if a user is "anonymous", we can still track the same visitor's visit to several pages on our site.

So I could just go ahead and use Session:: on public pages that did not assume any Auth::.

Cool... I think there's lots I could potentially do with that.

miwal started a new conversation Session Key Being Set Even For Unlogged Visits? (Redis Session Driver)

I've just been playing about with adding a separate redis instance to store sessions, and found that a key is set as a result even of an unlogged visit.

This conflicts with my understanding of what sessions are supposed to be. Can someone explain? Or point to source which would explain this?

Thank you!

I saw a discussion here which might be about this, but that's for Laravel 4: https://github.com/laravel/framework/issues/726

16 Apr
7 months ago

miwal left a reply on Setting Up Custom Monolog In Bootstrap/app.php

Addendum...

The reason I got into all this is that, on Heroku, I get double timestamps from php logs, because their php adds one, then laravels log adds one on top. So my goal is to zap one or the other. Hence, I've found that config('app.env') is not available at this early point of the application bootstrap, but env('APP_ENV') is.

Hence I've added a switch to keep the timestamp locally, but remove it in production as heroku already adds a timestamp...

Any comments, suggestions, critiques would be very welcome before I deploy this.

Thank you.

The line $output = ... above I've now replaced with this:

    if (env('APP_ENV') === 'local') 
    {
        $output = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";    
    } else {
        $output = "%channel%.%level_name%: %message%\n";
    }

miwal left a reply on Setting Up Custom Monolog In Bootstrap/app.php

Fixed, simple error, I had the paths to those classes wrong. This now works, giving me instant tweakable logging :)

$app->configureMonologUsing(function ($monolog) {

    // the default date format is "Y-m-d H:i:s"
    $dateFormat = "Y n j, g:i a";
    // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
    $output = "%datetime% > %level_name% > %message% %context% %extra%\n";
    // finally, create a formatter
    $formatter = new \Monolog\Formatter\LineFormatter($output, $dateFormat);

    // Create a handler
    $stream = new \Monolog\Handler\StreamHandler(base_path('storage/logs/laravel.log'), \Monolog\Logger::DEBUG);
    $stream->setFormatter($formatter);

    // This code adapted from very foot of page of:
    // https://github.com/Seldaek/monolog/blob/master/doc/01-usage.md
    $monolog->pushHandler($stream);
});

miwal started a new conversation Setting Up Custom Monolog In Bootstrap/app.php

As above I want to be able to customise the log format.

As per the docs I'm adding configureMonologUsing() to bootstrap/app.php

I'm a total newb to Monlog and just want to get started fast. Since I want to customise the log format, I copied code from here.

It's probably something really simple to someone who know show, but I'm getting error Class 'Monolog\\LineFormatter' not found

(I had to find this in the apache logs of my own dev machine, as with my code below the laravel crashes with that error before logging is configured). This is the code that crashes (obviously due to the class not being found. How do find that class at this early stage of application boot (if that's the issue)

Thanks.

$app->configureMonologUsing(function ($monolog) {

    // the default date format is "Y-m-d H:i:s"
    $dateFormat = "Y n j, g:i a";
    // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
    $output = "%datetime% > %level_name% > %message% %context% %extra%\n";
    // finally, create a formatter
    $formatter = new \Monolog\LineFormatter($output, $dateFormat);

    // Create a handler
    $stream = new \Monolog\StreamHandler(__DIR__.'../storage/logs/laravel.log', \Monolog\Logger::DEBUG);
    $stream->setFormatter($formatter);

    // This code adapted from very foot of page of:
    // https://github.com/Seldaek/monolog/blob/master/doc/01-usage.md
    $monolog->pushHandler($stream);
});
12 Apr
8 months ago

miwal started a new conversation Tips For Organising Campaign Emails In A Laravel App?

I'm using Laravel for both transactional emails (which I have no problem with), and also campaign emails. I created a folder structure like this:

app
- Campaigns
  - Commands      <- contains commands to send the mailables
  - Mail                     <- contains Mailables for campaigns

This keeps those Mailables and Commands in their own place and stops them cluttering my other mailables and commands.

The problem is I want the campaign mails I send to build up over time into a manageable order. With the above system, both mail and commands to send them build up in alphabetical order. That has nothing to do with the order these were sent. A listing in chronological order would make sense. But php classes cannot begin with a number, so I can't do that. If I do:

app
- Campaigns
  - Jan
  - Feb
  - ...

Those won't appear in the right order either.

Hmm.... thinking about it, it looks like I might be able to do:

app
- Campaigns
- 18-03     <- for March 2018
- 18-05     <- for April 2018
- ...

Since numbers and hyphens seem to be allowed in directories (and namespaces). Haven't checked those are legal in namespaces (they're not in class names) but look like they could be. Or does anyone know a better way to organise this?

Thank you!

03 Apr
8 months ago

miwal left a reply on How Do Timestamps Become Carbon Objects... (magic Method)?

@cronix interesting that it's comparing two strings.

My first thought was panic, but I see that would actually give the right answer, given a year-month-day format.

Thanks I new that $dates array was there somewhere, don't know why I didn't spot it in the docs.

miwal started a new conversation How Do Timestamps Become Carbon Objects... (magic Method)?

I'm have a timestamp field in a table called subscribed_until. I'm comparing that to Carbon::now()

In tinker, I can do

$user->subscribed_until > Carbon::now()

and it gives me exactly what I want.

I'd love to know what is really happening here though.

If I do dd($user->subscribed_until) I just get the timestamp as a string.

How is php/eloquent working here such that my timestamp field is actually becoming a Carbon object? What's the mechanism by which that works? How can I hack a bit to find out more? It just seems like magic at the moment :)

Thanks.

24 Mar
8 months ago

miwal started a new conversation What's The Point In Customising Plain Text Emails? (i.e. Why Vendor/mail/markdown Is A Publishable Asset)?

I'm just now making first use of Markdown Mailables with Laravel 5.5.

The basic usage in a mailable is of course ->markdown('my-email-view');

I found it important to realise that my-email-view above is not actually pure markdown at all (a misconception of that kind might arise if not thinking carefully), it's a blade file, and you get the ability to write markdown only through use of specific components, e.g. @component('mail::message'), which will parse markdown that is slotted into them.

That was the first thing to get my head around.

Onwards.

If I do vendor:publish on laravel mail, I get two directories.

The first is called html, I'm OK with that. It's to customise the html emails that are generated.

But what is the point of its sibling, the 'markdown' directory (and why is that called 'markdown' and not 'plain-text'? - since it really contains bits that are used to generate only the plain text version of emails (which ->markdown() now generates automatically, unlike '->view()' in a Mailable where you had to also call ->text() to get any plain text version at all).

I see that the 'plain text' versions of emails that laravel provides (when inspected in mailtrap's 'text' and 'raw' tabs) are actually now unparsed (raw) markdown; no comment...! :)

But I'm struggling to understand the reasoning behind publishing that so called 'markdown' directory. Why would I ever want to customise a plain text version of an email? What is there to customise?

Thank you for your thoughts.

13 Mar
9 months ago

miwal started a new conversation Overriding A Method Implemented In A (used) Trait

The trait Illuminate\Foundation\Auth\RegistersUsers contains the following method (I copy it exactly):

    /**
     * The user has been registered.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function registered(Request $request, $user)
    {
        //
    }

The trait is used in RegisterController, in Http/Controllers/Auth

As above the trait contains the above method with an empty method body. Obviously we don't want to change this trait in the framework code in vendor/.

In a video, what Jeff did was implement the method in RegisterController.

I just wanted to get something clear: a trait is a way of doing multiple inheritance, it's obviously not an interface.

In php, if a class uses a trait, and it implements a method that is also implemented in the (multiple inheritance...) trait, do we know for a fact that the method body in the class itself will take precedence over the same method in the trait?

Is that the behaviour being relied upon here?

Jeff doing the above is at 1:20 here: https://laracasts.com/series/lets-build-a-forum-with-laravel/episodes/73

miwal left a reply on Unsubscribe Token - Ok To Have One Permanently Valid Per User?

@shez1983 Aha - yes: anyone could unsubscribe anyone else.

I was wondering why @martinbean used quotation marks around "simplest"!

The other criteria here is the benefit of a uniform approach across a codebase.

Since token (now realise this could usefully be called "secure token" here) is used for password reset, secure token for unsubscribe could be a way to go, if only for consistency and to prevent the minor quibble of anyone being able to unsubscribe anyone else; rather, use of that insecure pattern.

What I might do though is to have the token be null when a user isn't subscribed. When they subscribe (which may or may not happen during registration), I'll create the token, and when they unsubscribe, set it to null.

This way manual inspection of the database is will be a slightly neater experience.

The small benefit of not using a detail table, so long as the token is not too long, is visibility on the users table. Could even use the logic unsubscribe_token is not null to determine subscribed or not... though still need to be sold on the readability of that... hmm... Though if I wanted a timestamp subscribed_at that would scupper that of course.

So if I'm willing to forego the timestamp...

Thanks for sharing the thoughts here.

miwal started a new conversation Unsubscribe Token - Ok To Have One Permanently Valid Per User?

I'm looking at implementing my own unsubscribe link for emails by creating and using an unsubscribe token. Obviously this will be a unique token identifying a particular user.

I note that the built in password_resets table is a detail table off of users, containing a created_at column, which allows the enforcement in code of a particular validity duration. The default for this as set in config/auth being 60 minutes.

To implement unsubscribe, I'm thinking of creating an unsubscribe_token directly on the users table, and creating this at the time of creation of the user record.

This would be one, permanent unsubscribe token per user that is permanently valid and never needs to be refreshed, identifying an unsubscribe request for a particular user.

Are there any conceivable drawbacks to using a token that is permanently valid for this purpose?

I want it as simple as possible but not simpler.

03 Mar
9 months ago

miwal left a reply on The Route::is() Method - How To Find Out ? ...

@skliche great tips there :) merci.

miwal left a reply on The Route::is() Method - How To Find Out ? ...

@sklicke Yes, that works. Thanks. My question, though, was on how to go about finding the information in cases like this... i.e., should I really be using methods when I don't know their origin -- so, how to find where the method comes from.

miwal left a reply on The Route::is() Method - How To Find Out ? ...

So now I have

@if(in_array(Route::currentRouteName(),
        ['minicourses.show', 'topics.show', 'lessons.show', 'questions.show']))
    // includes here ...
@endif

which is a slight improvement. thanks.

miwal started a new conversation The Route::is() Method - How To Find Out ? ...

I'm selectively including a bunch of modals in a blade layout file, and the pattern I'm following is to use @if(Route::is('routename.here')) in which I wrap @include('modal.here').

Now I find I need to apply this to four different routes, so I have:

@if(Route::is('minicourses.show') || Route::is('topics.show') ||
            Route::is('lessons.show') || Route::is('questions.show'))
  // include modals and a few scripts here
@endif 

which is getting a bit unweildy.

I'm wondering whether there is a Route::in([]), so I could do something like: Route::in(['minicourses.show', topics.show', 'lessons.show', 'questions.show' ])

My actual question is, how would I go about finding out whether such a method exists, apart from just trying in the dark to see if something works?

I found this: https://laravel.com/api/5.5/Illuminate/Routing/Route.html

but that doesn't even list the Route::is method I'm already using, so I'm not clear on how to go about finding out this kind of information.

18 Feb
9 months ago

miwal left a reply on Best If Repositories Always Return ->toArray() ?

it all depends on what exactly you are trying to achieve right now

Build a repository that provides both model instances and stdclass objects/arrays. See how it changes the rest of the code

My action now precisely :)

miwal left a reply on Best If Repositories Always Return ->toArray() ?

Thanks @skliche. I tried sketching some client code and see what you mean.

A problem, though, if I do use any of those eloquent calls on a returned model, is it appears the principal benefit on which repositories are being sold, viz. swappability (e.g. to add a caching layer, which is what I had in mind to do with it at this point), will be lost (!?)

(since any call on a returned model will bypass the repository).

A problem... :) Is this a problem with all use of the repository pattern in laravel?

At this point I'd like to see some example repository contracts to compare my needs against, do some drafting and see how it could stack up in reality for my case.

Wonder if it would be useful at this point to try reading the laravel source. Not sure where to start with that though :) I tried a few times and didn't get much leverage on it. Wonder what some of the most accessible parts to start reading first could be? Cheers.

miwal started a new conversation Best If Repositories Always Return ->toArray() ?

Am I right in saying that to implement a repository effectively, I must not return any active records (models).

Reason is, a (perverse) client could do this:

// $lessons is the name of the injected repository

$lesson = $lessons->get($slug);

$any_other_mad_query = $lesson::find('some other lesson');
// this last call circumvents the repository, so if the data layer had been derouted, say, to a mock, or some other implementation of the repository than the database which the model connects to, this would break.

The above code circumvents the repository and breaks separation of concerns. It's what you risk if your repository returns a functioning active record.

To prevent this, repositories should always call ->toArray().

toArray() will unnest even the eloquent collection of models (active records). Here's a summary of the options (I checked):

  • Lesson::first() gives a single model, not a collection.
  • Lesson::all() gives an eloquent collection (extends base collection) containing models.
  • Lesson::first()->toArray() gives a flat array.
  • Lesson::all()->toArray() gives an array of arrays
  •    (both collection and models inside it are unpacked to arrays)
    

Taylor calls ->toArray() when returning from a repository at the start of his book.

I just wanted to get my head around the concept before attempting to implement it, the options available, what to avoid and why.

Comments / clarifications / discussion greatly appreciated.

17 Feb
9 months ago

miwal left a reply on Is There Anything Wrong With Calling Two Gates In Succession, Using ->authorize()?

I was using that one-liner previously, but at the moment I prefer the double if block instead. I know it's longer... but in this case I prefer it... at the moment!

miwal left a reply on Is There Anything Wrong With Calling Two Gates In Succession, Using ->authorize()?

I've settled on this form for maximum avoidance of misreading and clarity:

        Gate::define('deploy-course', function($user) {

            if ($user->isCoordinator())
            {
                if (config('tm.coordinators_can_deploy'))
                {
                    return true;
                }
            }
            return false;
            
        });

Then Gate::allows('deploy-course') in controllers and @can('deploy-course') in views both read crystal clear. Good job.

To summarize, name a gate after the domain action that is being authorized, not the checks necessary to do it.

An important benefit in my opinion comes from never(?) writing authorization logic in controllers as a result, which means you know the bit that matters that you have to test when doing a code audit.

So to answer the title of the original question. YES, there is something wrong with that, because you should use a single domain-action named gate to encapsulate all of your logic, and not build them up in a granular way, because if you do that you loose the chance to abstract and make your client code read at a higher level. i.e. you fail in your conceptual decoupling.

Tada! Comments welcome.

miwal left a reply on Is There Anything Wrong With Calling Two Gates In Succession, Using ->authorize()?

@Nash I just went away from my computer then realised you are spot on with that.

If I think of the name as the action I'm trying to authorize, it is: deploy-course

Looked at this way, the Gate:: syntax is no longer such a dissonance:

Gate::allows('deploy-course)

perfect.

@can('deploy-course') now works for my view, too, rather than being the unreadable guff @can('coordinators-can-deploy') ?!, which it would have been before this change.

I could stick the config variable check in that gate, and either just use a method on user ->isCoordinator() for the other piece of the authz logic, or, which now makes much more sense, put it in the new, declaratively named, gate, in which, it seems, there is now no reason to be afraid of not being an atomic command... oh, sunlight...

The key for me is not being afraid to name the gate declaratively, as the actual domain action you want to authorize, not the pieces of internal logic you're going to use to build that check. Makes sense?

miwal started a new conversation Is There Anything Wrong With Calling Two Gates In Succession, Using ->authorize()?

I'm trying to simplify my authorization code.

I created two simple gates then another which was a combination of the previous two. (Compared to the below, it was is-coordinators-and-coordinators-can-deploy -- yuck).

My thought was to eliminate the compound one, and just call each of the atomic ones separately which then has the same effect.

In the controller actions that use them, it now looks like this:

...
$this->authorize('is-coordinator');
$this->authorize('coordinators-can-deploy');
...

I'm comfortable with putting the authorization logic in the gate, even though it is short, simply because it means less chance of error than were I to write out the needed boolean check off of a config variable every time a controller uses it.

My question is about laravel recommended usage.

I read in the docs that we are supposed to use Gate::allows() to call gates, rather than authorize.

$this->authorize is simply easier to read. There is a 'wtf' millisecond response when i see Gate::allows('is-coordinator'). It doesn't parse in my head well. Maybe my naming is the problem. I haven't solved that.

Is there anything wrong with writing two gates and calling them one after the other with ->authorize()?

14 Feb
10 months ago

miwal started a new conversation Case Sensitivity Difference (in Directory Names) Between Local (mac) And Production (ubuntu) Environments?

Just had an interesting issue having just replaced a live codebase with a newly rebuilt version of my app on 5.5, upgrading from 5.3. (that upgrade's not the issue, though).

I have a directory in Console/ called MailgunCampaigns/ with a single skeleton command at present; where I'm going to add run-once commands which trigger mailgun campaigns probably via the package Bogardo/Mailgun, which gives full api access, including tags so results can be independently tracked & analysed on the mailgun dashboard.

The issue is much simpler, though.

When I do php artisan on my dev machine, I could see all my commands including those that exist just as skeletons at present.

Then I did heroku run bash and php artisan to take a look, on my new deployment.

A command was missing!

After short befuzzlement I noticed a typo. My directory in commands was 'MailgunCampaigns/'. In the console kernel to register autoload of all commands in that directory, I'd spelt it 'MailGunCampaigns' (with capital 'G').

Long story short --- my mac is not case sensitive of the difference and registers the command anyway. --- heroku is case sensitive, and with the identical codebase, the command is not registered.

I've checked this and fixing the case fixes the heroku (ubuntu 16) deployment too.

Wondered if this is a well known thing to experienced hands and if there's anything related that one can be usefully aware of or comments to be made about this.

miwal left a reply on How .version() Really Works In Laravel Mix ?

Ah - I get it. The extreme simplicity of this was eluding me.

I view source of my front end, and, with .version() on, I see:

<link href="/css/front.css?id=4d2008fbca42a70de316" rel="stylesheet">

So in any old browser viewing that page, because that query string will have changed, that's going to cause it to not use what's in the cache (unless perhaps it already has that exact hashed version in its cache - not sure exactly how browser caches work..).

So this seems pretty cool. Not sure why previously (elixir, in 5.3) all that filename versioning was going on... But, thanks for the answer, and I'll just leave it to the experts and get on with my app at this point :)

miwal started a new conversation How .version() Really Works In Laravel Mix ?

Just upgraded to 5.5 from 5.3.

Adding .version() in my webpack.mix.js makes mix-manifiest.json in public/ change from

{
    "/js/back.js": "/js/back.js",
    "/css/front.css": "/css/front.css",
    "/css/back.css": "/css/back.css"
}

to:

{
    "/js/back.js": "/js/back.js?id=3d5fa110caada816e8d3",
    "/css/front.css": "/css/front.css?id=4d2008fbca42a70de316",
    "/css/back.css": "/css/back.css?id=7e816c2769c8d7d585dc"
}

but the file names themselves in public/ are not changed. (Just the query string is added to the call to load them, as above)

This seems to be some clever hashing type thingy which obviates the need to alter the actual filename. This is brilliant, as it reduces junk. But how does that work?

Do browsers now hashcode the file they have in cache and if it doesn't match, re-load it? front.css?id=4d2008fbca42a70de316

Does that mean if a browser didn't know to do this, it would use the stale version?

Just looking for some documentation on this feature. The 5.5. docs seem out of sync, not mentioning this behaviour I am now getting on 5.5

12 Feb
10 months ago

miwal left a reply on Empty Square Brackets After Every Log:: Line On Upgrade To 5.5 - Can They Be Removed?

Hmm... I'll certainly try that @cronix. Thank you.

Also, I was just mucking around and discovered that if I add an empty array as 2nd parameter in the call to Log, then the empty brackets are no longer printed.

i.e. the empty brackets can be removed by changing:

Log::info('------------ ' . Auth::user()->name . ' ------------');

to

Log::info('------------ ' . Auth::user()->name . ' ------------', []);

which then prints as:

app/web.1:  production.INFO: ------------ Logged users name appears here ------------ 

without the empty [].

miwal left a reply on Empty Square Brackets After Every Log:: Line On Upgrade To 5.5 - Can They Be Removed?

Interesting, thanks @Cronix. I've often wondered how to make logs more useful... That's a concrete idea I can try. I tend to heavily log things like payments, with tons of status lines like in the example above with lots of dashes to make them distinctive in the logstream, then other than that just print user names on access to certain key pages, so I have some dim idea of who is on the site on a particular day when just scanning through papertrail. Any other cool ideas for logging?

miwal started a new conversation Empty Square Brackets After Every Log:: Line On Upgrade To 5.5 - Can They Be Removed?

Just upgraded my application from 5.3 to 5.5.

I write quite a few Log::info() status lines to my heroku logstream / papertrail.

Two pairs of empty square brackets now appear at the end of every log line, which are always empty, so have no purpose at all.

Is this now normal? What's the point? Can they be switched off?

I note this issue has existed for others, e.g.: here

It looks like this:

app/web.1:  production.INFO: ------------ Logged users name appears here ------------ [] [] 

(pointless empty brackets at end of line)

Why not on 5.3? Why now? Have I done something wrong?

09 Feb
10 months ago

miwal left a reply on Why ->exists Property Errors Out On Upgrade From 5.3 To 5.5 ?

@talinon Thanks. It helps to know that the norm now is not to rely on presence of an 'empty' eloquent model returned off of a null parameter sent to be route model bound, and so the ability to call ->exists on it. That behaviour does seem strange, and I'm not entirely sure if I invented the ->exists call that used that myself by accident, or if it came from Jeff's community contributions, which was the inspiration for the code above:

https://github.com/laracasts/Hands-On-Community-Contributions/blob/master/app/Http/Controllers/CommunityLinksController.php

In any case, the lesson I take away is it makes more sense not to return an eloquent model that is 'empty' off of a null default, but to return an actual null. L5.5 now does the latter, so case solved, perhaps. Thanks.

I'm not yet a skilled navigator of the laravel source, but if anyone can find this exact change in the source for interest and point it out, kudos for that, would be interesting to see it!