Brownells Launches the Interactive “How to Build an AR-15” Video Series

https://www.thefirearmblog.com/blog/wp-content/uploads/2021/11/unnamed-6-180×180.jpg

Brownells Launches the Interactive "How to Build an AR-15" Video SeriesWith increasing restrictions in regards to firearms on YouTube and other social media platforms, new gun owners and those who are interested in building out their first AR are finding it harder and harder to find reliable and simple instructions for their first AR-15 build. Brownells and the living legend Roy Hill are excited to […]

Read More …

The post Brownells Launches the Interactive “How to Build an AR-15” Video Series appeared first on The Firearm Blog.

The Firearm Blog

Database and Eloquent ORM: New features and improvements since the original Laravel 8 release (1/2)

https://protone.media/img/header_social.jpg

Database and Eloquent ORM: New features and improvements since the original Laravel 8 release (1/2)

In this series, I show you new features and improvements to the Laravel framework since the original release of version 8. Last week, I wrote about the Collection class. This week is about the Database and Eloquent features in Laravel 8. The team added so many great improvements to the weekly versions that I split the Database and Eloquent features into two blog posts. Here is part one!

I got most code examples and explanations from the PRs and official documentation.

v8.5.0 Added crossJoinSub method to the query builder (#34400)

Add a subquery cross join to the query.

use Illuminate\Support\Facades\DB;

$totalQuery = DB::table('orders')->selectRaw('SUM(price) as total');

DB::table('orders')
    ->select('*')
    ->crossJoinSub($totalQuery, 'overall')
    ->selectRaw('(price / overall.total) * 100 AS percent_of_total')
    ->get();

v8.10.0 Added is() method to 1-1 relations for model comparison (#34693)

We can now do model comparisons between related models, without extra database calls!

// Before: foreign key is leaking from the post model
$post->author_id === $user->id;

// Before: performs extra query to fetch the user model from the author relation
$post->author->is($user);

// After
$post->author()->is($user);

v8.10.0 Added upsert to Eloquent and Base Query Builders (#34698, #34712)

If you would like to perform multiple “upserts” in a single query, then you may use the upsert method instead of multiple updateOrCreate calls.

Flight::upsert([
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);

v8.12.0 Added explain() to Query\Builder and Eloquent\Builder (#34969)

The explain() method allows you to receive the explanation from the builder (both Query and Eloquent).

User::where('name', 'Illia Sakovich')->explain();

User::where('name', 'Illia Sakovich')->explain()->dd();

v8.15.0 Added support of MorphTo relationship eager loading constraints (#35190)

If you are eager loading a morphTo relationship, Eloquent will run multiple queries to fetch each type of related model. You may add additional constraints to each of these queries using the MorphTo relation’s constrain method:

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphTo;

$comments = Comment::with(['commentable' => function (MorphTo $morphTo) {
    $morphTo->constrain([
        Post::class => function (Builder $query) {
            $query->whereNull('hidden_at');
        },
        Video::class => function (Builder $query) {
            $query->where('type', 'educational');
        },
    ]);
}])->get();

v8.17.2 Added BelongsToMany::orderByPivot() (#35455)

This method allows you to directly order the query results of a BelongsToMany relation:

class Tag extends Model
{
    public $table = 'tags';
}

class Post extends Model
{
    public $table = 'posts';

    public function tags()
    {
        return $this->belongsToMany(Tag::class, 'posts_tags', 'post_id', 'tag_id')
            ->using(PostTagPivot::class)
            ->withTimestamps()
            ->withPivot('flag');
    }
}

class PostTagPivot extends Pivot
{
    protected $table = 'posts_tags';
}

// Somewhere in a controller
public function getPostTags($id)
{
    return Post::findOrFail($id)->tags()->orderPivotBy('flag', 'desc')->get();
}

The sole method will return the only record that matches the criteria. If no records are found, a NoRecordsFoundException will be thrown. If multiple records were found, a MultipleRecordsFoundException will be thrown.

DB::table('products')->where('ref', '#123')->sole()

v8.27.0 Allow adding multiple columns after a column (#36145)

The after method may be used to add columns after an existing column in the schema:

Schema::table('users', function (Blueprint $table) {
    $table->after('remember_token', function ($table){
        $table->string('card_brand')->nullable();
        $table->string('card_last_four', 4)->nullable();
    });
});

v8.37.0 Added anonymous migrations (#36906)

Laravel automatically assign a class name to all of the migrations. You may now return an anonymous class from your migration file:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up()
    {
        Schema::table('people', function (Blueprint $table) {
            $table->string('first_name')->nullable();
        });
    }
};

v8.27.0 Add query builder map method (#36193)

The new chunkMap method is similar to the each query builder method, where it automatically chunks over the results:

return User::orderBy('name')->chunkMap(fn ($user) => [
    'id' => $user->id,
    'name' => $user->name,
]), 25);

v8.28.0 ArrayObject + Collection Custom Casts (#36245)

Since the array cast returns a primitive type, it is not possible to mutate an offset of the array directly. To solve this, the AsArrayObject cast casts your JSON attribute to an ArrayObject class:

// Within model...
$casts = ['options' => AsArrayObject::class];

// Manipulating the options...
$user = User::find(1);

$user->options['foo']['bar'] = 'baz';

$user->save();

v8.40.0 Added Eloquent\Builder::withOnly() (#37144)

If you would like to override all items within the $with property for a single query, you may use the withOnly method:

class Product extends Model{
    protected $with = ['prices', 'colours', 'brand'];

    public function colours(){ ... }
    public function prices(){ ... }
    public function brand(){ ... }
}

Product::withOnly(['brand'])->get();

v8.41.0 Added cursor pagination (aka keyset pagination) (#37216, #37315)

Cursor-based pagination places a “cursor” string in the query string, an encoded string containing the location that the next paginated query should start paginating and the direction it should paginate. This method of pagination is particularly well-suited for large data sets and “infinite” scrolling user interfaces.

use App\Models\User;
use Illuminate\Support\Facades\DB;

$users = User::orderBy('id')->cursorPaginate(10);
$users = DB::table('users')->orderBy('id')->cursorPaginate(10);

v8.12.0 Added withMax, withMin, withSum and withAvg methods to QueriesRelationships (#34965, #35004)

In addition to the withCount method, Eloquent now provides withMin, withMax, withAvg, and withSum methods. These methods will place a {relation}_{function}_{column} attribute on your resulting models.

Post::withCount('comments');

Post::withMin('comments', 'created_at');
Post::withMax('comments', 'created_at');
Post::withSum('comments', 'foo');
Post::withAvg('comments', 'foo');

Under the hood, these methods use the withAggregate method:

Post::withAggregate('comments', 'created_at', 'distinct');
Post::withAggregate('comments', 'content', 'length');
Post::withAggregate('comments', 'created_at', 'custom_function');

Comment::withAggregate('post', 'title');
Post::withAggregate('comments', 'content');

v8.13.0 Added loadMax, loadMin, loadSum and loadAvg methods to Eloquent\Collection. Added loadMax, loadMin, loadSum, loadAvg, loadMorphMax, loadMorphMin, loadMorphSum and loadMorphAvg methods to Eloquent\Model (#35029)

In addition to the new with* method above, new load* methods are added to the Collection and Model class.

// Eloquent/Collection
public function loadAggregate($relations, $column, $function = null) {...}
public function loadCount($relations) {...}
public function loadMax($relations, $column)  {...}
public function loadMin($relations, $column)  {...}
public function loadSum($relations, $column)  {...}
public function loadAvg($relations, $column)  {...}

// Eloquent/Model
public function loadAggregate($relations, $column, $function = null) {...}
public function loadCount($relations) {...}
public function loadMax($relations, $column) {...}
public function loadMin($relations, $column) {...}
public function loadSum($relations, $column) {...}
public function loadAvg($relations, $column) {...}

public function loadMorphAggregate($relation, $relations, $column, $function = null) {...}
public function loadMorphCount($relation, $relations) {...}
public function loadMorphMax($relation, $relations, $column) {...}
public function loadMorphMin($relation, $relations, $column) {...}
public function loadMorphSum($relation, $relations, $column) {...}
public function loadMorphAvg($relation, $relations, $column) {...}

v8.13.0 Modify QueriesRelationships::has() method to support MorphTo relations (#35050)

Add a polymorphic relationship count / exists condition to the query.

public function hasMorph($relation, ...)

public function orHasMorph($relation,...)
public function doesntHaveMorph($relation, ...)
public function whereHasMorph($relation, ...)
public function orWhereHasMorph($relation, ...)
public function orHasMorph($relation, ...)
public function doesntHaveMorph($relation, ...)
public function orDoesntHaveMorph($relation,...)

Example with a closure to customize the relationship query:

// Retrieve comments associated to posts or videos with a title like code%...
$comments = Comment::whereHasMorph(
    'commentable',
    [Post::class, Video::class],
    function (Builder $query) {
        $query->where('title', 'like', 'code%');
    }
)->get();

// Retrieve comments associated to posts with a title not like code%...
$comments = Comment::whereDoesntHaveMorph(
    'commentable',
    Post::class,
    function (Builder $query) {
        $query->where('title', 'like', 'code%');
    }
)->get();

Laravel News Links

The First Look at Netflix’s Live-Action Gundam Movie Is Here and Is Wild

https://i.kinja-img.com/gawker-media/image/upload/c_fill,f_auto,fl_progressive,g_center,h_675,pg_1,q_80,w_1200/500dd1ed958ca3ec4c3b1d977918acea.jpg

A giant Gundam robot strolls through fire.
Image: Sunrise/Netflix

It’s been more than three years since Legendary Pictures and Sunrise announced they would collaborate on a live-action movie based on the venerable franchise Mobile Suit Gundam, the giant robot anime whose shadow all others stand in. Today, we have our first look at Netflix’s film—a sole piece of concept art—and it’s probably not what you were expecting.

Yeah, the image up top of a Gundam walking away from a massive conflagration of fire like basically every action star ever? That’s it, which comes courtesy of the VFX whizzes at Industrial Light and Magic.

We knew that the film would be directed by Kong: Skull Island’s Jordan Vogt-Roberts, who’s also currently on board to direct the live-action movie adaptation of the Metal Gear Solid video game. The movie is being produced by Legendary Pictures, which made Skull Island and the recent spate of Godzilla films, so the studio is doing big business with films starring giants of various types. Even better, the script is by Brian K. Vaughan, who’s written the incredible Saga comic among many others. Basically, there’s every reason to believe Gundam’s (second) foray into live-action will be very, very good.

But boy, that giant robot sure looks like Nic Cage walking away from an explosion, or at least one of the countless action stars who have badassedly walked away from any scene of massive destruction happening right behind them. It’s weird because it does seem to be somewhat celebrating how awesome war is, when the original Mobile Suit Gundam is so focused on the trauma war inflicts on people, especially Amuro Ray, the teenager who inadvertently becomes the Gundam’s pilot and gets swept up in the war between Earth and the space-bound Principality of Zeon. Still, it’s only a single image, and that image looks very good. If it seems a bit off-brand for the very first look, whatever. Since Netflix’s live-action Gundam movie still has no release date, we clearly have plenty of time to see more.


Wondering where our RSS feed went? You can pick the new up one here. 

G/O Media may get a commission

All colors on sale today
Gizmodo describes these premium headphones as “annoyingly incredible.” This is the lowest we’ve seen the Apple AirPods Max yet.

Gizmodo

How Stetson Cowboy Hats Are Made

https://theawesomer.com/photos/2021/11/how_stetson_hats_are_made_t.jpg

How Stetson Cowboy Hats Are Made

Link

Stetson has made some of the best and most desirable hats since the 1800s. Their cowboy hats are beloved, though some can cost up to $5000. Business Insider provides a look at Stetson hat factory to see what makes these hats so special. One big difference is that the produce their own felt in-house.

The Awesomer

Explosive Admission at Rittenhouse Trial – Video

https://www.ammoland.com/wp-content/uploads/2021/11/Facepalm-by-prosecutor-Krautz-after-Grosskruetz-says-he-was-pointing-gun-at-Rittenhouse-when-he-is-shot-1000-500×368.jpg

U.S.A.-(AmmoLand.com)- On day six of the Kyle Rittenhouse trial in Kenosha, Wisconsin, November 8, 2021, the court video captured a particularly dramatic moment.

Gaige Grosskreutz has given testimony as a prosecution witness. He is being cross-examined by Corey Chirafisi, a defense attorney. It occurs about 2 hours and 27 minutes into this trial video on November 8, 2021. Over the next few minutes, there is this exchange:

Defense attorney Corey Chirafisi:

So, your hands are up, and at that point he (Rittenhouse) has not fired. Correct?

Gaige Grosskreutz:

No he has not.

Defense attorney Corey Chirafisi:

Do you agree at this point, you are dropping your hands, you are loading up your left foot, and you are moving toward Mr. Rittenhouse, at that point, True?

Gaige Grosskreutz:

Yes. 

Defense attorney Corey Chirafisi:

So, When you were shot; Can you bring up the photo? Do you agree, and now wait, how close were you, in the… How close were you, from the background.

Gaige Grosskreutz:

Three feet. If I was five feet before, so

Defense attorney Corey Chirafisi:

At this point, you are holding a loaded chambered Glock 27 in your right hand, Yes?

Gaige Grosskreutz:

That is correct, yes.

Defense attorney Corey Chirafisi:

You are advancing on Mr. Rittenhouse, who is seated on his butt, right?

Gaige Grosskreutz:

That is correct.

Defense attorney Corey Chirafisi:

 You are moving forward and your right hand drops down so your gun, your hands are no longer up, your hand has dropped down and now your gun is pointed in the direction, at Mr. Rittenhouse, agreed?  I will give you another  (exhibit?), and maybe that will help.

Defense attorney Corey Chirafisi:

So Mr. Grosskruetz, I am going to show you what has has been marked as exhibit #67.

exhibit #67 from Rittenhouse Trial

That is a photo of you, Yes?

Gaige Grosskreutz:

Yes.

Defense attorney Corey Chirafisi:

That is Mr. Rittenhouse?

Gaige Grosskreutz:

Correct.

Defense attorney Corey Chirafisi:

Do you agree your firearm is pointed at Mr. Rittenhouse? Correct?

Gaige Grosskreutz:

 Yes.

Defense attorney Corey Chirafisi:

 Ok. And, Once your firearm is pointed at Mr. Rittenhouse, that’s when he fires, Yes?

Gaige Grosskreutz:

Yeah.

Defense attorney Corey Chirafisi:

Does this look like right when he was firing the shot?  (#67, moment of Rittenhouse’s shot)

Gaige Grosskreutz:

That looks like my bicept being vaporized, yes.

Defense attorney Corey Chirafisi:

And it was vaporized at the time you are pointing your gun directly at him?

Gaige Grosskreutz:

Yes.

Defense attorney Corey Chirafisi:

When you were standing 3-5 feet from him, with your arms up in the air, he never fired? Right?

Gaige Grosskruetz:

Correct.

Defense attorney Corey Chirafisi:

It wasn’t until you pointed your gun at him, advanced on him,  with your gun, now your hand is down, pointed at him, that he fired? Right?

Gaige Grosskreutz:

Correct. 

The camera is pointed at Gaige Grosskreutz, We cannot see the prosecutor’s table. The camera then shows Kyle Rittenhouse for a few seconds. Then it shows the prosecutor’s table.  A dramatic image is captured, which will probably become an iconic graphic of images you do not want to present at court.

Prosecutor’s table, Kraus, left, Binger with glasses, right

Of interest, Gaige Grosskreutz showed significant function in his right arm and hand. He was able to hold and raise a water bottle, and the microphone easily, with considerable fine motor control in his fingers.

Becky Sullivan, National Public Radio (NPR) reporter and producer, who misreported information about a critical juncture of the shooting of Joseph Rosenbaum, in the Rittenhouse trial, had this take on the Gaige Grosskreutz testimony. From NPR:

 |  WBOI-FM

Updated November 8, 2021 at 3:27 PM ET

Gaige Grosskreutz, the only person who survived being shot by Kyle Rittenhouse last year at a chaotic demonstration in Kenosha, Wis., took the stand in a pivotal moment in Rittenhouse’s homicide trial. In three hours of dramatic testimony Monday, Grosskreutz, 27, acknowledged that he was armed with a pistol on the evening of Aug. 25, 2020, but said that his hands were raised when Rittenhouse raised his rifle at him and that he feared for his life.

Ms. Sullivan failed to mention Gaige Grosskreutz testified he was pointing his pistol at Kyle Rittenhouse when Kyle shot him.

The trial has had another day, where the prosecution witnesses appear to be defense witnesses.


Complete Live Trial Video:


About Dean Weingarten:

Dean Weingarten has been a peace officer, a military officer, was on the University of Wisconsin Pistol Team for four years, and was first certified to teach firearms safety in 1973. He taught the Arizona concealed carry course for fifteen years until the goal of Constitutional Carry was attained. He has degrees in meteorology and mining engineering and retired from the Department of Defense after a 30-year career in Army Research, Development, Testing, and Evaluation.

Dean Weingarten

AmmoLand.com

The Visitor Pattern in PHP

https://doeken.org/assets/img/visitor-pattern.jpg

The Visitor Pattern isn’t used often. This is because there are few situations in which it is applicable or even makes sense. However, it’s a nice pattern to know and to have in your tool belt when the time comes. Let’s look at how this pattern can be applied in a PHP environment.

🛑 The problem

Like a few other patterns, the Visitor Pattern tries to solve the problem of adding functionality to an entity without changing it (much…). In addition to this very generic problem, it provides a way of adding the functionality to multiple similar entities, which can’t be completely handled in the same way.

So let’s make the problem a bit more practical. Imagine you have two entities: Book and Document. And for both of these entities we want to know how many pages there are. Our Document has a public function getPageCount(): int which returns the number of pages, while the Book consists of an array of Chapter entities, which also have this function.

class Document

{

public function __construct(private int $page_count) {}

 

public function getPageCount(): int

{

return $this->page_count;

}

}

 

class Chapter extends Document

{

// Chapter specific code

}

 

class Book

{

public function getChapters(): array

{

return [

new Chapter(5),

new Chapter(7),

new Chapter(2),

];

}

}

To streamline the process of returning the page count for either of these entity types, we create a PageCountDumper. A (somewhat naive) implementation of this could look like this:

class PageCountDumper

{

public function handle($entity)

{

if ($entity instanceof Document) {

var_dump($entity->getPageCount());

} elseif ($entity instanceof Book) {

$count = 0;

 

foreach ($entity->getChapters() as $chapter) {

$count += $chapter->getPageCount();

}

 

var_dump($count);

} else {

throw new \InvalidArgumentException('PaperCalculator can not handle the provided type.');

}

}

}

And we can call it like this:

$document = new Document(20);

$book = new Book();

 

$dumper = new PageCountDumper();

 

$dumper->handle($document); // int(20)

$dumper->handle($book); // int(14)

This PageCountDumper has a handle() function that can handle both the Book and the Document entity, and will var_dump the proper page count for both. There are however a few things that stand out:

  • Because there is no shared interface or abstraction between Document and Book, the handle() function receives a mixed $entity and contains the logic for either situation. When adding on more entities, this type checking will pile on and can become quite cumbersome and unreadable.
  • We throw an exception when the entity type is unknown to avoid improper use.

We can do better!

👋 The Visitor Pattern Solution

So the Visitor Pattern provides a solution for this particular problem. It will remove the need for the instanceOf type checks, while keeping the reference to the entity type intact. And it will remove the need to explicitly throw an exception. Let’s see how the Visitor pattern tackles these issues.

Entity specific functions

First off, to remove the instanceOf checks, it requires a method for every possible entity type. For convention’s sake, we’ll call these methods: visitBook(Book $book) and visitDocument(Document $document). And because we are creating a Visitor let’s rename the calculator to: PageCountVisitor.

class PageCountVisitor

{

public function visitBook(Book $book)

{

$count = 0;

 

foreach ($book->getChapters() as $chapter) {

$count += $chapter->getPageCount();

}

 

var_dump($count);

}

 

public function visitDocument(Document $document)

{

var_dump($document->getPageCount());

}

}

By implementing separate methods, with type-hinted arguments, we’ve removed the need for the instanceOf checks. And because we can only call these methods with the appropriate type, there is no need to throw an exception. PHP would already do so when we provide an invalid argument.

If there is another entity in the future that needs its pages to be counted, let’s say a Report, we can add a pubilc function visitReport(Report $report) and implement that logic separately.

But, you might be thinking: This isn’t better. I still need to know what type my entity is in order to call the correct method!. And you would be correct. But hold on, this refactoring is only half of the visitor pattern.

Accepting a visitor

Remember when I said the entities the visitor works on should not be changed much? Yeah, well; there is one change that is needed on every entity to make the Visitor Pattern work. But only one, and this will make it accept any visitor, and therefore add any (future) functionality.

To avoid the instanceOf check, there is only one context in which we can be sure the entity is of a certain type: within the entity itself. Only when we are inside a (non-static) method of a class, we know for certain that $this is an instance of that type. That is why the Visitor Pattern uses a technique called Double Dispatch, in which the entity calls the correct function on the visitor, while providing itself as the argument.

To implement this double dispatch we need a generic method that receives the visitor, and relays the call to the correct method on the visitor. By convention this method is called: accept(). This method will receive the visitor as its argument. In order to accept other visitors in the future, we first extract a VisitorInterface.

interface VisitorInterface

{

public function visitBook(Book $book);

 

public function visitDocument(Document $document);

}

 

class PageCountVisitor implements VisitorInterface

{

// Make sure the visitor implements the interface

}

Then we create a VisitableInterface and apply it on Book and Document.

interface VisitableInterface

{

public function accept(VisitorInterface $visitor);

}

 

class Book implements VisitableInterface

{

// ...

public function accept(VisitorInterface $visitor)

{

$visitor->visitBook($this);

}

}

 

class Document implements VisitableInterface

{

// ...

public function accept(VisitorInterface $visitor)

{

$visitor->visitDocument($this);

}

}

Here you can see the double dispatch in action. The Book class calls the visitBook() method on the visitor and Document calls visitDocument(). Both are providing themselves as the parameter. Because of this minor change to the entity we can now apply all kinds of different visitors that provide a certain functionality for every entity.

To use the visitor on the entities we need to adjust our calling code like this:

$document = new Document(20);

$book = new Book();

 

$visitor = new PageCountVisitor();

 

$document->accept($visitor); // int(20)

$book->accept($visitor); // int(14)

With all the pieces now in place, we are free to create more visitors that implement the VisitorInterface and can perform a certain feature for both Book and Document. A WordCountVisitor for example.

Pros & cons

Like many other patterns, the Visitor Pattern isn’t the one pattern to rule them all. There are multiple solutions to different problems. The Visitor Pattern is just that; a possible solution to a specific problem. Let’s look at some reasons you might use it, and some reasons you might not.

✔️ Pros

  • You can add functionality to any entity by implementing the VisitableInterface once. This makes the entity more extendable.
  • By adding visitors the functionality you enforce separation of concern.
  • The entity is in control whether the visitor is accepted. You can omit the relay and cut the double dispatch.
  • The individual visitors are easier to test.

❌ Cons

  • The double dispatch can be confusing and make the code harder to understand.
  • The accept() and visit...() methods usually don’t return anything, so you need to keep records on the visitor itself.
  • All Visitors need every method on the VisitorInterface while it might not have an implementation for it.

Real world examples

Realistically, you aren’t likely to find this pattern much in the wild. However, it is a common practice in combination with Trees and Tree Traversal.

If you are unfamiliar with Trees & Tree Traversal, you can check out my previous blog on that.

When traversing a Tree, you are iterating over a continuous stream of Nodes. We can perform an action for every node in that Tree. This is called visiting… coincidence? These nodes are usually just an entity holding a value. Instead of adding a bunch of methods to these nodes; it’s actually a nice way of adding different features to these otherwise dumb entities.

Some tree implementations I’ve seen actually have A PreOderVisitor and a PostOrderVisistor. These will then return an array of nodes in that order. While that is a perfectly acceptable visitor, I believe a Visitor should not dictate the order in which it is applied to the tree. For some features it might not even matter what the traversal order is, while in some cases it might.

In my Trees & Tree Traversal post I gave the example of a document inside a tree structure. When traversing that tree in PreOrder you get a logical flow of the document; starting at the cover page. Some visitors we might want to build for that tree are:

  • RenderPdfVisitor which could render every node as a PDF file.
  • TableOfContentsVisitor which could create a table of contents with the correct page numbering.
  • CombinePdfVisitor which could combine every previously rendered PDF into a single PDF document.

And basically every example from that blog post can be build as a visitor.

Thanks for reading

Like I said, the Visitor Pattern isn’t very common, but it’s nice to have up your sleeve. Do you have any experience with this pattern? Please let me know in the comments. I’m curious to hear what you think of it.

I hope you enjoyed reading this article! If so, please leave a 👍 reaction or a 💬 comment and consider subscribing to my newsletter! I write posts on PHP almost every week. You can also follow me on 🐦 twitter for more content and the occasional tip.

Laravel News Links

Security in Laravel: How to Protect Your App

https://static.adevait.com/2021/10/Social-Sharing-photo-Template-1.jpg

Security is always a concern when you are developing a web application.

Not only do you need to think about the security features and vulnerabilities, but also about the possible issues that might appear during the process.

There are a lot of segments that need to be covered and taken care of if you want your application to be secure.

Fortunately, tools like the Laravel framework provide us with a lot of good practices and excellent features. So, if you are building your application using this framework, you can rest assured that the Laravel security package will deliver the results you want.

In this text, we are going to dive into these Laravel security features, and other out-of-the-box practices. We will take a close look into their implementation to understand how we can protect our application.

Checklist

  • Code injections
    • SQL injections
    • XSS attacks
  • Requests origin
  • Exposed files
  • A weak login implementation
  • The right configuration for your environment
  • Software/packages updates
  • Passwords vulnerabilities
  • Prevent CSRF attack
  • Prevent DOS attack
  • Security tips

Code Injections

SQL Injections

In plain PHP, we need to bind all the parameters on SQL queries. But in Laravel, we have the query builder and Eloquent ORM that provides automatic protection against SQL injections by adding param binding by default. Even with this, you should watch out for malicious requests, like for example:

User::query()->create($request->all());

This code could lead to a mass assignment. In this case, a user can send a payload like this:

{
    "name": "John Doe",
    "email": "[email protected]",
    "role_id": "admin" 
}

Another code that could lead to the same issue could be:

$user->fill($request->all());
$user->save();

In this example, we are hydrating an eloquent model with all the data from a request and then saving it.

A malicious user can try with different payloads. Or, they can add extra inputs with different names and try to find a weak implementation like this.

Hopefully, with this example, we can see that we need to take care of mass assignments. We cannot trust any user request, because any user can open the browser inspector and add an input in a monolith or modify the payload from an API.

Laravel provides different ways to handle this:

Set Fillable Property

We can prevent mass assignment by adding explicitly the fields that a model contains by using protected properties, “fillable” or “guarded”:

protected $fillable = ['name', 'email', 'password', 'role_id'];

In this case, we are adding explicitly the columns that a model contains. You can use the guarded property as an empty array. Personally, I do not like this approach as many projects have more than one developer and there is no guaranty that other developers would validate the data.

The forceFill() method can skip this protection, so take care when you are using this method.

Validate Request Data

You should validate any type of resource no matter where it came from. The best policy is to not trust the user. Laravel provides FormRequest so we only need to create one with artisan:

php artisan make:request UserRequest

You can define the rules to validate your requests:

public function authorize() 
{
    return $this->user()->check(); 
} 

public function rules() 
{     
    return [
        'name' => ['required', 'string', 'min:5', 'max:255'],
        'email' => ['required', 'email', 'unique:users'],
        'password' =>   ['required', Password::default()]
    ]; 
}

The authorize method must return a boolean. It is a convenient way to return an authorization validation before starting to validate the requested content. This is something to take in mind and it would apply in any route that has the middleware auth for web or sanctum/API if you are using token-based authentication.

The rules method returns an array with the rules that are validating your request. You can use a lot of rules out of the box or create your own custom rules. If you are interested to dive in deeper into this topic, you can find all the rules in the doc: https://laravel.com/docs/8.x/validation#available-validation-rules.

XSS Attack

This attack could be divided into two sections. The first one restricts special tags on the server and does not return special tags in the views.

Restrict Special Tags in the Server

You could use different approaches. PHP natively has some methods like strip_tags that only protect against HTML and PHP tags. You can even use a regex or use the PHP native method htmlentities() or filter_var both, although it does not protect completely against all the possible tags. In this case, my best recommendation is to use a specific package to solve this, like HTML Purifier.

Does Not Return Special Tags in the Views

If you are working with the Blade template engine, you should take care about how you are printing your data in your template:

<p></p>

The double mustaches syntax would protect you against XSS attacks by automatically escaping the tags for you.

<p>{!! $user->name !!}</p>

On the other hand, this syntax is dangerous. If you do not trust the data that could come, do not use it because the bang-bang syntax could interpret PHP.

Using Another PHP Template Engine

Laravel also provides an escape method that we use on any other template engine like Twig:

Using a Javascript Framework

Any modern Javascript framework automatically protects us to inject a script. VueJS, for example, has a v-html directive that already protects us against this type of attack.

Request Origin

In your application, you can get requests from multiple sites. It could be a webhook, a mobile application, requests from a Javascript project, etc.

In these cases, we should take a defensive approach. A lot of antiviruses are great examples that a non-trust list simply does not work as we cannot keep updating different origins and sites all the time. In this case, a trust list can be the best approach to only validate some origins.

In short, a trust list could work if we know the origins that we are going to allow. But what if we do not?

Maybe an unknown origin could try to send unauthenticated requests. In this case, Laravel once again provides a great tool out of the box. We can use the throttles middleware to protect a route or group of routes from malicious requests. This is one of Laravel’s security best practices to consider.

Route::get('dashboard', DashboardController::class)    ->middleware('throttle:3,10');

The param:3,10 represents that it allows 3 requests during 10 minutes. At the fourth request, it would throw an error 429 in the browser. If it is a request that has a content-type: application/json and accept: application-json, it would return a response with 429 status and a message with the exception.

You can go even further and add a RateLimiter on the app/Providers/RouteServiceProvider.php:

protected function configureRateLimiting() 
{  
    RateLimiter::for('global', function (Request $request) {
        return Limit::perMinute(1000);     
    }); 
}

Then in your route file, you can define a route like this:

Route::get('dashboard', DashboardController::class)->middleware('throttle:global');

If you want to dive deeper into the rate limiter, you can visit this resource. And if you want to get something more robust in terms of a trusts list, here is a great package for adding a white list implementation.

Do Not Trust Sites Without an SSL Certificate

A site that does not have an SSL certificate should not be allowed. No data should be sent without proper encrypted channels as this could lead to a potential man-in-the-middle attack where your data can be exposed.

Lastly, do not share session ids or cookies with insecure connections that do not use the HTTPS protocol. Doing so can also expose sensitive data.

Exposed Files

By default, Laravel only exposes the public directory. This is intended to avoid security breaches. Considering that any file that will be exposed can be accessed by anyone, you should avoid adding their sensitive data.

If you want to expose files to download, the best way to do this is by keeping the files on the storage directory and just adding a symbolic link on a public directory. Laravel provides a command to make it easier:

php artisan storage:link

Now, any file that your app stores in the storage directory will be available. Avoid adding manual permissions to any other directory as this could lead to a potential breach.

Weak Login Implementation

All the authentication workflow, register, forgot password, login, etc, are steps that require utmost attention. For example, if you return a specific message for any field that does not match in a login form, the attacker could know exactly when an email already exists in the database.

One of the strengths of the Laravel ecosystem is that they offer a lot of packages to work with authentication: 

  • laravel/ui – basic authentication, comes with blade views and bootstrap css
  • laravel/breeze – basic authentication, comes with blade views or inertiaJS components, use tailwindcss for styles
  • laravel/jetstream – basic authentication, user profile, 2FA, teams, comes for livewire and inertiaJS stacks, use tailwindcss for styles
  • laravel/fortify – authentication backend logic without any ui preset
  • laravel/passport – full JWT authentication (most of the time over engineer)
  • laravel/sanctum – api tokens authentication with scopes

In this case, a good practice would be to use a package that meets your needs, has official support, and has contributions from the community.

The Right Configuration For Your Environment

Let’s imagine that you push your code to the production environment, and in your production .env file, you set the key APP_ENVIRONMENT=local and APP_DEBUG=true.

In this case, every time that your app throws an error, it would show the stack trace of the exception and it would probably reveal more than you would like.

A stack trace screen would appear to any potential attacker. The technology that is used on the project – the database table and its structure, and the application directory structure – shows there might be more vulnerabilities to explode. With this in mind, take care of the environment file values, but take special care of those two keys.

Software/Packages Updates

By the time your project dependencies get updated, the package authors or the community could find vulnerabilities, like a patch, for example. That is why is so important to update every package that your app has – at least as a production dependency.

You can update your packages by simple running a composer/npm command:

composer update npm update

This command updates the current package/dependencies version. If you want to update to a major release you can execute:

composer outdated
npm outdated

Password Vulnerabilties

Any password should be hashed. Luckily, Laravel provides more than one way to hash data:

bcrypt('LaravelIsCool');
Hash::make('LaravelIsCool');

The APP_KEY is used to encrypt and decrypt data, but it can also be used for signed routes too. This has no relation with hashes, so use it with confidence.

Prevent CSRF Attack

Laravel API security also goes the extra mile with a mechanism to protect the application against CSRF attacks. This type of attack is very difficult to replicate and we do not need to cover it as the framework does it for us.

A CSRF attack makes a request from another browser tab and tries to submit malicious requests to the application. Laravel protects us against these attacks. Every request generates a token that changes on every request. This token would be known only by the application and every request should have this token to validate that the request comes from the same server.

In blade, you can use the directive @csrf:

<form method="POST" action="/profile">
    @csrf
    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="" />
</form>

To exclude some requests that come from a webhook that was created outside of our application, there is a protected property $except in the VerifyCsrfToken middleware:

protected $except = [
    'stripe/*',
    'http://example.com/foo/bar',
    'http://example.com/foo/*',
];

Prevent DOS Attack

These types of attacks can be divided into two popular categories:

DOS Attacks That Send a Lot of Requests

These attacks would send a lot of PHP requests that are not closed. The server responds to multiple requests until it cannot support more requests and the memory fails, resulting in our server going down. An example of these attacks could be a “slow loris” attack.

Laravel throttle middleware and RateLimiter help us to handle these attacks by IP. It’s important to remember that in your app context, you can handle, but not stop requests from the outside world. You should need other dev-ops tools and server platform tweaks to mitigate these attacks.

DOS Attacks That Send Large Files to Consume the Server Memory

Another variety of this attack could be in a public form. Maybe your application has some public form to submit a file. In this case, large files can exhaust the server memory. Keep in mind that the server should be serving data/resources to other users and handling this type of submits all at the same time.

To handle this attack, you can use the Laravel API security validator to validate the file from the request. Here is an example:

//file is exactly 512 kilobytes.. 
'photo' => ['mimes:jpg,bmp,png', 'file', 'size:512'] 
// file max size is 512 kilobytes.. 
'photo' => ['mimes:jpg,bmp,png', 'file', 'max:512']

Additional Security Tips

Here is a list of tips that could increase your app security:

Use a Honeypot on Any Public Form

Any public form can be submitted by anyone. To avoid malicious requests from bots, you can set a hidden input. The bots would fill the input (a normal user should not fill a hidden input), and then you can use the prohibited validation rule from Laravel validator:

// this input should never comes in the request 
'honey_pot_field' => ['prohibited'],

Constantly Change Your APP_KEY Value

This can be challenging if you have data encryption store models. In this case, I suggest using a package that handles it for you: https://github.com/rawilk/laravel-app-key-rotator. The package rotates the APP_KEY, decrypting and encrypting again all models that were encrypted.

Send an Email When a User Updates a New Email Account

Laravel provides a feature to send an email to verify a new account with new user registration. However, when the same user changes an email account, it does not verify the new email address. This process could be automated by a package: https://github.com/protonemedia/laravel-verify-new-email.

The same applies to password changes.

Register SSH Credentials on Your Server Cautiously

Try to connect with SSH only from places where your connection is “secure.” Avoid public wifi connections.

Set Tokens Lifetime

For Laravel Passport:

In your app/providers/AuthServiceProvider.php, you can set a specific lifetime for every token:

/** 
 * Register any authentication / authorization services. 
 * 
 * @return void 
*/ 
public function boot() 
{    
    $this->registerPolicies();
    Passport::routes();
    Passport::tokensExpireIn(now()->addDays(15));
    Passport::refreshTokensExpireIn(now()->addDays(30));
    Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}

For Laravel Sanctum:

Just publish the sanctum config file and change the value. The time would be set in minutes:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
'expiration' => null,

Use Authorization Features

Laravel security provides a native system to authorize users on any action. Actions that are not related to any specific model are typically covered by Gates, and the rules that are tight to a model could be covered by Policies. Laravel provides a lot of ways to apply these rules across the app layers. You can apply an authorization rule on:

  • Routes, by using your gates and policies as middlewares.
  • Controllers, using $this->authorizeResource() in the constructor of resource controllers.
  • Controllers, using a more granular validation with $this->authorize() method.
  • Any place, (models, custom services, resources, gates, policies, etc) where you have available the authenticated user with the method $user->can() or $user->cannot().
  • In Blade views, by using the directive @can and @cannot.
  • If you are using any javascript template system you can set an array of permissions in your user or any other model, to get pretty similar functionality, as any policy, the typical actions like viewAll , view , create , update , destroy, here an example:
<button v-if="$page.props.auth.user.permissions.admin_action.create">Admin Action</button> 
<td v-if="product.permissions.view"></td>

Conclusion

This introduction to the security aspects of Laravel allows us, the Laravel developers, to better understand how the framework already protects us from many vulnerabilities.

It also shows us the additional value of Laravel by allowing us to focus our time on development and not on solving common security problems.

An additional advantage is that we can see how working with a tool with such a wide ecosystem allows us to add third-party packages to solve specific problems that other developers have already faced before.

And if you’re in a reading mode and want to advance your Laravel skills, take a look at the following resources:

Laravel News Links