I have got the task to maintain some legacy code made in Laravel. It is using Bouncer for access control. The application has serious performance problems, which I am analyzing. It uses Nova for GUI.
When I am using the Laravel Debugbar I can see, that certain calls generate over 33.000 models of (bouncer) abilities, for generating a list of 25 real world objects. The database abilities table contains only 113 row.
Is this what I have to expect?
If not, is there a source explaining the pitfalls of using Bouncer?
The documentation and the blog posts on Bouncer, don't touch the topic.
The code has the simplest implementation of Bouncer.
use Silber\Bouncer\Database\HasRolesAndAbilities;
class User extends Authenticatable implements CanResetPassword, Auditable
{
...
use HasRolesAndAbilities;
...
}
No use of Bouncer::allow() etc.
The code also generates too may SQL calls. I the call mentioned above Laravel Debugbar reports:
152 statements were executed, 143 of which were duplicated, 9 unique.
The former programmers had used Bouncer, not only to limit the access of certain pages/models, but also to restrict the access to every field in those models. And fields of related models too.
After cleaning the code, the problem has disappeared.
Related
I have a page for creating a driver and adding his cars - drivers/create. A driver must have at least one car.
So I keep all the logic of storing the driver info in DriverController#store, but I also need to save cars info. I feel it is not a correct way to store elements of a Car class in the DriverController.
What would be a correct (or just a better) way in my case?
You can create a public static store method in CarController, and then invoke the method in DriverController#store.
Or create a car in CarModule and invoke it in DriverController#store.
If you're using Eloquent ORM, Laracasts has a free video series on v5.4 from scratch.
Two of the videos show you one way to set up a one-to-many relationship, but using a blog with comments. You could follow their example but substitute blog with driver, and comments with cars.
Laravel 5.4 From Scratch: Eloquent Relationships and Comments
https://laracasts.com/series/laravel-from-scratch-2017/episodes/15
Laravel 5.4 From Scratch: Add Comments
https://laracasts.com/series/laravel-from-scratch-2017/episodes/16
There's also a lot of other ways to approach the problem, with the Repositories or Service Layers, but those can lead you down a rabbit hole.
I have watched many youtube guides/tutorials but those only tackle the coding part.
Whenever i start a project, i always start with a simple controller called main.
and 2 models.
For example: if i were to start an online store project. Then my models would be 'product_model' and 'user_model'. All database functions for users, i always put them in the 'user_model' and all database functions for products, i always put them in the 'product_model'.
user_model:
public function register(){
}
public function login(){
}
//more functions for user
product_model:
public function create_product(){
}
public function review_product(){
}
//more functions for product
My problem is that i easily get confused with my project and/or dissatisfied with how unorganized it is. especially when im more than halfway into the project and i accumulate hundreds of lines of codes.
I could try to organize them myself but at the end of the day, i'm just an amateur so i end up doubting myself. so i get no work done for 1 day(or doing work but redoing it again and again). then that snowballs to tomorrow and the day after that and so on and so forth.
So i want to ask to experienced programmers a basic guideline for me, when to create a new model and a new controller?
How do i group up functions and make them into a separate model?
Do i make a new model per table? and all database functions to that table i just write in the new model created for that table?
Or
Do i group up database functions based on what they do? for example: purchasing a product involves many separate database functions. so save them all inside purchase_model?
The answer to all of these questions is: it depends. Personally I think that kindof of flexibility is what makes coding so interesting.
As a general rule of thumb I try to keep all my classes less than 500-700 lines of code and functions less than 20 lines of code. If my class becomes larger than that I usually start a new one. With that being said, controllers I am fine with being larger as form validation and response logic can take up quite a few lines.
So let's take an example: user authentication system
I would have a controller that contains functions for login, registration, forgot password, and activation; another controller for user management that contains functions to delete, ban, unban, activate, and create new users; and then another controller for the users' profile that contains functions for editing their details and profile picture.
Now as user management and auth systems are typically reusable a library is better then using a model or models; but let's say we use models. I would have a model for each of the controllers outlined in the aforementioned paragraph and then a model for general "utility" functions like checking if the user is logged in .etc.
Generally
You have to decide:
How much code is too much for a controller/model?
(with above) Do I expect my code to grow? If so then I have to take into account how much when determining (1).
How should I group together functions? For this keep in mind separation of concerns e.g. auth functions shouldn't be grouped with database backup functions.
Am I doing too much in a particular function/model? If so, how should I separate these items so that I conform with DRY principles (chances are some code is reusable elsewhere even though its functionality is inherently different).
(with above) If this code is really that useful elsewhere, should I make it into a library/helper?
(and there are countless other things to take into consideration).
I think it is important to realize (especially as a beginner) that your coding style and the "techniques" and organization skills you use will be constantly evolving and so will your code. While it is nice to see that you want to learn the best practices - a lot of this will be dependent on what you want to achieve with your app and what level of mastery you are at in your coding career. Try and look at the bigger picture and realize in a year or two when you look at your code again you will probably say "what was I even thinking here?".
Side note: you could research the ORM approach to models (Laravel and a host of other frameworks use it) but CI has a more "whatever" approach to just about everything. If being forced to work a certain way makes you feel more secure, you might want to learn other "more advanced" and "newer" frameworks.
I have developed a system where various classes have attributes consisting of a custom formula. The formula can contain special tokens which refer to different types of object. For example an object of class FruitSalad may have the following attribute;
$contents = "[A12] + [B76]";
In somewhat abstract terms, this means "add apple 12 to banana 76". It can also get significantly more complex than that with as many as 15 or 20 references to other objects involved in one formula.
I have a trait which passes formulae such as this and each time it finds a reference to a model (i.e. "[A12]") it gets it from the database with A::find(12) and adds it to an array of component objects which can be used for other processes later on in the request.
So, in essence, it's a relationship. But instead of a pivot table to describe the relationship, there is a formula on the parent model which can include references to child models.
This is all working. Yay! But it's really inefficient because there are so many tiny queries to get single models as formulae are parsed. One request may quite easily result in hundreds of queries. Oops.
I see two potential options;
1. Get all my apples and bananas from the database at the start of the request and get them from an in-memory store instead of from the database when parsing a formula (is this the repository pattern??).
2. Create a custom relation type (something like hasManyFromFormula) which makes eager loading work so that the parsing becomes much simpler because the relevant apples and bananas would already be loaded into the parent model.
Is there a precedent for this? As for why I am doing it like this, it would a bit tough to explain in brief but suffice to say it is to support a highly configurable data retrieval system which supports as-yet unknown input data configurations.
Help!
Thanks,
Geoff
Am not completely sure if it is the best solution, but in the end I created a new directory class for basic components and then set it up in the app service provider as a singleton. The constructor for the directory class loaded all models of several relevant classes and made them available as collections throughout the app.
I am working with Laravel for almost two years and trying to understand all the benefits of using Repositories and DDD. I still struggle with how to use best practices for working with data and models for better code reusability and nicer Architecture.
I have seen other developers suggesting to generate models in factories and then use Repositories for saving these models like :
public function add(User $user)
{
return $user->save();
}
but what should I do, in case my user model has models related with it, like images, description and settings.
Should I create repository for each model and call ->add() function 4 times in the controller or should I place the saving logic inside the UserRepository ->add() function passing all models as well as user? Also, how about update function, that logic might also be quite complicated.
Update - what I need is a practical example with realization.
It's always difficult to deal with "right way" questions. But here is one way.
From a DDD perspective, in this specific context, treat the User object as an aggregate root entity and the other objects as child value objects.
$description = new UserDescripton('Some description');
$image1 = new UserImage('head_shot','headshot.jpg');
$image2 = new UserImage('full_body','fullbody.jpg');
$user = new User('The Name',$description,[$image1,$image2]);
$userRepository->persist($user);
First thing to note is that you if really want to try and apply some of the ddd concepts then it is important to think in terms of domain models without worrying about how to persist them. If you find that you are basically writing a CRUD app with a bunch of getters and setters and almost no business logic then pretty much forget about it. All you will end up doing is to add complexity without much value.
The persist line is where the user will get stored. And you certainly don't want to have to write a bunch of code to store and update the children. Likewise, it would normally be waste of effort to make repositories for value objects. If you are going this route then you really need some sort of database layer that understands individual objects as well as their relations. It is the relations that are the key.
I assume you are using Laravel's Eloquent active record persistence layer. I'm not familiar enough with it to know how easy it is to persist and update an aggregate root.
The code I showed is actually based more on Doctrine 2 Object Relation Mapper and pretty much works out of the box. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/ It is easy enough to integrate it with Laravel.
But even Doctrine 2 is largely CRUD oriented. In different domain contexts, the user object will be treated differently. It can start to get a bit involved to basically have different user implementations for different contexts. So make sure that the payoff in the domain layer is worth the effort.
I am not a PHP guy but from what I can find, Laravel an MVC framework, which has nothing to do with DDD.
Check this presentation, it does not to go to domain modelling, more concentrating on tactics but at least it has some goodness like command handling and domain events, briefly explains repositories with active record.
It also has references to two iconic DDD books at the last slide, I suggest you have a look at those too.
I'm wondering whether it is possible/advisable to use instances of a laravel model instead of using the Facade. Why all this trouble? I have a model which will be used with many tables, and i want to be setting the model's table automatically using the constructor. Is it possible/advisable, or what is the best approach of achieving the same end?
I have researched around with no much success.
UPDATE
THis is the scenario: an exam system, where different exams are "created". after an exam is created, a table is created in the database under the name Exam_#, where # is the ID of the exam. I want to access all exam from one model: Exam, but you see the particular table the model is to use can vary significantly, so we cannot set the table variable statically. The model shall not know the table it will use until it(the model) is called. So thats why i was wondering whether i can be passing the ID of the exam when i am calling the model or something like that. I hope my question is now more clear.
At the end of this, Laravel is still PHP... Anything you can do in PHP can be done in Laravel.
is (it) possible/advisable to use instances of a laravel model instead of using the Facade?
You can achieve exactly the same results using an instance of the model as you would using the static facade.
$user = User::find(1);
$user2 = new User();
$user2 = $user2->find(1);
Both instances of the above model contain the same results.
Is it advisable? I really don't like the static facades at all, they bring with them more trouble than they are worth, especially when it comes to testing (despite being able to mock them, they create tight coupling where most of us need loose coupling). My answer to this would be: don't use the facades at all.
What is the best approach of achieving the same end?
As #JoelHinz suggested, create a base model with common properties and then use the models as they are intended. i.e. ONE table to ONE model and create the relationships between them. Don't use the same model for multiple tables, this is not how Laravel models were intended and you will lose a lot of the power Eloquent provides by taking the approach you mentioned.
Updates from comments
To get you started with testing in Laravel this is a good end to end tutorial Tutsplus Laravel4 + Backbone. Ignore the backbone part, what you're interested in is the testing parts that start about a 1/3rd of the way down the page. This will get you testing controllers straight away and introduce you to the repository pattern to create testable DAL structures.
Once you get the hang of writing tests, it becomes very easy to write a unit test for anything. It may seem like a scary subject, but that is purely down to not understanding how it works, it really is quite simple. Take a look at the PHPUnit documentation as well, it is an excellent resource.