73 tips and tricks of Laravel and Eloquent in 2021

Lecture



73 tips and tricks of Laravel and Eloquent in 2021

1. Increments and decrements

Instead:

 $ article = Article :: find ($ article_id);
 $ article-> read_count ++;
 $ article-> save (); 

You can do:

 $ article = Article :: find ($ article_id);
 $ article-> increment ('read_count'); 

Will also work:

 Article :: find ($ article_id) -> increment ('read_count');
 Article :: find ($ article_id) -> increment ('read_count', 10);  // +10
 Product :: find ($ produce_id) -> decrement ('stock');  // -one 

2. X or Y methods

Eloquent has several functions that combine two methods, for example “make X, otherwise make Y”.

Example 1 - findOrFail ():

Instead:

 $ user = User :: find ($ id);
 if (! $ user) {abort (404);  } 

Use:

 $ user = User :: findOrFail ($ id); 

Example 2 - firstOrCreate ():

Instead of:

 $ user = User :: where ('email', $ email) -> first ();
 if (! $ user) {
   User :: create ([
     'email' => $ email
   ]);
 } 

Use:

 $ user = User :: firstOrCreate (['email' => $ email]); 

3. The boot () method of the model

The Eloquent model has a magic boot () method, where you can override the default behavior:

 class User extends Model
 {
     public static function boot ()
     {
         parent :: boot ();
         static :: updating (function ($ model)
         {
             // execute some logic
             // override any property, for example $ model-> something = transform ($ something);
         });
     }
 } 

Probably one of the most popular examples is setting the value of some field at the moment of creating an instance of a model. Suppose you want to generate a UUID field at this moment.

 public static function boot ()
 {
   parent :: boot ();
   self :: creating (function ($ model) {
     $ model-> uuid = (string) Uuid :: generate ();
   });
 } 

4. Relationship with condition and sorting

The usual way to define relationships is:

 public function users () {
     return $ this-> hasMany ('App \ User');    
 } 

But did you know that we can add where or orderBy here? For example, if you need a special relationship for certain types of users, organized by email, you can do this:

 public function approvedUsers () {
     return $ this-> hasMany ('App \ User') -> where ('approved', 1) -> orderBy ('email');
 } 

5. Model properties: timestamps, appends, and so on.

There are several “parameters” of the Eloquent model in the form of class properties. The most popular ones are probably the following:

 class User extends Model {
     protected $ table = 'users';
     protected $ fillable = ['email', 'password'];  // what fields can be filled in by performing User :: create ()
     protected $ dates = ['created_at', 'deleted_at'];  // what fields will be of type Carbon
     protected $ appends = ['field1', 'field2'];  // additional values ​​returned in JSON
 } 

But wait, there is more:

 protected $ primaryKey = 'uuid';  // should not be "id"
 public $ incrementing = false;  // and should not be auto increment
 protected $ perPage = 25;  // Yes, you can override the number of pagination entries (default is 15)
 const CREATED_AT = 'created_at';
 const UPDATED_AT = 'updated_at';  // Yes, even these names can also be overridden
 public $ timestamps = false;  // or not at all 

And there are more properties, for more information, read the code of the abstract Model class and see all the used traits.

6. Search multiple entries

Everyone knows the find () method, right?

 $ user = User :: find (1); 

It's amazing how few people know that he can accept multiple ID's as an array:

 $ users = User :: find ([1,2,3]); 

7. WhereX

There is an elegant way to transform:

 $ users = User :: where ('approved', 1) -> get (); 

AT:

 $ users = User :: whereApproved (1) -> get (); 

Yes, you can change the name of any field and add it as a suffix to the “where”, and it will work like magic. Also in the Eloquent ORM there are predefined methods related to the date and time:

 User :: whereDate ('created_at', date ('Ymd'));
 User :: whereDay ('created_at', date ('d'));
 User :: whereMonth ('created_at', date ('m'));
 User :: whereYear ('created_at', date ('Y')); 

8. Sorting with relationships

A little more than a "trick." What to do if you have forum threads, but you want to sort them by their latest posts? Quite a popular requirement in the forums with the latest updated topics at the top, right?

First describe a separate link for the last post in the topic:

 public function latestPost ()
 {
     return $ this-> hasOne (\ App \ Post :: class) -> latest ();
 } 

And then, in your controller, you can perform this "magic":

 $ users = Topic :: with ('latestPost') -> get () -> sortByDesc ('latestPost.created_at'); 

9. Eloquent :: when () - without “if-else”

Many of us write conditional requests with “if-else”, something like this:

 if (request ('filter_by') == 'likes') {
     $ query-> where ('likes', '>', request ('likes_amount', 0));
 }
 if (request ('filter_by') == 'date') {
     $ query-> orderBy ('created_at', request ('ordering_rule', 'desc'));
 } 

But the best way is to use when ():

 $ query = Author :: query ();
 $ query-> when (request ('filter_by') == 'likes', function ($ q) {
     return $ q-> where ('likes', '>', request ('likes_amount', 0));
 });
 $ query-> when (request ('filter_by') == 'date', function ($ q) {
     return $ q-> orderBy ('created_at', request ('ordering_rule', 'desc'));
 }); 

This example may not seem shorter or more elegant, but it would be more correct to forward parameters:

 $ query = User :: query ();
 $ query-> when (request ('role', false), function ($ q, $ role) { 
     return $ q-> where ('role_id', $ role);
 });
 $ authors = $ query-> get (); 

10. Default Model for BelongsTo Relationships

Suppose you have a post owned by the author, and Blade code:

 {{$ post-> author-> name}} 

But what if the author is removed or not installed for any reason? You will get an error like "property of non-object".

Of course, you can prevent this by doing the following:

 {{$ post-> author-> name ??  ''}} 

But you can do it at the level of an eloquent relationship:

 public function author ()
 {
     return $ this-> belongsTo ('App \ Author') -> withDefault ();
 } 

In this example, the relationship author () returns an empty App \ Author model, if the author is not attached to the post.

In addition, for the default model, you can assign default property values.

 public function author ()
 {
     return $ this-> belongsTo ('App \ Author') -> withDefault ([
         'name' => 'Guest Author'
     ]);
 } 

11. Sort by converter

Imagine that you have such a converter:

 function getFullNameAttribute ()
 {
   return $ this-> attributes ['first_name'].  ''.  $ this-> attributes ['last_name'];
 } 

Do you need to sort entries by the full_name field? This solution will not work:

 $ clients = Client :: orderBy ('full_name') -> get ();  // does not work 

The solution is quite simple. We need to sort the records after we received them.

 $ clients = Client :: get () -> sortBy ('full_name');  // works! 

Please note that the function name is different - it is not orderBy, it is sortBy.

12. Sort by default

What if you want User :: all () to always be sorted by the name field? You can assign a global stub (Global Scope). Let us return to the boot () method, which we have already mentioned above.

 protected static function boot ()
 {
     parent :: boot ();

     // Sort By Name In Alphabetical Order
     static :: addGlobalScope ('order', function (Builder $ builder) {
         $ builder-> orderBy ('name', 'asc');
     });
 } 

More information about Query Scopes here.

13. Raw expressions

Sometimes you need to add raw expressions to our Eloquent request. Fortunately, there are functions for this.

 // whereRaw
 $ orders = DB :: table ('orders')
     -> whereRaw ('price> IF (state = "TX",?, 100)', [200])
     -> get ();

 // havingRaw
 Product :: groupBy ('category_id') -> havingRaw ('COUNT (*)> 1') -> get ();

 // orderByRaw
 User :: where ('created_at', '>', '2016-01-01')
   -> orderByRaw ('(updated_at - created_at) desc')
   -> get (); 

14. Make a copy of the record in the database

Without a deep explanation, here is the best way to make a copy of a record in the database:

 $ task = Tasks :: find (1);
 $ newTask = $ task-> replicate ();
 $ newTask-> save (); 

15. Chunk () method for large tables

Not really about Eloquent, it's more about collections, but still a powerful method — to handle large data sets. The method allows to break the data set into pieces.

Instead:

 $ users = User :: all ();
 foreach ($ users as $ user) {
     // ... 

You can do:

 User :: chunk (100, function ($ users) {
     foreach ($ users as $ user) {
         // ...
     }
 }); 

16. Creating additional files when creating a model

We all know Artisan com *** y:

 php artisan make: model Company 

But did you know that there are three useful flags for creating additional model files?

 php artisan make: model Company -mcr 
  • -m will create a migration file
  • -c will create a controller (controller)
  • -r indicates that the controller should be a resource (resourceful)

17. Overwriting updated_at during save

Did you know that the method -> save () can take parameters? As a result, we can “ignore” the updated_at functionality, which by default should have set the current timestamp.

Look at the following example:

 $ product = Product :: find ($ id);
 $ product-> updated_at = '2019-01-01 10:00:00';
 $ product-> save (['timestamps' => false]); 

Here updated_at is rewritten by the preset value.

18. What is the result of the update () method?

Have you ever thought about what this code returns?

 $ result = $ products-> whereNull ('category_id') -> update (['category_id' => 2]); 

I mean that the update is running in the database, but what will this $ result contain?

Answer: affected lines. Therefore, if you need to check how many rows have been affected, you do not need to call anything - the update () method will return this number for you.

19. Convert brackets to Eloquent request.

What to do if you have AND and OR in your SQL query, like this:

 ... WHERE (gender = 'Male' and age> = 18) or (gender = 'Female' and age> = 65) 

How to convert this query to an eloquent query? This is the wrong way:

 $ q-> where ('gender', 'Male');
 $ q-> orWhere ('age', '> =', 18);
 $ q-> where ('gender', 'Female');
 $ q-> orWhere ('age', '> =', 65); 

The order will be wrong. The correct way is a little more complicated, using closures as subqueries:

 $ q-> where (function ($ query) {
     $ query-> where ('gender', 'Male')
         -> where ('age', '> =', 18);
 }) -> orWhere (function ($ query) {
     $ query-> where ('gender', 'Female')
         -> where ('age', '> =', 65); 
 }) 

20. orWhere with several parameters

You can pass an array of parameters in orWhere ().
“Normal” method:

 $ q-> where ('a', 1);
 $ q-> orWhere ('b', 2);
 $ q-> orWhere ('c', 3); 

You can do this:

 $ q-> where ('a', 1);
 $ q-> orWhere (['b' => 2, 'c' => 3]); 

31. Eloquent Queries

Laravel offers one of the most powerful implementations of Active-Record in the PHP world. Suppose you have an order table, and an Order Eloquent model:

 class Order extends Eloquent {} 

We can easily execute any number of database queries using simple, elegant PHP. No need to throw dirty SQL around the room. Let's take all the orders.

 $ orders = Order :: all (); 

Is done. Or maybe these orders should be returned in order, according to the release date. It is easy:

 $ orders = Order :: orderBy ('release_date', 'desc') -> get (); 

What if instead of retrieving the record, we need to save the new order in the database. Of course, we can do it.

 $ order = new Order;
 $ order-> title = 'Xbox One';
 $ order-> save (); 

Finished! With Laravel, tasks that were cumbersome to perform are ridiculously simple.


32. Flexible routing

Laravel is unique in that it can be used in several ways. Prefer a simpler, more intuitive routing system? Of course, Laravel can offer this quite easily using a close.

 Route :: get ('orders', function ()
 {
     return View :: make ('orders.index')
         -> with ('orders', Order :: all ());
 }); 

This may be useful for small projects and APIs, but you will most likely need controllers for most of your projects. This is normal; Laravel can do it too!

 Route :: get ('orders', 'OrdersController @ index'); 

Is done. Notice how Laravel grows with your needs? This level of accommodation is what makes the structure as popular as it is today.


33. Easy relationship

What do we do in cases where we have to define relationships? For example, the task certainly belongs to the user. How can we imagine this in Laravel? Well, assuming the required database tables are configured, we just need to configure the appropriate Eloquent models.

 class Task extends Eloquent {
     public function user ()
     {
         return $ this-> belongsTo ('User');
     }
 }
 class User extends Eloquent {
     public function tasks ()
     {
         return $ this-> hasMany ('Task');
     }
 } 

And with this we are done! Let's take all the tasks for user ID 1. We can do this in two lines of code.

 $ user = User :: find (1);
 $ tasks = $ user-> tasks; 

However, since we have defined the relationship from both ends, if we want to get a sample related to the task, we will do that too.

 $ task = Task :: find (1);
 $ user = $ task-> user; 


34. Model form binding

It is often useful to associate a form with a model. An obvious example of this is that you want to edit a record in your database. When attaching a model to a model, we can instantly fill in the form fields with values ​​from the corresponding row in the table.

 {{Form :: model ($ order)}}
     

{{Form :: label ('title', 'Title:')}} {{Form :: text ('title')}}

{{Form :: label ('description', 'Description:')}} {{Form :: textarea ('description')}} {{Form :: close ()}}

Since the form is now associated with a specific order instance, the inputs will display the correct values ​​from the table. Simply!


35. Database cache queries

Too many database requests, and very quickly your application can become like molasses. Fortunately, Laravel offers a simple mechanism for caching these requests using just one method call.

Let's take all the questions from the database, but we cache the query, since this table is unlikely to be updated frequently.

 $ questions = Question :: remember (60) -> get (); 

This is it! Now, over the next hour of page requests, this request will remain cached and the database will not be affected.


36. View composers

You will encounter situations where several types require a certain variable or part of the data. A good example of this is the navigation bar, which displays a list of tags.

Controllers are too simple to manage; Laravel offers browsing composers to manage such things.

 View :: composer ('layouts.nav', function ($ view)
 {
     $ view-> with ('tags', ['tag1', 'tag2']);
 }); 

With this code snippet, at any time when the layouts nav.blade.php is being loaded, it will have access to the $ tags variable, equal to the array provided.


37. Simple authentication

Laravel uses a simple authentication approach. Just pass the array of credentials, which are most likely obtained from the login form, to Auth :: purchase (). If the values ​​provided correspond to what is stored in the user table, the user will be logged in immediately.

 $ user = [
     'email' => 'email',
     'password' => 'password'
 ];
 if (Auth :: attempt ($ user))
 {
     // user is now logged in!
     // Access user object with Auth :: user ()
 } 

What if we need to log a user out of the system — maybe when the logout URI is removed? It is also easy.

 Route :: get ('logout', function ()
 {
     Auth :: logout ();
     return Redirect :: home ();
 }); 


38. Resources

Working RESTfully in Laravel has never been easier. To register a resourceful controller, simply call Route :: resource (), for example:

 Route :: resource ('orders', 'OrdersController'); 

With this code, Laravel will register eight routes.

GET ordersnGET orders: ordernGET orders createnGET orders: order editnPOST ordersnPUT orders: ordernPATCH orders: ordernDELETE orders: ordern

In addition, a companion controller can be generated from the command line:

 php artisan controller: make OrdersController 

Inside this generated controller, each method will correspond to one of the above routes. For example, orders will be displayed in the index method, the creation of orders will be displayed for creation, and so on.

We now have the necessary ability to easily create RESTful applications and APIs.


39. Blade Templating

Although, yes, PHP is by its nature a template language, it didn’t evolve to become too good. Everything is good; Laravel offers its Blade engine to fill the gap. Just name your views with the extension .blade.php, and they will be automatically analyzed accordingly. Now we can do things like:

 @if ($ orders-> count ())
     
  • @foreach ($ orders as $ order)
  • {{$ order-> title}} @endforeach @endif


40. Testing

Since Laravel uses Composer, we instantly get support for PHPUnit in a frame out of the box. Install the framework and run phpunit from the command line to test it.

Even better, however, Laravel offers a number of test assistants for the most common types of functional tests.

Let's check that the home page returns status code 200.

 public function test_home_page ()
 {
     $ this-> call ('GET', '/');
     $ this-> assertResponseOk ();
 } 

Or maybe we want to confirm that when sending a contact form, the user is redirected to the home page using a flash message.

 public function test_contact_page_redirects_user_to_home_page ()
 {
     $ postData = [
         'name' => 'Joe Example',
         'email' => 'email-address',
         'message' => 'I love your website'
     ];
     $ this-> call ('POST', '/ contact', $ postData);
     $ this-> assertRedirectedToRoute ('home', null, ['flash_message']);
 } 


41. Removed component

As part of Laravel 4.1, which is scheduled for release in November 2013, you can easily write a *** from Artisan SSH to your server and perform any number of actions. This is as simple as using the SSH facade:

 Ssh :: into ('production') -> run ([
     'cd / var / www',
     'git pull origin master'
 ]); 

Pass the array of commands to the run () method, and Laravel will do the rest! Now, since it makes sense to execute such a code as com *** from Artisan, you only need to run com *** from php artisan: make DeployCommand and insert the appropriate code into the fire brigade method to quickly create a dedicated com *** in deployment!


42. Events

Laravel offers an elegant implementation of an observer pattern that you can use in all applications. Listen to local events such as illuminate.query, or even fire and catch your own.

Mature use of events in an application can have an incredible effect on its maintainability and structure.

 Event :: listen ('user.signUp', function ()
 {
     // do whatever needs to happen
     // when a new user signs up
 }); 

Like most things in Laravel, if you prefer to refer to the name of a class rather than to close, you can freely do it. Laravel then resolves it from the IoC container.

 Event :: listen ('user.signUp', 'UserEventHandler'); 


43. View all routes

As the application expands, it can be difficult to see which routes have been registered. This is especially true if proper care has not been provided to your route.php file (i.e. Offensive implicit routing).

Laravel offers a com *** at useful routes, which will display all registered routes, as well as controller methods that they run.

 php artisan routes 


44. Queues

Think about when a user registers for your application. Probably a series of events should occur. It is necessary to update the database table, add a list of bulletins, add an invoice, send a welcome letter, etc. Unfortunately, such actions tend to take a long time.

Why make the user wait for these actions when we can instead throw them in the background?

 Queue :: push ('SignUpService', compact ('user')); 

Perhaps the most exciting part is that Laravel brilliantly offers support for Iron.io push queues. This means that even without an ounce of “worker” or “demon” experience, we can still use the queue features. Simply register the endpoint of the URL using the useful com *** at php artisan queue for Laravel: sign the com *** u, and Iron.io will check your selected URL every time a task is added to the queue.

Simple steps to increase productivity!


45. Simple check

When verification is required (and when it is not), Laravel comes to the rescue again! Using the Validator class is as intuitive as it can be. Just pass the object under check, as well as a list of rules for the make method, and Laravel takes care of the rest.

 $ order = [
     'title' => 'Wii U',
     'description' => 'Game console from Nintendo'
 ];
 $ rules = [
     'title' => 'required',
     'description' => 'required'
 ];
 $ validator = Validator :: make ($ order, $ rules);
 if ($ validator-> fails ())
 {
     var_dump ($ validator-> messages ());  // validation errors array
 } 

For example, you can choose one method:

$ order-> isValid (); 


46. ​​Tinker Tinker

Especially when you first learn Laravel, it's helpful to work with the kernel. Com *** Artistsan masters.

As part of version 4.1, com *** and tinker is even more powerful, Boris.n
$ php artisan tinker
> $ order = Order :: find (1);
> var_dump ($ order-> toArray ());
> array (...) 


47. Migrations

Think about migration as a version control for your database. At any time you can “roll back” all migrations, repeat them and much more. Perhaps the true power is to push the application to the production and run one com *** from the php artisan migration to instantly create your database.

To prepare the scheme for a new user table, we can run:

php artisan migrate: make create_users_table 

This will create a migration file, which you can then fill in according to your needs. After the migration is complete, php artisan will create a table. This is it! Need to cancel this creation? Easy! Reconfigure php-artisan: rollback.

Here is an example diagram for frequently asked questions.

public function up ()
 {
    Schema :: create ('faqs', function (Blueprint $ table) {
        $ table-> integer ('id', true);
        $ table-> text ('question');
        $ table-> text ('answer');
         $ table-> timestamps ();
     });
 }
public function down ()
 {
    Schema :: drop ('faqs');
 } 

Notice how the drop () method inverts up (). This allows us to roll back the migration. Isn't that much easier than arguing about a bunch of SQL?


48. Generators

While Laravel offers a number of useful generators, an incredibly useful third-party package called “Laravel 4 Generators” does it even more. Create resources, seed files, pivot tables, and migrations using a schema!

In this previous board, we were forced to manually write a diagram. However, with the generator package included, we can:

php artisan generate: migration create_users_table --fields = "username: string, password: string" 

The generator takes care of the rest. This means that with the help of two commands you can prepare and build a new database table.

Laravel 4 Generators can be installed via Composer.n

49. Teams

As noted earlier, there are many instances where it may be useful to write custom commands. They can be used to create applications, create files, deploy applications and everything in between.

Since this is such a common task, Laravel makes the team building process as simple as possible.

php artisan command: make MyCustomCommand 

This com *** will create the necessary template for your new user command. Then, from the newly created application commands MyCustomCommand.php, fill in the appropriate name and description:

protected $ name = 'command: name';
protected $ description = 'Command description.'; 

And finally, in the class method fire () of a class, perform any action that you need. As soon as you finish, the only remaining step is to register a com *** u with Artisan, starting with the Artisan.php application.

Artisan :: add (new MyCustomCommand); 

Believe it or not; this is it! Now you can call your user com *** at the terminal.


50. Mock Facades

Laravel makes heavy use of the facade pattern. This allows you to use pure static syntax, which you will surely like (Route :: get (), Config :: get (), etc.), but at the same time allows you to fully test behind the scenes.

Since these “base classes” are allowed from the IoC container, we can easily exchange these base instances using mocks for testing purposes. This allows such control as:

Validator :: shouldReceive ('make') -> once (); 

Yes, we call shouldReceive directly from the facade. Behind the scenes, Laravel uses the excellent Mockery structure for this. This means that you can freely use these facades in your code, while maintaining 100% testability.


51. Form Helpers

Because building forms can often be a cumbersome task, the Laravel form builder does this to facilitate the process, and also uses many of the features associated with building a form. Here are some examples:

{{Form :: open ()}}
    {{Form :: text ('name')}}
    {{Form :: textarea ('bio')}}
    {{Form :: selectYear ('dob', date ('Y') - 80, date ('Y'))}}
{{Form :: close ()}} 

What about tasks such as memorizing input from a previous form submission? Laravel can do it all automatically!


52. IoC container

Laravel is based on its powerful IoC container, which is a tool that helps manage class dependencies. It is noteworthy that the container has the ability to automatically allow classes without configuration!

Simply enter the dependency types inside the constructor and, after creating the instance, Laravel will use the PHP Reflection API to intelligently read type keys and try to enter them for you.

public function __construct (MyDependency $ thing)
 {
    $ this-> thing = $ thing;
 } 

As long as you request a class from the IoC container, this permission will be executed automatically.

$ myClass = App :: make ('MyClass'); 

It is important to note that controllers are always enabled from the IoC container. Thus, you can disable the dependencies of your controller for free, and Laravel will then do everything possible to introduce them for you. N

53. Wednesdays

Despite the fact that for medium projects one environment can work, for any size applications, several reasons will be necessary. Development, testing, production ... they are all necessary and require their own configuration.

Your test environment may be using an in-memory database for testing. Perhaps your development environment uses different API keys. Your production environment will probably use a custom database connection string.

Fortunately, Laravel simplifies our work. Look at the bootstrap start.php in your application.

Here is a basic demonstration of setting up a local and production environment based on the browser’s address bar.

 $ env = $ app-> detectEnvironment (array (
     'local' => array ('localhost'),
     'production' => array ('*. com')
 )) 

Although this will work, generally speaking, it is preferable to use environment variables for this sort of thing. Do not worry; this is still doable in Laravel! Instead, simply return a function from the container object's detectEnvironment method.

 $ env = $ app-> detectEnvironment (function ()
 {
     return getenv ('ENV_NAME')?: 'local';
 }); 

Now, if the environment variable (which you will do for production) is not set, the environment will be local by default.


54. Simple configuration

Laravel, again, uses a simple approach to customization. Create a folder in the application configuration that matches your desired environment, and any configuration files in it will take precedence if the environment name matches. So, for example, to install a different API key for billing for development, you can:

  app / config / development / billing.php
 return [
     'api_key' => 'your-development-mode-api-key'
 ]; 

The switcharoo configuration is automatic. Simply enter Config :: get ('billing.api_key'), and Laravel will correctly determine which file to read.


55. Superficial training Further training

When it comes to education, the Laravel community, despite its relatively young age, is endless. Less than a year later, half a dozen different books were published related to all development issues of Laravel.

Learn everything from the basics to testing, building and supporting large applications!


This is not a retelling of best practices like SOLID, patterns, etc., with adaptation to Laravel. Here are collected exactly the practices that are ignored in real Laravel projects. Also, I recommend to get acquainted with good practitioners in the context of PHP. See also the discussion of the good practices of Laravel.

56 Single responsibility principle

Each class and method must perform only one function.

Poorly:

 public function getFullNameAttribute ()
 {
     if (auth () -> user () && auth () -> user () -> hasRole ('client') && auth () -> user () -> isVerified ()) {
         return 'Mr.  '.  $ this-> first_name.  ''.  $ this-> middle_name.  ''.  $ this-> last_name;
     } else {
         return $ this-> first_name [0].  '.  '.  $ this-> last_name;
     }
 }

Good:

 public function getFullNameAttribute ()
 {
     return $ this-> isVerifiedClient ()?  $ this-> getFullNameLong (): $ this-> getFullNameShort ();
 }

 public function isVerifiedClient ()
 {
     return auth () -> user () && auth () -> user () -> hasRole ('client') && auth () -> user () -> isVerified ();
 }

 public function getFullNameLong ()
 {
     return 'Mr.  '.  $ this-> first_name.  ''.  $ this-> middle_name.  ''.  $ this-> last_name;
 }

 public function getFullNameShort ()
 {
     return $ this-> first_name [0].  '.  '.  $ this-> last_name;
 }

57 Thin controllers, thick models

At its core, this is just one of the particular cases of the principle of common responsibility. Take out working with data in the model when working with Eloquent or in the repository when working with Query Builder or "raw" SQL queries.

Poorly:

 public function index ()
 {
     $ clients = Client :: verified ()
         -> with (['orders' => function ($ q) {
             $ q-> where ('created_at', '>', Carbon :: today () -> subWeek ());
         }])
         -> get ();

     return view ('index', ['clients' => $ clients]);
 }

Good:

 public function index ()
 {
     return view ('index', ['clients' => $ this-> client-> getWithNewOrders ()));
 }

 class Client extends Model
 {
     public function getWithNewOrders ()
     {
         return $ this-> verified ()
             -> with (['orders' => function ($ q) {
                 $ q-> where ('created_at', '>', Carbon :: today () -> subWeek ());
             }])
             -> get ();
     }
 }

58 Validation

Following the principles of a thin controller and SRP, take validation from the controller to the Request classes.

Poorly:

 public function store (Request $ request)
 {
     $ request-> validate ([
         'title' => 'required | unique: posts | max: 255',
         'body' => 'required',
         'publish_at' => 'nullable | date',
     ]);

     ....
 }

Good:

 public function store (PostRequest $ request)
 {    
     ....
 }

 class PostRequest extends Request
 {
     public function rules ()
     {
         return [
             'title' => 'required | unique: posts | max: 255',
             'body' => 'required',
             'publish_at' => 'nullable | date',
         ];
     }
 }

59 Business Logic in Service Classes

The controller must perform only its direct duties, so make the entire business logic in separate classes and service classes.

Poorly:

 public function store (Request $ request)
 {
     if ($ request-> hasFile ('image')) {
         $ request-> file ('image') -> move (public_path ('images'). 'temp');
     }
    
     ....
 }

Good:

 public function store (Request $ request)
 {
     $ this-> articleService-> handleUploadedImage ($ request-> file ('image'));

     ....
 }

 class ArticleService
 {
     public function handleUploadedImage ($ image)
     {
         if (! is_null ($ image)) {
             $ image-> move (public_path ('images'). 'temp');
         }
     }
 }

60 Do not repeat (DRY)

This principle encourages you to reuse code wherever possible. If you follow the SRP principle, you avoid repetitions already, but Laravel allows you to also reuse views, parts of Eloquent queries, etc.

Poorly:

 public function getActive ()
 {
     return $ this-> where ('verified', 1) -> whereNotNull ('deleted_at') -> get ();
 }

 public function getArticles ()
 {
     return $ this-> whereHas ('user', function ($ q) {
             $ q-> where ('verified', 1) -> whereNotNull ('deleted_at');
         }) -> get ();
 }

Good:

 public function scopeActive ($ q)
 {
     return $ q-> where ('verified', 1) -> whereNotNull ('deleted_at');
 }

 public function getActive ()
 {
     return $ this-> active () -> get ();
 }

 public function getArticles ()
 {
     return $ this-> whereHas ('user', function ($ q) {
             $ q-> active ();
         }) -> get ();
 }

61 Prefer Eloquent to the query builder and to raw queries in the database. Prefer working with collections to work with arrays

Eloquent allows you to write the most readable code, and change the application functionality is disproportionately easier. Eloquent also has a number of handy and powerful tools.

Poorly:

 SELECT *
 FROM `articles`
 WHERE EXISTS (SELECT *
               FROM `users`
               WHERE `articles`.`user_id` =` users`.`id`
               AND EXISTS (SELECT *
                           FROM `profiles`
                           WHERE `profiles`.`user_id` =` users`.`id`) 
               AND `users`.`deleted_at` IS NULL)
 AND `verified` = '1'
 AND `active` = '1'
 ORDER BY `created_at` DESC

Good:

 Article :: has ('user.profile') -> verified () -> latest () -> get ();

62 Use mass assignment

Poorly:

 $ article = new Article;
 $ article-> title = $ request-> title;
 $ article-> content = $ request-> content;
 $ article-> verified = $ request-> verified;
 // Link an article to a category.
 $ article-> category_id = $ category-> id;
 $ article-> save ();

Good:

 $ category-> article () -> create ($ request-> all ());

63 Do not perform queries in views and use eager loading (problem N + 1)

Bad (101 requests to the database for 100 users will be executed):

 @foreach (User :: all () as $ user)
     {{$ user-> profile-> name}}
 @endforeach

Good (2 queries in the database for 100 users will be executed):

 $ users = User :: with ('profile') -> get ();

 ...

 @foreach ($ users as $ user)
     {{$ user-> profile-> name}}
 @endforeach

64 Comment on code, prefer readable method names to comments.

Poorly:

 if (count ((array) $ builder-> getQuery () -> joins)> 0)

It is better:

 // Determine if there are any joins.
 if (count ((array) $ builder-> getQuery () -> joins)> 0)

Good:

 if ($ this-> hasJoins ())

65 Take out JS and CSS from Blade and HTML templates from PHP code

Poorly:

 let article = `{{json_encode ($ article)}}`;

It is better:

 

 Or {{$ article-> name}}

In the Javascript file:

 let article = $ ('# article'). val ();

It is even better to use a specialized packet for transferring data from the backend to the frontend.

66 Configs, language files and constants instead of text in code

There should be no text directly in the code.

Poorly:

 public function isNormal ()
 {
     return $ article-> type === 'normal';
 }

 Return back () -> with ('message', 'Your article was successfully added');

Good:

 public function isNormal ()
 {
     return $ article-> type === Article :: TYPE_NORMAL;
 }

 return back () -> with ('message', __ ('app.article_added'));

67 Use community-based tools and practices.

Laravel has built-in tools for solving common problems. Prefer to use them using third-party packages and tools. Laravel developer, who came to the project after you, will have to study and work with a new tool for him, with all the ensuing consequences. Getting help from the community will also be much more difficult. Do not force a client or employer to pay for your bikes.

Task Standard tool Custom tool
Authorization Politicians Entrust, Sentinel and others. Packages, own solution
Work with JS, CSS, etc. Laravel mix Grunt, Gulp, third-party packages
Development environment Homestead Docker
Deploying Applications Laravel forge Deployer and many others
Testing Phpunit mockery Phpspec
e2e testing Laravel dusk Codeception
Work with DB Eloquent SQL Query Builder, Doctrine
Templates Blade Twig
Work with data Laravel Collections Arrays
Validation of forms Request classes Third-party packages, validation in the controller
Authentication Built-in functionality Third-party packages, own solution
API Authentication Laravel passport Third-party packages using JWT, OAuth
API creation Built-in functionality Dingo API and other packages
Work with database structure Migrations Working directly with the database
Localization Built-in functionality Third Party Packages
Real-time data exchange Laravel Echo, Pusher Packages and working with web sockets directly
Test data generation Seeder Classes, Model Factories, Faker Manual filling and packages
Scheduling tasks Laravel Task Scheduler Scripts and third-party packages
DB MySQL, PostgreSQL, SQLite, SQL Server MongoDb

68 Follow Community Naming Conventions

Follow PSR standards when writing code.

Also, observe other naming conventions:

what Rule Accepted Not accepted
Controller units h ArticleController ArticlesController
Routes mn h articles / 1 article / 1
Route names snake_case users.show_active users.show-active, show-active-users
Model units h User Users
Relationship hasOne and belongsTo units h articleComment articleComments, article_comment
All other relationships mn h articleComments articleComment, article_comments
Table mn h article_comments article_comment, articleComments
Pivot table model names in alphabetical order in units h article_user user_article, articles_users
Column in the table snake_case without model name meta_title MetaTitle; article_meta_title
Model property snake_case $ model-> created_at $ model-> createdAt
External key model name unit h and _id article_id ArticleId, id_article, articles_id
Primary key - id custom_id
Migration - 2017_01_01_000000_create_articles_table 2017_01_01_000000_articles
Method camelCase getAll get_all
Method in resource controller table store saveArticle
Method in the test camelCase testGuestCannotSeeArticle test_guest_cannot_see_article
Variables camelCase $ articlesWithAuthor $ articles_with_author
Collection descriptive, pl h $ activeUsers = User :: active () -> get () $ active, $ data
An object descriptive, units h $ activeUser = User :: active () -> first () $ users, $ obj
Indexes in config and language files snake_case articles_enabled ArticlesEnabled; articles-enabled
Representation snake_case show_filtered.blade.php showFiltered.blade.php, show-filtered.blade.php
Configuration file snake_case google_calendar.php googleCalendar.php, google-calendar.php
Contract (Interface) adjective or noun Authenticatable AuthenticationInterface, IAuthentication
Treit adjective Notifiable Notificationtrait

69 Short and readable syntax where possible

Poorly:

 $ request-> session () -> get ('cart');
 $ request-> input ('name');

Good:

 session ('cart');
 $ request-> name;

More examples:

Frequently used syntax Shorter and more readable syntax
Session :: get ('cart') session ('cart')
$ request-> session () -> get ('cart') session ('cart')
Session :: put ('cart', $ data) session (['cart' => $ data])
$ request-> input ('name'), Request :: get ('name') $ request-> name, request ('name')
return Redirect :: back () return back ()
is_null ($ object-> relation)? null: $ object-> relation-> id optional ($ object-> relation) -> id
return view ('index') -> with ('title', $ title) -> with ('client', $ client) return view ('index', compact ('title', 'client'))
$ request-> has ('value')? $ request-> value: 'default'; $ request-> get ('value', 'default')
Carbon :: now (), Carbon :: today () now (), today ()
App :: make ('Class') app ('Class')
-> where ('column', '=', 1) -> where ('column', 1)
-> orderBy ('created_at', 'desc') -> latest ()
-> orderBy ('age', 'desc') -> latest ('age')
-> orderBy ('created_at', 'asc') -> oldest ()
-> select ('id', 'name') -> get () -> get (['id', 'name'])
-> first () -> name -> value ('name')

70 Use IoC or facades instead of new Class

Introducing classes using the new Class syntax creates a strong pairing between parts of the application and makes testing difficult. Use a container or facades.

Poorly:

 $ user = new User;
 $ user-> create ($ request-> all ());

Good:

 public function __construct (User $ user)
 {
     $ this-> user = $ user;
 }

 ....

 $ this-> user-> create ($ request-> all ());

71 Do not work with data from a .env file directly.

Transfer data from the .env file to the configuration file and use config () in the application to use this data.

Poorly:

 $ apiKey = env ('API_KEY');

Good:

 // config / api.php
 'key' => env ('API_KEY'),

 // Use the data in the application
 $ apiKey = config ('api.key');

72 Store dates in a standard format. Use readers and converters for format conversion.

Poorly:

 {{Carbon :: createFromFormat ('Ydm Hi', $ object-> ordered_at) -> toDateString ()}}
 {{Carbon :: createFromFormat ('Ydm Hi', $ object-> ordered_at) -> format ('md')}}

Good:

 // Model
 protected $ dates = ['ordered_at', 'created_at', 'updated_at']
 // reader (accessor)
 public function getSomeDateAttribute ($ date)
 {
     return $ date-> format ('md');
 }

 // Template
 {{$ object-> ordered_at-> toDateString ()}}
 {{$ object-> ordered_at-> some_date}}

73 Other tips and practices

Do not place logic in routes.

Try not to use raw PHP in Blade templates.

74. orWhere with several parameters


“Normal” method:

 $q->where('foo1', 1); $q->orWhere('foo2', 2); $q->orWhere('foo3', 3); 

You can pass an array of parameters in orWhere() .

You can do it like this:

 $q->where('foo1', 1); $q->orWhere(['foo2' => 2, 'foo3' => 3]); 

Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Famworks

Terms: Famworks