Lecture
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
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]);
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 (); }); }
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'); }
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.
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]);
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'));
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');
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 ();
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' ]); }
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.
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.
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 ();
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 ();
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) { // ... } });
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
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.
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.
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); })
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]);
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.
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.
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;
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!
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.
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.
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 (); });
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.
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 ())
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']); }
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!
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');
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
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!
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 ();
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 (...)
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?
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
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.
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.
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!
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
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.
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.
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.
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; }
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 (); } }
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', ]; } }
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'); } } }
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 (); }
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 ();
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 ());
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
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 ())
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.
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'));
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 |
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 |
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') |
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 ());
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');
{{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}}
Do not place logic in routes.
Try not to use raw PHP in Blade templates.
$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
Famworks
Terms: Famworks