Laravel Code Tips

Make your Laravel code cleaner, faster, and safer.

You can use WITH TIES instead of LIMIT to return more results if they have the same value

318

๐Ÿ”ฅ You can use WITH TIES instead of LIMIT to return more results if they have the same value

You can use WITH TIES instead of LIMIT to return more results if they have the same value

โšก๏ธ Database Tip

Everyone knows the LIMIT clause. But what do you do if you want to have e.g. the employees with the TOP 3 salaries and not exclude the 4th or 5th one earning the same as the 3rd? The WITH TIES clause can return more results if the value is the same. Great!

HTTP response status can be customized when denying actions via Gates & Policies

316

๐Ÿ”ฅ HTTP response status can be customized when denying actions via Gates & Policies

HTTP response status can be customized when denying actions via Gates & Policies

๐Ÿ”๐Ÿงต I added a small, but pretty nice, security enhancement in Laravel v9.20.0

When denying actions via Gates & Policies in Laravel, you can now customise the HTTP response status that is returned

This allows you to deny access, while hiding the existence of your resources.

Use `$wire.entangle()` instead of `$entangle`

314

๐Ÿ”ฅ Use `$wire.entangle()` instead of `$entangle`

Use `$wire.entangle()` instead of `$entangle`

TIL:

In Laravel Livewire, it's better sometimes to use wire.entangle(), instead of the entangle directive, avoids weird issues like "invalid or unexpected token."

Thanks, @samuelstancl, for posting that gem. ๐Ÿ”ฅ

You can time travel() in your tests

312

๐Ÿ”ฅ You can time travel() in your tests

You can time travel() in your tests

๐Ÿ”ฎ Travel in time in your Laravel tests.

Using the travel() method you can travel back and forward in time.

No more Carbon::setTestNow()

Super useful ๐Ÿ‘

Be careful if you're not scoping your route model bindings

311

๐Ÿ”ฅ Be careful if you're not scoping your route model bindings

Be careful if you're not scoping your route model bindings

I've caught myself writing this security bug many times in controllers, making the assumption that Laravel will retrieve child route bound models by the parent model by default. Be careful if you're not scoping your route model bindings!

You can use `Str::markdown` to build translation strings

310

๐Ÿ”ฅ You can use `Str::markdown` to build translation strings

You can use `Str::markdown` to build translation strings

Ever needed to add HTML inside a Laravel translation string, and had to split the string up into chunks?

Or felt bad about raw HTML in your translations?

Here's a little cheat - parse markdown. Most of the formatting you want to do inside a translation string is available. ๐Ÿคทโ€โ™‚๏ธ

You can use the boolean() / date() / string() methods on the Request object instead of manually type-casting request parameters

309

๐Ÿ”ฅ You can use the boolean() / date() / string() methods on the Request object instead of manually type-casting request parameters

You can use the boolean() / date() / string() methods on the Request object instead of manually type-casting request parameters

โšก๏ธ Instead of explicitly type-casting or wrapping request parameters, you can use some of Laravel's utility methods on the Request object. It comes with a boolean() helper, date() helper and a string() / str() helper!

Use database partitions to delete large chunks of data efficiently

307

๐Ÿ”ฅ Use database partitions to delete large chunks of data efficiently

Use database partitions to delete large chunks of data efficiently

โšก Database Tip

Some applications want to periodically delete old historic data (or have to because of regulations). Deleting billions of rows is a very slow task that could take several minutes and may take your application down. Use partitions for efficient deleting!

Encrypted casts can use unique model-derived keys

306

๐Ÿ”ฅ Encrypted casts can use unique model-derived keys

Encrypted casts can use unique model-derived keys

๐Ÿ”ฅ #Laravel Tip:

The default encryption cast for Eloquent models uses the app key, making rotation difficult and allowing anyone with key to decrypt all the DB. To address this, consider creating a custom cast that uses the model to create its own unique key.

Laravel's RateLimiter can be used to throttle ANY parts of your code

305

๐Ÿ”ฅ Laravel's RateLimiter can be used to throttle ANY parts of your code

Laravel's RateLimiter can be used to throttle ANY parts of your code

๐Ÿ”ฅ #Laravel Tip: Rate-limiting is not only for throttling entire requests. You can also use it to throttle methods or parts of your code, which can be really useful when you need to protect things against spikes e.g. the DB.

String IDs can be case sensitive

303

๐Ÿ”ฅ String IDs can be case sensitive

String IDs can be case sensitive

You can make your IDs case sensitive when using strings as primary keys in Laravel โœจ

You can generate fake values anywhere in your app using the new `fake()` helper

300

๐Ÿ”ฅ You can generate fake values anywhere in your app using the new `fake()` helper

You can generate fake values anywhere in your app using the new `fake()` helper

Enjoying the little things: the new fake() helper we introduced to Laravel.

Because it is a singleton, you can get unique values across multiple calls / boundaries.

Super useful for tests, factories, seeders, and for quickly prototyping a design with fake data โœŒ๏ธ

You can customize default validation rules for passwords

299

๐Ÿ”ฅ You can customize default validation rules for passwords

You can customize default validation rules for passwords

You can specify the default validation rules for passwords in a single location of your Laravel app ๐Ÿ”

Create a custom provider or use the AppServiceProvider. Then use Password::defaults() as validation rule โœ…

You can have different defaults depending on the app environment.

Long classes can be split into small single-use traits

298

๐Ÿ”ฅ Long classes can be split into small single-use traits

Long classes can be split into small single-use traits

๐Ÿ’ก Create single-use traits to split up long classes into smaller parts

This way, all e.g. link-related logic can be contained within a single trait

You can namespace your helper functions

297

๐Ÿ”ฅ You can namespace your helper functions

You can namespace your helper functions

๐Ÿ”ฅ Namespaced functions are a good way to make use of helper functions, while avoiding conflicts in the global namespace

You can import entire namespaces in PHP

294

๐Ÿ”ฅ You can import entire namespaces in PHP

You can import entire namespaces in PHP

๐Ÿ”ฅ You can import entire namespaces in PHP

This is useful when you're interacting with many classes from a single namespace

You can add a URI fragment when redirecting to a route

293

๐Ÿ”ฅ You can add a URI fragment when redirecting to a route

You can add a URI fragment when redirecting to a route

You can add a URI fragment when redirecting to a route in Laravel.

This is super useful when redirecting to a specific section of the page. E.g. reviews section on a product page ๐Ÿ“ˆ

You can use Eloquent `whereColumn()` to compare columns to each other

292

๐Ÿ”ฅ You can use Eloquent `whereColumn()` to compare columns to each other

You can use Eloquent `whereColumn()` to compare columns to each other

๐Ÿ’ก๐ŸŸฐ Quick #Laravel Eloquent tip for comparing database columns to each other within a query.

You don't have to use any raw statements to do this - whereColumn() has got you covered! ๐Ÿ˜Š

Uploaded files can be attached to emails directly from the request

291

๐Ÿ”ฅ Uploaded files can be attached to emails directly from the request

Uploaded files can be attached to emails directly from the request

Sending emails with user uploaded files in Laravel?

Did you know you don't have to save the file first โ€” you can simply attach the uploaded file with attachData ๐Ÿ’Œ ๐Ÿ“ธ

Here's a snippet from a Mailable class using it.

Laravel's Http client lets you easily define retry attempts and a timeout

285

๐Ÿ”ฅ Laravel's Http client lets you easily define retry attempts and a timeout

Laravel's Http client lets you easily define retry attempts and a timeout

๐Ÿ˜ Laravelโ€™s Http client is amazing. Using just a bit of code, you can specify a timeout, retry attempts, and immediately get the result as JSON.

Is there any other HTTP client written in #php that makes it this easy?

๐Ÿ’ช Laravel

Consider creating helpers for model factories

282

๐Ÿ”ฅ Consider creating helpers for model factories

Consider creating helpers for model factories

If your app has only a few models, consider creating helper functions for model factories

Helpers have perfect IDE support and can make your tests a lot cleaner

Pairs especially well with @pestphp ๐Ÿ’…

orderByRaw() is very useful for complex sorting in Eloquent

281

๐Ÿ”ฅ orderByRaw() is very useful for complex sorting in Eloquent

orderByRaw() is very useful for complex sorting in Eloquent

๐Ÿ”ฅ #Laravel Tip: Make use of โ€˜orderByRawโ€™ when you need to sort records in a more complex manner than simply A-Z or Z-A. Hereโ€™s an example where I sort โ€˜rolesโ€™ based on their level of importance (rather than their alphabetical order).

Partial indexes are useful for enforcing rules that only apply conditionally

280

๐Ÿ”ฅ Partial indexes are useful for enforcing rules that only apply conditionally

Partial indexes are useful for enforcing rules that only apply conditionally

โšก๏ธ Database Tip

Sometimes you want to make columns unique but you can't because e.g. there are still soft-deleted rows in the table witht the same value. By only including relevant rows (partial index) you can still enforce uniqueness, and you can even simulate it for MySQL!

You can define default model data for BelongsTo relationships

274

๐Ÿ”ฅ You can define default model data for BelongsTo relationships

You can define default model data for BelongsTo relationships

๐Ÿ”ฅ Laravel Tip: Default Models.

In your relationships, you can define default models.

That way if the relationship doesn't exist it will return a default model so you don't have to check if is null every time.

You can validate a field and exclude it from the validated() data

273

๐Ÿ”ฅ You can validate a field and exclude it from the validated() data

You can validate a field and exclude it from the validated() data

๐Ÿ”ฅ #Laravel Tip: When you need to validate a field, but don't actually require it for anything e.g. 'accept terms and conditions', make use of the 'exclude' rule. That way, the 'validated' method won't return it...

Controllers can be used as route groups

270

๐Ÿ”ฅ Controllers can be used as route groups

Controllers can be used as route groups

#Laravel Tip โšก Instead of using the controller in each route, consider using a route controller group.

You can temporarily disable timestamps when saving a model

260

๐Ÿ”ฅ You can temporarily disable timestamps when saving a model

You can temporarily disable timestamps when saving a model

๐Ÿ“ #Laravel Tip | In some cases you don't want the updated_at field the change when updating small things. .. Did you know you could disable the timestamps while saving your data? Here is how... ๐Ÿ”ฅ

#laraveltip #php #code #development #details

You can create Storage disks on the fly

259

๐Ÿ”ฅ You can create Storage disks on the fly

You can create Storage disks on the fly

๐Ÿ”ฅ Did you know that you can create Storage disks on the fly in @laravelphp? This is super useful when you want your user to provide their own filesystem credentials, e.g. a user can bring their own S3 bucket to your app.

You can use the `missing` method to customize 404 handling on a route

258

๐Ÿ”ฅ You can use the `missing` method to customize 404 handling on a route

You can use the `missing` method to customize 404 handling on a route

๐Ÿ”ฅ Laravel tip: Customizing Missing Model Behavior in route model bindings

By default, Laravel throws a 404 error when it can't bind the model, but you can change that behavior by passing a closure to the missing method.

You can call `withTrashed()` on a route to accept soft deleted models

256

๐Ÿ”ฅ You can call `withTrashed()` on a route to accept soft deleted models

You can call `withTrashed()` on a route to accept soft deleted models

๐Ÿ”ฅ Laravel Tip: Route model binding soft-deleted models

By default, when using route model binding will not retrieve models that have been soft-deleted. You can change that behavior by using withTrashed in your route.

You can call `squish()` on Stringable instances to remove all unnecessary whitespaces

255

๐Ÿ”ฅ You can call `squish()` on Stringable instances to remove all unnecessary whitespaces

You can call `squish()` on Stringable instances to remove all unnecessary whitespaces

๐Ÿ”ฅ #Laravel Tip: Hot off the press, the latest release includes the โ€˜squishโ€™ global helper method by @DwightConrad. It removes all extraneous white space from a string, including between words. Itโ€™s like โ€˜trimโ€™ on steroids :)

You can now call `newLine()` on Stringable instances

253

๐Ÿ”ฅ You can now call `newLine()` on Stringable instances

You can now call `newLine()` on Stringable instances

#PHP #Laravel Since todays Laravel 9.6 release a new newline() method was added to the Stringable Class.

Thanks to @paulandroshchuk who contributed this

You can queue Closures

251

๐Ÿ”ฅ You can queue Closures

You can queue Closures

I had no idea you could queue closures in @laravelphp until today.

Understand the difference between `fresh()` and `refresh()`. One returns a *fresh* new instance, while the other *refreshes* an existing instance

248

๐Ÿ”ฅ Understand the difference between `fresh()` and `refresh()`. One returns a *fresh* new instance, while the other *refreshes* an existing instance

Understand the difference between `fresh()` and `refresh()`. One returns a *fresh* new instance, while the other *refreshes* an existing instance

๐Ÿ”ฅ #Laravel Tip: Ever wondered what the differences are between an Eloquent modelโ€™s โ€˜fresh()โ€™ and โ€˜refresh()โ€™ methods? Letโ€™s see what each of them do with this little cheatsheet.

You can freeze time in tests

247

๐Ÿ”ฅ You can freeze time in tests

You can freeze time in tests

โ„๏ธIn your Laravel tests, you might sometimes need to freeze the time.

This is particularly useful if you're trying to make assertions based on timestamps or need to make queries based on dates and/or times.

#laravel #php

You can generate a series of dates in a given range right at the database level

245

๐Ÿ”ฅ You can generate a series of dates in a given range right at the database level

You can generate a series of dates in a given range right at the database level

โšก๏ธ Database Tip

When doing statistical aggregations by time, you may have gaps in your data. You don't have to fill them manually with code! You can generate a series of dates from a start to end time and use these days to join to your statistical data with gaps.

You can debounce a function using Alpine.debounce()

243

๐Ÿ”ฅ You can debounce a function using Alpine.debounce()

โ“ Using Alpine.js and need to debounce a function?

โŒ You don't need JavaScript libraries like lodash.

โœ… Just use Alpine.debounce() which is also used internally for the x-on:input.debounce="" modifier.

Cc: @calebporzio

You can start testing Livewire components with basic tests that makes sure components render accurately

240

๐Ÿ”ฅ You can start testing Livewire components with basic tests that makes sure components render accurately

You can start testing Livewire components with basic tests that makes sure components render accurately

๐Ÿ”ฅ When you're testing your @LaravelLivewire components, one of the simplest tests you can add is a "can this component be mounted" test. This is one of the best ways to test your the mounting process in isolation and ensuring the component renders the view correctly.

You can record all login & logout events

239

๐Ÿ”ฅ You can record all login & logout events

You can record all login & logout events

๐Ÿ”ฅ #Laravel Tip: If your app needs to record logins and logouts for security purposes (auditing), then you should definitely make use of the auth events, which allow you to easily listen for them.

You can use partial Queue fakes

236

๐Ÿ”ฅ You can use partial Queue fakes

You can use partial Queue fakes

#Laravel Tip: Since todays Laravel 9.5 release you can now do partially queue faking.

You can use $this->mock in Pest tests

235

๐Ÿ”ฅ You can use $this->mock in Pest tests

You can use $this->mock in Pest tests

Within your Pest / PHPUnit tests, you may use @laravelphp's "mock" method to instruct the container to use your mocked instance of the object instead of constructing the object itself. โœ…

PHP traits can contain abstract methods

233

๐Ÿ”ฅ PHP traits can contain abstract methods

PHP traits can contain abstract methods

๐Ÿ’กDid you know you can write abstract methods in a trait?

This way you don't have to make assumptions about the models where the trait is used.

But instead, you have a clear contract:

You can define casts for specific Eloquent queries

231

๐Ÿ”ฅ You can define casts for specific Eloquent queries

You can define casts for specific Eloquent queries

๐Ÿ”ฅ #Laravel Query Time Casting

We all know you can add casts to your eloquent models, but did you know you can add casts to a specific query?

You can validate data at the database level

230

๐Ÿ”ฅ You can validate data at the database level

You can validate data at the database level

โšก๏ธ Database Tip

Your application will have bugs and any data stored may be corrupt forever. But with constraints on the data model, rules would have prevented saving incorrect data in the first place! Use them as a last frontier to make sure you always have valid data.

You can convert an Eloquent collection back to an Eloquent Query builder

226

๐Ÿ”ฅ You can convert an Eloquent collection back to an Eloquent Query builder

You can convert an Eloquent collection back to an Eloquent Query builder

#Laravel Tip ๐Ÿ”ฅ : In some situation you might want to update all the models inside the eloquent collection. You can do that easily in Laravel using toQuery() method. Laravel is utilizing #PHP like a pro. See how can you do that ๐Ÿ‘‡

#webdevelopers #100DaysOfCode #developers

RateLimiter's attempt() accepts a fourth parameter for the "decay"

225

๐Ÿ”ฅ RateLimiter's attempt() accepts a fourth parameter for the "decay"

RateLimiter's attempt() accepts a fourth parameter for the "decay"

๐Ÿ’ก The 'attempt()' method of the RateLimiter that comes with @laravelphp has an optional fourth argument to specify the decay.

Both examples dispatch max 12 events per minute, but the latter spread the events throughout the minute. Incredible, isn't it? ๐Ÿคฉ

#Laravel #PHP #webdev

The order of columns in multi-column indices matters

224

๐Ÿ”ฅ The order of columns in multi-column indices matters

The order of columns in multi-column indices matters

โšก๏ธ Database Tip

Creating indexes is a handcraft learned from experience, multiple-column indexes is a lot more complicated. But it doesn't have to be complicated!

Here are 3 simple rules for the column ordering of multiple column indexes, solving 80% of the perf problems.

Use Carbon's setTimezone() and shiftTimezone() methods

220

๐Ÿ”ฅ Use Carbon's setTimezone() and shiftTimezone() methods

Use Carbon's setTimezone() and shiftTimezone() methods

Over the past few years, I've worked on some large apps that deal with events in different timezones. This can end up being quite confusing, as best practice is always to store dates in UTC.

That's where Carbon's shiftTimezone() and setTimezone() methods can help you out! โฌ‡๏ธ

Be careful about setting timezones with Carbon

219

๐Ÿ”ฅ Be careful about setting timezones with Carbon

Be careful about setting timezones with Carbon

โ—๏ธโฐ When working with Carbon/timezones, you should be aware that setting the timezone during construction is not the same as altering the timezone later. ๐Ÿ‘

Use on-demand notifications to send messages to unregistered users

216

๐Ÿ”ฅ Use on-demand notifications to send messages to unregistered users

Use on-demand notifications to send messages to unregistered users

๐ŸŒถ๏ธ #Laravel tip: Sometimes you may need to send a notification to someone who is not stored as a "user" of your application.

Welcome to On-Demand Notifications in Laravel ๐Ÿ”ฅ

#PHP #Developers

Name *all* timestamp fields using the action_at convention

214

๐Ÿ”ฅ Name *all* timestamp fields using the action_at convention

Name *all* timestamp fields using the action_at convention

Laravel tip: Use the "{action}_at" naming convention for your DATETIME and TIMESTAMP fields.

This helps you to instantly recognise in your code when you're using a datetime field ๐Ÿ˜„

#laravel #php

Use the `WITH TIES` clause to return more than the `LIMIT`-ed amount when there are multiple results with the same value

213

๐Ÿ”ฅ Use the `WITH TIES` clause to return more than the `LIMIT`-ed amount when there are multiple results with the same value

Use the `WITH TIES` clause to return more than the `LIMIT`-ed amount when there are multiple results with the same value

โšก๏ธ Database Tip

Everyone knows the LIMIT clause. But what do you do if you want to have e.g. the employees with the TOP 3 salaries and not exclude the 4th or 5th one earning the same as the 3rd? The WITH TIES clause can return more results if the value is the same. Great!

Create Subscribers to listen to & handle multiple events using separate methods, inside a single class

212

๐Ÿ”ฅ Create Subscribers to listen to & handle multiple events using separate methods, inside a single class

Create Subscribers to listen to & handle multiple events using separate methods, inside a single class

Did you know that you can create a "Subscriber" class in Laravel to handle multiple events with different methods in one Listener class?

This is very useful if you want to group certain actions with the same dependencies.

Documentation: https://laravel.com/docs/9.x/events#event-subscribers

Use comments for explaining complex logic

211

๐Ÿ”ฅ Use comments for explaining complex logic

Use comments for explaining complex logic

Comments in code should be used with care. They should only be added when they add actual value to the programmer; which is why I style them in such a way that they "pop out", instead of them disappearing in the background.

Move tests to separate test suites

208

๐Ÿ”ฅ Move tests to separate test suites

Move tests to separate test suites

My Laravel tip of the day. If you're running slow tests that need to hit a third party API, you can break them out of your Features directory and put them in a dedicated test suite (e.g. External). Then you can run "phpunit --testsuite Feature", and your External tests won't run.

You can use traits inside PHP enums

207

๐Ÿ”ฅ You can use traits inside PHP enums

You can use traits inside PHP enums

A few days ago, I learned that PHP enums can use traits

It may seem like a massive anti-pattern, but it allows making enums actually awesome with this one trick ๐Ÿ”ฅ

You can skip() TransformRequests-type middleware

202

๐Ÿ”ฅ You can skip() TransformRequests-type middleware

You can skip() TransformRequests-type middleware

๐Ÿ’ก As of @laravelphp v8.36.0, you can skip 'TransformRequests' middlewares by registering a callback.

For example, you can use it on 'TrimStrings' and 'ConvertEmptyStringsToNull'.

#Laravel #PHP #webdev

Laravel provides a `Fluent` class as a universal structure for array data

196

๐Ÿ”ฅ Laravel provides a `Fluent` class as a universal structure for array data

Laravel provides a `Fluent` class as a universal structure for array data

Fluent is a utility class provided by @laravelphp that lets us handle data fluently.

Out of the box it can be turned into an array or JSON, it can act as an array and it's serializable as a JSON.

It also gets and sets attributes dynamically and in a fluent way.

#Laravel #PHP

match() statements are a great way to clean up code

192

๐Ÿ”ฅ match() statements are a great way to clean up code

match() statements are a great way to clean up code

Match offers such a compact and clean syntax compared to its PHP alternatives ๐ŸŒˆ

It can make our code way more readable and concise ๐Ÿ’…

#PHP

You can disable lazy loading using Model::preventLazyLoading()

191

๐Ÿ”ฅ You can disable lazy loading using Model::preventLazyLoading()

You can disable lazy loading using Model::preventLazyLoading()

๐Ÿ”ฅ #Laravel Tip: Protect your database from the dangers of lazy loading by disabling it in your Laravel app. You can also customise how violations are handled, which is perfect for models outside of your control e.g. within packages.

Use Eloquent scopes to clean up complex relation queries

184

๐Ÿ”ฅ Use Eloquent scopes to clean up complex relation queries

Use Eloquent scopes to clean up complex relation queries

๐Ÿ”ฅ Eloquent scopes pair very well with complex relation queries

Scopes should also have @method annotations. They make the model more self-documenting & better supported in IDEs

Use PostgreSQL's trigram indexes to make WHERE LIKE queries faster

183

๐Ÿ”ฅ Use PostgreSQL's trigram indexes to make WHERE LIKE queries faster

Use PostgreSQL's trigram indexes to make WHERE LIKE queries faster

โšก๏ธ Database Tip

Every database performance guide is repeating the false statement stating WHERE LIKE '%search%' queries can't use an index. That is just not true! Most probably your database can't, but PostgreSQL implements trigram indexes which will make this really fast!

Laravel's container can be used for resolving variadic dependencies

182

๐Ÿ”ฅ Laravel's container can be used for resolving variadic dependencies

Laravel's container can be used for resolving variadic dependencies

Since @laravelphp 8.79 it is possible to resolve variadic dependencies out of the IoC container.

This is quite useful for type-hinting and static analysis and allows us to bind a set of concrete implementations to an abstraction layer.

#Laravel #PHP

Laravel's Http client supports concurrent requests using the `pool` method

180

๐Ÿ”ฅ Laravel's Http client supports concurrent requests using the `pool` method

Laravel's Http client supports concurrent requests using the `pool` method

๐Ÿ”ฅ #Laravel Tip: Need to make more than one HTTP request e.g. to one or more sites? You might think about running them concurrently to improve performance. The HTTP client's 'pool' method makes this a trivial exercise.

MySQL has a blackhole store engine

179

๐Ÿ”ฅ MySQL has a blackhole store engine

MySQL has a blackhole store engine

๐Ÿ‘จโ€๐Ÿ”ฌ Cool MySQL hack:

๐Ÿง If your staging env has a table that ideally doesn't have data in it (esp production data)

๐Ÿ•ณ You can make it a BLACKHOLE table

๐Ÿ˜… I used this to make sure a table with a list of emails to send never contains any rows. Because, you know....

Interesting technique: add getters to Form Requests

177

๐Ÿ”ฅ Interesting technique: add getters to Form Requests

Interesting technique: add getters to Form Requests

๐Ÿ’ชPower up your #Laravel requests

You can add very simple getters on the request, so: โœ…You actually know what's on the request โœ…You have types โœ…You can do basic data transformation

Specify the columns you want to select when fetching all() models

176

๐Ÿ”ฅ Specify the columns you want to select when fetching all() models

Specify the columns you want to select when fetching all() models

๐ŸŒถ๏ธ #Laravel tip: You can select the columns to run when using the Model::all() method. No need for an additional select() method.

A tiny tip to always keep in mind ๐Ÿ’ก

#PHP #Developers

Make models prunable to periodically delete them from the DB

173

๐Ÿ”ฅ Make models prunable to periodically delete them from the DB

Make models prunable to periodically delete them from the DB

๐Ÿ’ก#Laravel Eloquent Tip

Laravel 8 introduced the Prunable trait. You can use it to delete old models on a scheduled basis.

You don't need to write custom commands anymore:

You can name migrations "like this"

172

๐Ÿ”ฅ You can name migrations "like this"

You can name migrations "like this"

๐Ÿ”ฅ Epic Laravel Tip - Did you know that you don't necessarily have to use underscores for migrations names?

You can add the context() and render() methods to custom exceptions

170

๐Ÿ”ฅ You can add the context() and render() methods to custom exceptions

You can add the context() and render() methods to custom exceptions

If you're creating custom exceptions inside your Laravel application, you can add a "context()" method to provide additional data to be printed in the log, as well as a "render()" method to allow the exception to display its own view to the user. Super cool! ๐Ÿคฉ

Custom collections pair well with higher order proxies

164

๐Ÿ”ฅ Custom collections pair well with higher order proxies

Custom collections pair well with higher order proxies

๐Ÿ”ฅ Custom collections pair very well with higher order proxies

When you have some repetitive low level logic that you'd like to abstract into more readable methods that follow your business terminology, custom collections can be a great choice

PHP 8.1 enums can be used as model casts

163

๐Ÿ”ฅ PHP 8.1 enums can be used as model casts

PHP 8.1 enums can be used as model casts

๐Ÿ”ฅ Did you know that @laravelphp can cast model columns into instances an enum in PHP 8.1?

The example below will create an instance of OrderStatus based on variant value. If the status column has the value shipped, it will return the OrderStatus::Shipped variant.

You can supply default values for route parameters

160

๐Ÿ”ฅ You can supply default values for route parameters

You can supply default values for route parameters

๐Ÿ”ฅ Did you know that you can supply default values for route parameters in @laravelphp?

In the screenshot below, we use the current user's account as the default value for {account}. This means we don't have to provide it when generating the users.index route.

You can use generic class-string annotations to hint that an instance of the passed class is returned

159

๐Ÿ”ฅ You can use generic class-string annotations to hint that an instance of the passed class is returned

You can use generic class-string annotations to hint that an instance of the passed class is returned

This is how you can hint that a function returns an instance of the class of which you passed the class name.

Cool stuff!

Hat tip to @enunomaduro

https://github.com/spatie/laravel-route-discovery/blob/7fa88922aa693b03b4763eda870867075ab44999/src/PendingRoutes/PendingRouteAction.php#L100-L107

Use partitions for deleting mass amounts of data

158

๐Ÿ”ฅ Use partitions for deleting mass amounts of data

Use partitions for deleting mass amounts of data

โšก ๏ธDatabase Tip

Some applications want to periodically deleted old historic data (or have to because of regulations). Deleting billions of rows is a very slow task which could take several minutes and may take your application down. Use partitions for efficient deleting!

You can use `onerror` on the image tag

156

๐Ÿ”ฅ You can use `onerror` on the image tag

You can use `onerror` on the image tag

๐Ÿ˜ฒ TIL: You can hide an image when it is broken so you don't get that ugly broken image icon from the browser.

Use skip() when writing tests ahead of time

154

๐Ÿ”ฅ Use skip() when writing tests ahead of time

Use skip() when writing tests ahead of time

๐ŸŒถ๏ธ #Laravel #pestphp tip

If you like to plan your tests ahead of time and implement them one by one, you can always make use of a handy method skip() to tell the test runner to ignore those empty tests.

skip() accepts a callback too!

Number markdown lists with `1.` rather than the actual number

153

๐Ÿ”ฅ Number markdown lists with `1.` rather than the actual number

Number markdown lists with `1.` rather than the actual number

๐Ÿ’ก A little thing I always like to do. Use only "1." for numbered lists in markdown. The list is rendered the same, but adding an item doesn't require you to renumber the other items ๐Ÿค˜

You can use first class callables for routes in PHP 8.1

152

๐Ÿ”ฅ You can use first class callables for routes in PHP 8.1

You can use first class callables for routes in PHP 8.1

๐Ÿ”ฅ You can use first class callables for routes in PHP 8.1

The caveat is that the methods need to be static because there's no syntax for referencing instance methods on classes

I don't use constructor DI in my apps, so static methods are fine despite feeling a bit non-standard

You can add a --refresh flag to the artisan down command to send a refresh header to the browser

150

๐Ÿ”ฅ You can add a --refresh flag to the artisan down command to send a refresh header to the browser

You can add a --refresh flag to the artisan down command to send a refresh header to the browser

#WeirdDevReadsDocs

Did you know?

You can add a --refresh flag to the artisan down command to send a refresh header to the browser. I think that's helpful for well visited apps where you trying to keep perceived downtime as low as possible!

https://laravel.com/docs/8.x/configuration#maintenance-mode

@laravelphp

Use match () or switch () statements to conditionally scope database queries based on query strings in the request

148

๐Ÿ”ฅ Use match () or switch () statements to conditionally scope database queries based on query strings in the request

Use match () or switch () statements to conditionally scope database queries based on query strings in the request

Remembered this great tip recently, and it's nice to see how fast PHP evolves

The exact same behavior can be implemented using match () with a default value, which also removes the need for the second callback โšก๏ธ https://twitter.com/reinink/status/1233017064492761088

Adding WHERE scopes which use an indexed column to a query that's primarily filtered by another column is a great way to speed up DB performance

147

๐Ÿ”ฅ Adding WHERE scopes which use an indexed column to a query that's primarily filtered by another column is a great way to speed up DB performance

Adding WHERE scopes which use an indexed column to a query that's primarily filtered by another column is a great way to speed up DB performance

โšก๏ธ Database Tip

Sometimes you have seldom used queries and you can't add an index on columns for these queries. A nice trick is to use another indexed condition so the rows are filtered by the indexable column first and afterwards again for the more limiting condition.

You can use the array spread syntax to pass an array of arguments to another function

146

๐Ÿ”ฅ You can use the array spread syntax to pass an array of arguments to another function

You can use the array spread syntax to pass an array of arguments to another function

๐Ÿ”ฅ You can use array spreading to pass an array as arguments to another function. #php

Hereโ€™s a self-contained example where we spread the array output of sys_getloadavg. That function returns an array with three elements.

https://github.com/spatie/cpu-load-health-check/blob/70f387d5167c24d4000d825a5bddab2504d557fb/src/CpuLoad.php#L17

#php

You can use $request->whenFilled() to execute some logic only when a specific value is part of the request data

143

๐Ÿ”ฅ You can use $request->whenFilled() to execute some logic only when a specific value is part of the request data

You can use $request->whenFilled() to execute some logic only when a specific value is part of the request data

๐Ÿ”ฅAnother amazing #Laravel feature!๐Ÿ”ฅ

We often write if statements to check if a value is present on a request or not.

You can simplify it with the whenFilled() helper.

๐Ÿ‘‹If you find this useful, consider clicking the button that says Retweet. It's a very cool button!

Writing simple "page can be visited" tests is a great way to get started with testing

142

๐Ÿ”ฅ Writing simple "page can be visited" tests is a great way to get started with testing

Writing simple "page can be visited" tests is a great way to get started with testing

Does your @laravelphp application have 0 tests? Here is one test you can easily add to get started. It's probably the most important test โ€” in web projects โ€” and it has an enormous value.

โœ“ Ensures your application boots. โœ… โœ“ Ensures the home page can be loaded. ๐Ÿ’จ

You can calculate multiple aggregates in a single database query

139

๐Ÿ”ฅ You can calculate multiple aggregates in a single database query

You can calculate multiple aggregates in a single database query

โšก๏ธ Database Tip

You don't have to execute multiple queries to calculate different aggregates. With the filter clause you can narrow the rows which should be included for the calculation. So you may need to scan the table only once, the performance impact can be massive ๐Ÿ”ฅ

Use typehints wherever possible to improve code safety and IDE support

138

๐Ÿ”ฅ Use typehints wherever possible to improve code safety and IDE support

Use typehints wherever possible to improve code safety and IDE support

๐Ÿ”ฅ Simple typehints and annotations go a long way

Even without any docblocks, this code is perfectly understandable by both developers and IDEs

Writing code like this: ๐Ÿ‘‰ Prevents bugs using type safety ๐Ÿ‘‰ Makes the code self-documenting ๐Ÿ‘‰ Takes only a few seconds to implement

You can pass parameters to Laravel middleware classes

129

๐Ÿ”ฅ You can pass parameters to Laravel middleware classes

You can pass parameters to Laravel middleware classes

๐Ÿ”ฅ Remember that you can pass parameters to your custom @laravelphp middleware classes

This simple middleware allows me to inject onboarding screens in an Inertia app.

You can validate user input inside middleware

127

๐Ÿ”ฅ You can validate user input inside middleware

You can validate user input inside middleware

โœ” You can validate fields even within a middleware in Laravel.

This would help when you need to constantly validate the same field(s) on your requests:

Use aggregate methods to count related models

125

๐Ÿ”ฅ Use aggregate methods to count related models

Use aggregate methods to count related models

When you're counting related models in @laravelphp, opt for aggregates!

๐Ÿ‘Ž Using the count() method on a collection of related models is a tad slower.

You can implement the ShouldBeEncrypted interface on your jobs to encrypt their payload before they get pushed to the queue

123

๐Ÿ”ฅ You can implement the ShouldBeEncrypted interface on your jobs to encrypt their payload before they get pushed to the queue

You can implement the ShouldBeEncrypted interface on your jobs to encrypt their payload before they get pushed to the queue

๐Ÿ’ก Since @laravelphp v8.19, there is a ShouldBeEncrypted interface that jobs can implement. This encrypts the payload, for example, in case the properties hold sensitive data.

As of v8.25, this works for Listeners, Mailables, and Notifications as well ๐Ÿ’ซ

#Laravel #PHP #webdev https://twitter.com/pascalbaljet/status/1462711618329055232

You can convert Eloquent Collections back to a Query Builder instance

122

๐Ÿ”ฅ You can convert Eloquent Collections back to a Query Builder instance

You can convert Eloquent Collections back to a Query Builder instance

A tiny tip about #laravel eloquent.

To retrieve the Query Builder after filtering the results: you can use ->toQuery().

The method internally use the first model of the collection and a whereKey comparison on the Collection models.

Use prefetching to boost the perceived speed of Livewire apps

120

๐Ÿ”ฅ Use prefetching to boost the perceived speed of Livewire apps

Use prefetching to boost the perceived speed of Livewire apps

To boost perceived speed in your @LaravelLivewire apps when loading data, make use of prefetching.

The .prefetch modifier tells Livewire to fetch the result in the background on hover, and then displays the result when the button is actually clicked โœจ

Create renderable exceptions

118

๐Ÿ”ฅ Create renderable exceptions

Create renderable exceptions

Laravel Tip: You can customize how your exceptions are rendered by adding a 'render' method to your exception.

For example, this allows you to return JSON instead of a Blade view when the request expects JSON.

You can use the data_get() method to safely access a nested array value

115

๐Ÿ”ฅ You can use the data_get() method to safely access a nested array value

You can use the data_get() method to safely access a nested array value

๐Ÿ’ก#Laravel Tip: Dealing with deeply-nested arrays can result in missing key / value exceptions. Fortunately, Laravel's data_get() helper makes this easy to avoid. It also supports deeply-nested objects.

Including a unique value, like now() or Str::random(), in the Blade template of a Livewire component is a great way to check if that part of the DOM is getting re-rendered

113

๐Ÿ”ฅ Including a unique value, like now() or Str::random(), in the Blade template of a Livewire component is a great way to check if that part of the DOM is getting re-rendered

Including a unique value, like now() or Str::random(), in the Blade template of a Livewire component is a great way to check if that part of the DOM is getting re-rendered

A quick and easy way to check if @LaravelLivewire components are re-rendering when you don't want/need them to.

Add now() or now()->timestamp to your component template. The time value will increment if there's a re-render side effect!

You can use the form="another-form" attribute on buttons to submit a different form

112

๐Ÿ”ฅ You can use the form="another-form" attribute on buttons to submit a different form

You can use the form="another-form" attribute on buttons to submit a different form

๐Ÿ”ฅ I sometimes forget you can use form="form-name" on input types to hook fields inside one form to another. This makes it as if those fields were inside that <form>-tag.

This is super useful if the fields are rendered in the wrong form, but UI wise it makes sense.

Use the *quietly() methods to create models without firing events using your factories

109

๐Ÿ”ฅ Use the *quietly() methods to create models without firing events using your factories

Use the *quietly() methods to create models without firing events using your factories

๐Ÿ“ Here's part 2 of the new Database and Eloquent ORM features in @laravelphp 8.x since the release in September 2020.

One of my favorites is the ability in Model Factories to create models without dispatching any events ๐Ÿ”ฅ

Blog post: https://protone.media/en/blog/database-and-eloquent-orm-new-features-and-improvements-since-the-original-laravel-8-release-22

#Laravel #PHP

Use Common Table Expressions to refine your data in complex Eloquent queries

106

๐Ÿ”ฅ Use Common Table Expressions to refine your data in complex Eloquent queries

Use Common Table Expressions to refine your data in complex Eloquent queries

โšก๏ธ Database Tip

Sometimes you have very complex queries involving multiple calculation steps. Instead of nesting queries or doing it in application code you can use Common Table Expressions (CTE) to refine your data in every step and even reuse former steps.

Use the --requests flag when creating models to also create form requests

104

๐Ÿ”ฅ Use the --requests flag when creating models to also create form requests

Use the --requests flag when creating models to also create form requests

This release of Laravel also includes a "--requests" flag when making models via Artisan. This option will create a "Store{Model}Request" and "Update{Model}Request" form request + update the controller to use those requests on their respective methods. ๐Ÿ”ฅ

Thanks @PovilasKorop!

Use the Str::headline() method to convert strings to studly words

101

๐Ÿ”ฅ Use the Str::headline() method to convert strings to studly words

Use the Str::headline() method to convert strings to studly words

๐Ÿ’กIt's refactor time!

Laravel 8.65 introduces the Str::headline() method, this method converts a string into studly words!

A small change like this results in less noise in my code.

Thanks @SteveTheBauman for this implementation! ๐Ÿ™Œ

Use the withAggregate() method to add related values to Eloquent queries using subselects

99

๐Ÿ”ฅ Use the withAggregate() method to add related values to Eloquent queries using subselects

Use the withAggregate() method to add related values to Eloquent queries using subselects

๐Ÿ’ก A little #Laravel tip from the latest blog post to get the week started!

Under the hood, the withAvg/withCount/withSum and other methods in Eloquent use the 'withAggregate' method. You can use this method to add a subselect based on a relationship ๐Ÿ’ซ

#PHP #webdev #OpenSource

You can create text-based tables in Laravel even outside CLI commands

94

๐Ÿ”ฅ You can create text-based tables in Laravel even outside CLI commands

You can create text-based tables in Laravel even outside CLI commands

If you ever need to generate text-based tables for sending in text messages, outputting in console, or in logs, @symfony provides an awesome "Table" class, just for that! ๐Ÿ’… Such a cool utility! ๐Ÿคฉ

You can use valueOrFail() to fetch a value from the database, or abort the request if the queried record does not exist

93

๐Ÿ”ฅ You can use valueOrFail() to fetch a value from the database, or abort the request if the queried record does not exist

You can use valueOrFail() to fetch a value from the database, or abort the request if the queried record does not exist

In the next blog posts, I'll cover Database and Eloquent improvements and new features in #Laravel 8.x.

Here's a great little feature that got added in v8.60 ๐Ÿ”ฅ

PR: https://github.com/laravel/framework/pull/38707

Yesterday's post about Collections: https://protone.media/en/blog/a-look-at-new-features-and-improvements-since-the-original-laravel-80-release-collections

#PHP #webdev #opensource

Use declare(strict_types=1) to enable strict mode for type checking

87

๐Ÿ”ฅ Use declare(strict_types=1) to enable strict mode for type checking

Use declare(strict_types=1) to enable strict mode for type checking

PHP reminder: The "declare(strict_types = 1);" directive enables strict mode. In strict mode, only a variable of exact type of the โ€œtype declarationโ€ will be accepted, or a "TypeError" will be thrown. โœ…

You can make the Http client throw exceptions to terminate execution on any received errors

80

๐Ÿ”ฅ You can make the Http client throw exceptions to terminate execution on any received errors

You can make the Http client throw exceptions to terminate execution on any received errors

๐Ÿ’ก By default, the @laravelphp HTTP client doesn't throw exceptions on client and server errors.

However, you can make it do that by using the 'throw' method, and this method is chainable ๐Ÿ”ฅ

Documentation: https://laravel.com/docs/8.x/http-client#throwing-exceptions

#Laravel #PHP #webdev #webdevelopment

Readonly properties

77

๐Ÿ”ฅ Readonly properties

Readonly properties

They're a great way to make your components safer and faster.

Say you have a component for editing some resource.

You enforce the ACL in mount().

But if the user could change the currently edited resource, you'd need to enforce ACL on all requests!

Replace children with a custom directive

76

๐Ÿ”ฅ Replace children with a custom directive

Replace children with a custom directive

Imagine that you have a nested component that depends on the parent state. You don't need to sync child state into parent, you just want to replace the child when the parent state changes.

You can use my custom directive for that.

Quick tip: Use $wire.entangle() instead of @entangle

74

๐Ÿ”ฅ Quick tip: Use $wire.entangle() instead of @entangle

Quick tip: Use $wire.entangle() instead of @entangle

It's good to get into the habit of using $wire, since it provides a full communication layer for your Livewire component.

It also doesn't run into issues when you use it inside single quoted attributes.

Advanced notifications

73

๐Ÿ”ฅ Advanced notifications

Advanced notifications

This trait allows dispatching notifications:

  • on the current page
  • on the next page (after redirect)
  • from any part of your code: you can run Lean::notify() in an action class, a model method, or anywhere else โ€” and it will be sent to the browser
Advanced trait design

72

๐Ÿ”ฅ Advanced trait design

Advanced trait design

Let's look at the same trait again. It does two interesting things.

  1. Livewire::listen() is superior to hydrate* and dehydrate* when you need access to specific parts of the lifecycle

  2. The instanceof self check scopes the listener to the component

Custom response effects

71

๐Ÿ”ฅ Custom response effects

Custom response effects

You can add custom data to response effects. Those are separate from component data, and act more like events.

You can use them when you have some JS code that looks at Livewire responses, and when you want more control than dispatching browser events

Compose components using traits

70

๐Ÿ”ฅ Compose components using traits

Compose components using traits

Traits are a powerful way to reuse functionality between Livewire components.

They're generally better than component nesting, since that comes with more complexity and worse performance.

Next up: Advanced trait examples

Call methods from JavaScript

69

๐Ÿ”ฅ Call methods from JavaScript

Call methods from JavaScript

Livewire's properties are extremely powerful, which often makes us forget that we can also call methods from the frontend.

Livewire gives you a full component API. Use it!

Use wire:replace

68

๐Ÿ”ฅ Use wire:replace

Use wire:replace

As you know, Livewire sometimes runs into painful DOM diffing issues. They can usually be solved with simple workarounds, but sometimes those workarounds get quite complex.

So I built a package that adds a wire:replace directive, telling Livewire to replace an entire chunk of the DOM, instead of trying to diff individual changes.

This one is less obscure

65

๐Ÿ”ฅ This one is less obscure

This one is less obscure

The $loop variable.

It greatly complements Tailwind-styled tables.

Striped tables done easily ๐ŸŽ‰

Laravel migrations have a very nice syntax for foreign keys

60

๐Ÿ”ฅ Laravel migrations have a very nice syntax for foreign keys

I didn't know about this for so long.

Instead of: $table->unsignedBigInteger('user_id'); $table->foreign('user_id')->references('id')->on('users');

You do: $table->foreignId('user_id')->constrained();

Comparing changes on 'saving' using:

56

๐Ÿ”ฅ Comparing changes on 'saving' using:

Comparing changes on 'saving' using:

$model->getOriginal()

in Eloquent event listeners can be very useful.

One such use case is checking whether an order is locked. If it is, the only write action we permit is unlocking it. Only then can changes be made.

Laravel Telescope is great for so many things

52

๐Ÿ”ฅ Laravel Telescope is great for so many things

Laravel Telescope is great for so many things

One of them is examining sent emails โœ‰๏ธ

You usually don't need a service like Mailtrap. Just use the log mail driver and install Telescope.

(image stolen from the internet)

Relevant for people building packages ๐Ÿ“ฆ

50

๐Ÿ”ฅ Relevant for people building packages ๐Ÿ“ฆ

Relevant for people building packages ๐Ÿ“ฆ

It's IMO better to use static properties and have "self-contained" behavior & configuration. Than to have a billion config keys. Especially when building large packages.

Makes the package more extensible, by consisting of atomic parts

People underutilize the exception handler

44

๐Ÿ”ฅ People underutilize the exception handler

People underutilize the exception handler

You can tell the app what response to return when a specific exception is encountered.

This is the simplest example. There's many more use cases.

Write functional code when it benefits you

41

๐Ÿ”ฅ Write functional code when it benefits you

Write functional code when it benefits you

Functional code can both clean things up and make them impossible to understand. Refactor common loops into functional calls, but don't write stupidly complex reduce()s just to avoid writing a loop. There's a use case for both.

Context matters

40

๐Ÿ”ฅ Context matters

Context matters

Above I said that moving business logic to action/service classes is good. But context matters

Here's code design advice from a popular "Laravel best practices" repo. There's absolutely no reason to put a 3-line check into a class. That's just overengineered

Use collections when they can clean up your code

39

๐Ÿ”ฅ Use collections when they can clean up your code

Use collections when they can clean up your code

Don't turn all arrays into collections just because Laravel offers them, but DO turn arrays into collections when you can make use of collection syntax to clean up your code.

Use docblocks only when they clarify things

38

๐Ÿ”ฅ Use docblocks only when they clarify things

Use docblocks only when they clarify things

Many people will disagree with this, because they do it. But it makes no sense.

There's no point in using docblocks when they don't give any extra information. If the typehint is enough, don't add a docblock.

That's just noise.

Create custom Blade directives for business logic

36

๐Ÿ”ฅ Create custom Blade directives for business logic

Create custom Blade directives for business logic

You can make your Blade templates more expressive by creating custom directives. For example, rather than checking if the user has the admin role, you could use @admin.

Use strict comparison

35

๐Ÿ”ฅ Use strict comparison

Use strict comparison

ALWAYS use strict comparison (=== and !==). If needed, cast things go the correct type before comparing. Better than weird == results

Also consider enabling strict types in your code. This will prevent passing variables of wrong data types to functions

Avoid queries in Blade when possible

34

๐Ÿ”ฅ Avoid queries in Blade when possible

Avoid queries in Blade when possible

Sometimes you may want to execute DB queries in blade. There are some ok use cases for this, such as in layout files.

But if it's a view returned by a controller, pass the data in the view data instead.

Consider using helpers instead of facades. They can clean things up

33

๐Ÿ”ฅ Consider using helpers instead of facades. They can clean things up

Consider using helpers instead of facades. They can clean things up

This is largely a matter of personal preference, but calling a global function instead of having to import a class and statically call a method feels nicer to me.

Bonus points for session('key') syntax.

Use short operators

32

๐Ÿ”ฅ Use short operators

Use short operators

PHP has many great operators that can replace ugly if checks. Memorize them.

Be friends with your IDE

31

๐Ÿ”ฅ Be friends with your IDE

Be friends with your IDE

Install extensions, write annotations, use typehints. Your IDE will help you with getting your code working correctly, which lets you spend more energy on writing code that's also readable.

Consider single-action controllers

30

๐Ÿ”ฅ Consider single-action controllers

Consider single-action controllers

If you have a complex route action, consider moving it to a separate controller.

For OrderController::create, you'd create CreateOrderController.

Another solution is to move that logic to an action class โ€” do what works best in your case.

Don't use a controller namespace

29

๐Ÿ”ฅ Don't use a controller namespace

Don't use a controller namespace

Instead of writing controller actions like [email protected], use the callable array syntax [PostController::class, 'index'].

You will be able to navigate to the class by clicking PostController.

Use custom config files

28

๐Ÿ”ฅ Use custom config files

Use custom config files

You can store things like "results per page" in config files. Don't add them to the app config file though. Create your own. In my e-commerce project, I use config/shop.php.

Don't use model methods to retrieve data

27

๐Ÿ”ฅ Don't use model methods to retrieve data

Don't use model methods to retrieve data

If you want to retrieve some data from a model, create an accessor.

Keep methods for things that change the model in some way.

Create query scopes for complex where()s

26

๐Ÿ”ฅ Create query scopes for complex where()s

Create query scopes for complex where()s

Rather than writing complex where() clauses, create query scopes with expressive names.

This will make your e.g. controllers have to know less about the database structure and your code will be cleaner.

Import namespaces instead of using aliases

25

๐Ÿ”ฅ Import namespaces instead of using aliases

Import namespaces instead of using aliases

Sometimes you may have multiple classes with the same name. Rather than importing them with an alias, import the namespaces.

Create single-use Blade includes

24

๐Ÿ”ฅ Create single-use Blade includes

Similar to single-use traits.

This tactic is great when you have a very long template and you want to make it more manageable.

There's nothing wrong with @including headers and footers in layouts, or things like complex forms in page views.

Create single-use traits

23

๐Ÿ”ฅ Create single-use traits

Create single-use traits

Adding methods to classes where they belong is cleaner than creating action classes for everything, but it can make the classes grow big

Consider using traits. They're meant primarily for code reuse, but there's nothing wrong with single-use traits

Use custom collections

21

๐Ÿ”ฅ Use custom collections

Use custom collections

Creating custom collections can be a great way to achieve more expressive syntax. Consider this example with order totals.

Don't use abbreviations

20

๐Ÿ”ฅ Don't use abbreviations

Don't use abbreviations

Don't think that long variable/method names are wrong. They're not. They're expressive.

Better to call a longer method than a short one and check the docblock to understand what it does

Same with variables. Don't use nonsense 3-letters abbreviations

Create fluent objects

19

๐Ÿ”ฅ Create fluent objects

Create fluent objects

You can also create objects with fluent APIs. Gradually add data by with separate calls, and only require the absolute minimum in the constructor.

Each method will return $this, so you can stop at any call.

Use Data Transfer Objects (DTOs)

18

๐Ÿ”ฅ Use Data Transfer Objects (DTOs)

Use Data Transfer Objects (DTOs)

Rather than passing a huge amount of arguments in a specific order, consider creating an object with properties to store this data.

Bonus points if you can find that some behavior can be moved into to this object.

Don't just write procedural code in classes

17

๐Ÿ”ฅ Don't just write procedural code in classes

Don't just write procedural code in classes

This ties the previous tweet with the other tips here. OOP exists to make your code more readable, use it. Don't just write 400 line long procedural code in controller actions.

Here's code from my first Laravel project ๐Ÿ˜ฌ

Dedicate a weekend towards learning proper OOP

16

๐Ÿ”ฅ Dedicate a weekend towards learning proper OOP

Know the difference between static/instance methods & variables and private/protected/public visibility. Also learn how Laravel uses magic methods.

You don't need this as a beginner, but as your code grows, it's crucial.

Create helper functions

15

๐Ÿ”ฅ Create helper functions

Create helper functions

If you repeat some code a lot, consider if extracting it to a helper function would make the code cleaner.

Avoid helper *classes*

14

๐Ÿ”ฅ Avoid helper *classes*

Avoid helper *classes*

Sometimes people put helpers into a class.

Beware, it can get messy. This is a class with only static methods used as helper functions. It's usually better to put these methods into classes with related logic or just keep them as global functions.

Extract methods

13

๐Ÿ”ฅ Extract methods

Extract methods

If some method is too long or complex, and it's hard to understand what exactly is happening, split the logic into multiple methods.

Consider using form requests

12

๐Ÿ”ฅ Consider using form requests

Consider using form requests

They're a great place to hide complex validation logic.

But beware of exactly that โ€” hiding things. When your validation logic is simple, there's nothing wrong with doing it in the controller. Moving it to a form request makes it less explicit

Use events

11

๐Ÿ”ฅ Use events

Use events

Consider offloading some logic from controllers to events. For example, when creating models.

The benefit is that creating these models will work the same everywhere (controllers, jobs, ...) and the controller has one less worry about the details of the DB schema

Create model methods for business logic

10

๐Ÿ”ฅ Create model methods for business logic

Create model methods for business logic

Your controllers should be simple. They should say things like "create invoice for order". They shouldn't be concerned with the details of how your database is structured.

Leave that to the model.

Create action classes

9

๐Ÿ”ฅ Create action classes

Create action classes

Let's expand on the previous example. Sometimes, creating a class for a single action can clean things up.

Models should encapsulate the business logic related to them, but they shouldn't be too big.

Create variables when they improve readability

7

๐Ÿ”ฅ Create variables when they improve readability

Create variables when they improve readability

The opposite of the previous tip. Sometimes the value comes from a complex call and as such, creating a variable improves readability & removes the need for a comment.

Remember that context matters & your end goal is readability

It's about the *micro*

3

๐Ÿ”ฅ It's about the *micro*

Using some "macro" philosophy for structuring your code, like hexagonal architecture or DDD won't save you.

A clean codebase is the result of constant good decisions at the micro level.

We're writing a book, you can get it for free here.