Right now, I'm programming in PHP/Laravel, but I think this might apply to any other MVC framework. I'll use PHP/Laravel syntax.
I have an app that will need a very basic audit trail. The audit table (audit_event) in the databse is something like:
(id, user_id, event_id, description, occured_at)
As you guess, the user_id is the user that caused the event_id. The description is here if you need to be more verbose, occured_at is the timestamp for the event.
Now, I created an AuditEvent model that has the relations to User and Event. I also wrote the relations from User and Event to AuditEvent.
The function to write an audit event is somethin as simple as:
public static function audit($event, $description = "") {
$id = \Auth::user()->id;
$ae = new AuditEvent();
$ae->user_id = $id;
$ae->event_id = $event;
$ae->description = $description;
$ae->save();
return null;
}
My question is... where should this function be? Should it be in the Model, or should I create a Controller AuditEventController and place it there?
When I call the function, I must include
use \App\Controllers\AuditEventController
and call it
AuditEventController::audit(5, "whatever")
I know placing the function in the Model will also work, but... what is the correct thing to do to comply with MVC?
How you go about conforming to an MVC architecture is entirely up to you. Laravel does not provide the Model location explicitly so that developers can decide. With that said, since this is something that is going to be doing a CRUD operation it could go in a Model.
You would run your checks in the controller and if everything passed you'd pass a reference to your audit method inside your model.
You mentioned that you need to include use \App\Controllers\AuditEventController with it, so then I'd say put this in your controller and create the actual method that saves it in your model.
Related
I have built a small PHP MVC framework and just want to clarify the best way to get data from one model into another. For example:
I have a Users_model that contains a method called get_users().
I also have Communications_model that needs to get specific or all user data and as such needs to access the get_users() method from the Users_model.
Is it best practice to:
a) Instantiate the Users_model in a controller and pass the data from the get_users() method into the Communications_model?
b) Instantiate the Users_model inside the Communications_model and run get_users() from there, so it can be accessed directly?
c) Another way?
Many thanks for any help.
It depends of your motive behind this.
If you want effect on result, then using well know library, like Doctrine etc. should be your choice.
If you want to learn design patterns, then you should get read about ActiveRecord or DataMapper + Repository patterns. Then implements both and check out.
If you want your code, this way - ORM should represent relations of data, then you should ask what it more important? If you menage communication (bus, train), then user can be there assigned and getting users from communication is OK. If user have communication (like car), then relation is reversed.
All depends, what is you motive behind this. Using library, like Doctrine, could you help you running you application. If you want learn design patterns, then check out both options to get some experience.
What you call "users model" is a repository. And what you call "communication model" looks like a service.
Your communication service should have the user repository passed in constructor as a dependency.
I honestly think, that a huge part of your confusion is that you try to call all of those things "models". Those classes are not part of the same layer. You migth find this answer to be useful.
All are possible ways but what I usually do is, whenever there is any function that I think would be reused a number of times by a number of objects, I declare it as static.
It would save the effort of playing with object declaration and would be easily accessible by ClassName::function();
Again, it's a design choice, usually objects are declared right there in the controller and used as per the need but just to save declaration of objects again and again I follow the approach of declaring function static.
The simple principle here is using the __construct() (constructor) to build the object with the relevant properties from the Database. The User Model will have a static function (therefore accessible through any scope) to create an array of instanced objects by simply passing the model data through a new self() which returns the instance.
The concept is you end up with an array of User_Model instances each being a build of the Database columns to properties. All that's left is to create the Database Model and the functions to retrieve the columns and data.
class Communications_Model {
private $_all_users;
public function getUsers() {
$this->_all_users = Users_Model::loadAllUsers();
}
}
class Users_Model {
private $_example_property;
public function __construct($user_id) {
$data = SomeDatabaseModel::getConnection()->loadUserFromDatabase((int)$user_id);
$this->_example_property = $data['example_column'];
}
public static function loadAllUsers() {
$users = array();
foreach(SomeDataModel::getConnection()->loadAllUsers() as $data) {
$users[] = new self($data['user_id']);
}
return $users;
}
}
Of course, now, you have a $_all_users; property that has an array of instanced User Models containing the data.
I have a model named Message, which is an internal notification in my website.
I have a controller, RegistrationController that handles when a new person registers with my website. When this happens I send a Message to all users.
This is how the code involved looks like:
public static createMessage($receiver, $content)
{
$message = new Message;
$message->receiver = $receiver;
$message->content = $content;
$message->save(false);
}
It is called like this in the RegistrationController.php
foreach($users as user)
Message::createMessage($user->ID, $content);
What is the best approach and that it won't violate mvc?
Inside the Message model I add the createMessage() function. It doesn't require imports.
Or I create a MessageController and add that function inside? If I do version 2 then I need to include MessageController in the RegistrationController.
Any better idea.
Which version would produce better code that can better be maintained? Please quantify your answer to avoid opinions.
Doing MVC is a style of programming.
There is no restriction where to put a logic. You can put it in Models or Controllers.
Which ever best suit your work style, use it.
I usually put in Controller the logics that interact with users through interfaces. (Get values from interfaces)
And put in Models the logics that help business rules. (Do things with the value from interface and database)
If you decide to put your Message logic as Controller, you do not need to include MessageController.
But make sure in the /config/main.php you include this:
'application.controllers.*'
Please be brutally honest, and tear my work apart if you have to.
So I'm re-writing a small web-application that I recently made. The reason for this is simply that the code got pretty messy and I want to learn and apply better OO design. What this application should do is just simple CRUD.
I have a database with 3 tables, companies and partners which are in no relation to each other and city which has a 1:n relation with companies and partners. Very simple, really. Now, I have several questions which i will state at the end of my post. Here i'll just try to explain:
My first approach was that I created classes company, partner and city, fetched all datasets from the database and created objects from that:
class company {
private $id = null;
private $name = null;
private $city = null;
//many more attributes
function __construct( $id, $name, $city, [...] ) {
$this->id = $id;
$this->name = $name;
$this->city = $city;
//huge constructor
}
/*
* getters + setters here
*
* no need to paste the partner class as it looks just like this one
*
*/
}
And that is all these classes did. I fetched every dataset from the database and constructed company, partner and city objects (the attribute city within these classes is an object with several attributes itself) and saved them into two arrays arr_companies and arr_partners, which then held these objects...and it worked fine like that.
Now, what I wanted is to update, insert, delete into the database, and all 3 classes (city, company, partner) need this functionality. My approach was that I created a new class with a constructor that would basically take 2 strings command and object, e.g. ('update', 'company') and it would then update the company directly in the database leaving my objects untouched. That made me really sad, because I had such nicely constructed objects and I didn't know how to make use of them.
Questions:
Is it bad to have such huge constructors (my biggest one would take
28 parameters)?
Should you have a separate class for database
operations or is it better to have maybe an abstract class or
interface for it and let the subclasses themselves handle update, delete, insert?
Is it common to just write, delete from the database whenever or should I just apply these changes to my objects and only execute the commands to the database later, for example when the session ends?
I figure an application like this must have been done a fantastillion times before. What is the proper approach here? create objects, work with objects, save them to the database?
I have so many questions but I think many of them I just don't know how to ask.
Please note that if possible I would not like to use an ORM at this point.
Thank you very much for your time.
Questions posed in OP:
"Is it bad to have such huge constructors (my biggest one would take 28 parameters)"?
Yes. Imagine the calling code. You would have to pass 28 different values, not to mention each call would have to respect the exact order specified in the constructor. If one parameter was out of place, you could wreck havoc with parameter dependent algorithms. If you really need to pass a large number of parameters, I would recommend passing them in as an array (posted an example to another SO question).
"Should you have a separate class for database operations or is it better to have maybe an abstract class or interface for it and let the subclasses themselves handle update, delete, insert?"
Generally speaking, when creating classes, you want to try to identify the nouns that best represent your business needs. In your specific case you would probably have three classes; Company, Partner, and City.
Now within each class (noun), your methods would be in the form of verbs, so symantically your calling code makes sense: if ($company->getName() === 'forbes')
As you mentioned, each class needs a database object (dbo) to work with, so you could implement any number of patterns to expose datase connections to your classes; singleton, singleton with factory, or dependency injection, etc.
Abstract (parent) classes are great for sharing common algorithms across child classes, and should be identified when you are in the psuedo-code stage of your design. Parent classes also allow you to force child classes to have methods by declaring abstract methods within the parent.
Interfaces are a useful tool in certain situations, but I find they are less flexible than declaring abstract methods in parent class. But are good in situations where classes do not share a common parent.
"Is it common to just write, delete from the database whenever or should I just apply these changes to my objects and only execute the commands to the database later, for example when the session ends"?
CRUD activity should happen at the time the action is executed. If you wait for the session to end, you may run into situations where a session is pre-maturely ended due to a user closing a browser, for example. To better protect your data you can wrap your CRUD activity within transactions.
If you are running a high-traffic application, you can implement a queuing system and queue up the work to be done.
"I figure an application like this must have been done a fantastillion times before. What is the proper approach here? create objects, work with objects, save them to the database"?
You are correct, this has been done before, and are commonly referred to as ORMs (object relation mappers). Basically, an ORM will introspect your database schema, and create objects (and relations) which represent your schema. So instead of working with native SQL, you are working with objects. Although you can use SQL for custom business needs, but in the case of Doctrine, you would use Doctrine Query Language (DQL) vs native SQL.
An ORM I would highly recommend is Doctrine.
If you do not want to use an ORM, you can add CRUD methods to your primary classes. I Opted for an interface so your classes don't have to extend from a parent comprised of database operations. Also, check out this post on using a singleton/factory for exposing your classes database object(s).
Consider the following:
// Company.php
class Company implements iDatabaseOperation
public function delete()
{
// Lets use a DBO singleton/factory for DB access
// Uses PDO, which is strongly recommended
$dbo = Database::factory(Database::DATABASE_NAME);
$dbo->beginTransaction();
try {
$sql =
"DELETE FROM " .
" company " .
"WHERE " .
" id = :companyId " .
"LIMIT 1";
$stmt = $dbo->prepare($sql);
$stmt->bindValue(':companyId', $this->getId());
$stmt->execute();
$dbo->commit();
} catch (Exception $e) {
$dbo->rollback();
error_log($e->getMessage();
$e = null; // Php's garbage collection sucks
}
}
}
// iDatabaseOperation.php
interface iDatabaseOperation
{
public function delete();
public function update();
public function insert();
}
It is realy bad. Code is completele unreadable in this case. You have options
to use setters (can add validation logic inside, better readability, no need to fill empty fields with null)
to have separate class builder for each domain class (takes some memory for additional object). Example in java hope you can understand:
class CompanyBuilder {
private final Company c;
public CompanyBuilder() {
c = new Company();
}
CompanyBuilder addId(String id){c.id = id;}
// id should be package visible and class should be located in the same package with builder
CompanyBuilder addName(String name){...}
CompanyBuilder addCity(String city){...}
Company build(){ return c;}
}
hybrid solution to have methods to organise chain(worse debugging, better readability). In java will be methods:
class Company {
...
Company addId(String id){
this.id = id;
return this;
}
Company addName(String name){...}
...
}
Usage:
Company c = new Company().addId("1").addName("Name1");
maybe you can create more granular objects to reuse them later and add specific logic in correct place. For instance it can be Address(Location) object for company.
Follow single responsibility principle. SOLID description on wiki.
It helps to change database specific code without affection of other part of system in your case. Well, separate domain and database specific code, have common interface or abstract class(if you have common logic for all of domain classes - liskov principle). In subclasses implement domain specific part.
If you do not want to lose data you should save them each time or have cluster of servers or have distributed cache. If it is ok to lose save them in the end of session as batch. It will increase youre performance. Also you should save in transaction each time if you have concurrent updates.
Approach is get data from database/construct objects from this data or new objects/ work(update) objects/write data from objects to database
just write more code and read stackoverflow
Finally I suggest to read "Clean Code: A Handbook of Agile Software Craftsmanship" R.Martin.
You are essentially writing your own ORM. So, I wouldn't discount just switching to one that's already been written for you. The advantage to rolling your own is that you gain an understanding of how it works as your write it. But the disadvantage is that someone else has probably already done it better. But assuming you want to continue on...
General Advice: Remember to always break the problem down into simpler and simpler pieces. Each class should only perform a simple function. Also, you should not have to worry about caching updates... unless perhaps your database is on the other end of a remote connection over a modem.
Specific Advice follows:
I would setup your entity instance classes to house data and not to do a lot of data loading. Use other classes and logic for loading the data. I would use the constructor of the entity class only to populate the data that pertains to the class (and it's children).
A simple thing to do is to use static methods on the entity class for loading and saving data. E.g.
class city {
private $id = null;
private $name = null;
function __construct( $id, $name ) {
$this->id = $id;
$this->name = $name;
}
// getters and setters
...
// ---------------------
// static functions
// ---------------------
public static function loadById($cityId) {
// pull up the city by id
$retval = new city(row["id"], row["name"]);
// close db connection
return $retval;
}
public static function loadByCustomerId($customerId) {
// pull up multiple cities by customer id
// loop through each row and make a new city object
// return a hash or array of cities
}
public static function update($city) {
// generate your update statement with $city->values
}
// other methods for inserting and deleting cities
...
}
So now the code to get and update cities would look something like this:
// loading city data
$city = city::loadById(1); // returns a city instance
$cities = city::loadByCustomerId(1); // returns an array of city instances
// updating city data
$city->name = "Chicago"; // was "chicago"
city::update($city); // saves the change we made to $city
The static methods are not the best way to implement this, but it gets you pointed in the right direction. A repository pattern would be better, but that's beyond the scope of this one answer. I find that often I don't see the merit in a more involved solution like the repository pattern until I run into problems with the simpler solutions.
What you are doing looks greate. What you can add is an intermediate layer which maps your business object to your database(object relation mapping). There are a lot of object relational mapping api out there. Check this wikipedia list for ones you can use for PHP
I think a constructor with 28 parameters is too much, you should others classes managing some attributes having some stuff in common. You should give us what kind of others attributes you instanciated, and it could help you to find a way to make more common objects.
I think you should also create a class managing the operations and the database like a DBHandler with delete, update, and so on..
In my opinion, do modifications on tuples in your database directly after functions are called are important.
Why? Because it could avoid conflict, like the case you try to update an object which is supposed to be deleted for example, if you do modifications on your database at the end.
You might want to look at ruby on rails.
You don't necessarily have to switch over to it, but look at how they implement the MVC pattern and achieve CRUD.
When implementing models using the MVC pattern, how complex should my models be?
Let's say I have got a few tables like so:
User (id, password, created ...)
Emails(user_id, email ...)
Addresses (user_id, address ...)
I have got a controller called UserController. This controller should allow me to log users in, create users, etc.
<!-- language: php -->
class UserController{
public function create($array){
...
}
public function login($email, $password){
...
}
}
Should my models be very primitive, implemeting only CRUD operations via ORM? This would result in code like:
<!-- language: php -->
class UserController{
public function create($array){
$userModel->username = 'blah';
$userModel->blah = 'blah';
$id = $userModel->save();
$emailModel->id = $id;
$emailModel->email = "emailhere";
$emailModel->save();
//Do the same for addresses
}
public function login($email, $password){
...
}
}
Or, alternatively, I could have models that are more complex:
<!-- language: php -->
UserModel{
public function login($email, $password){
//Do the joining and checking here, then return true or false to the controller
}
}
Then in my controller:
<!-- language: php -->
userModel->login($mail, $password);
So, which is the better way? To stuff all the logic into models, or should I have models doing only the basic CRUD operations? Finally, how do I deal with table joins? Should they be dealt within the model, or in the controller?
Cheers
Most people think of the "Fat Models, skinny controllers" paradigm, and it works better in the long run.
A great rule of thumb is to think about your Models as their own entity, in the sense that if you were to move your models to a different framework for example, they would still be functional.
A simple example would be saving information about an order on an e-commerce website. Let's say you want to save information about Tax, namely how much Tax is on the order. An abstract way of doing this is...
$tax_amount = $order_amount * (TAX_PERCENTAGE / 100);
Should we do this in the controller or the model? Suppose we did it in the controller, well... in our create action and our update action we would be calculating the tax, which makes for harder to maintain code and should the business rules of the e-commerce website change (say, we start selling to Tax exempt businesses or overseas business) then we would have to change any controller that saves order information.
If we were to calculate Tax in our Order model however, we would be doing it once in our save() method, which would be called when editing and adding orders.
public function save() {
//calculate tax first
$q = $this->db->query($sql);
}
Imo, it's better to enforce business rules in your model because it makes for more portable code and far less headaches when it comes to maintaining your code. Of course, there are people who will disagree, and this is a very subjective area.
EDIT:
Applying this to the specific question you asked, think about whether you would ever need the login() method anywhere else but your User model? It's possible you might want to split your models into different, more specific ones. But you could extend from your User model in that case.
What about if you were to take away your controller completely? Or if you wanted to interface with your models in an entirely different way (say via a different framework in the future). Thinking in this way you would be far better off with your login method in your User model.
Personally, I would be creating a login method on my model because it is an operation on data and that is what our models are for. I would also be creating a loginAction() method on my controller which would initiate the login() method on our model and perform any other action (for example, log failed attempts/redirect) that has to happen on post-login, should it be successful or unsuccessful. An example loginAction() may look as follows...
class UserController extends GenericController {
public function loginAction() {
$post = $this->form->getPost();
if(UserModel::login($post)) {
//do something
} else {
//do something else
}
}
}
All functionality which will or could be reused at different parts in the application should be accessbile globally, so that the coupling is low and there is no need to redeclare it.
I think you need an additional model for authorization and/or the current system parameters. The AuthModel could store information about the different authorization roles and the SysModel stores application parameters like the default login settings (e.g. use cookies yes or no).
The login method could be placed in the AuthModel then, which should be a good place in my opinion. Also the models are responsible to validate the inputted data, so the creation of new users should be in the UserModel.
I'm creating an ORM in PHP, and I've got a class 'ORM' which basically creates an object corresponding to a database table (I'm aiming for similar to/same functionality as an ActiveRecord pattern.) ORM itself extends 'Database', which sets up the database connection.
So, I can call: $c = new Customer();
$c->name = 'John Smith';
$c->save();
The ORM class provides this functionality (sets up the class properties, provides save(), find(), findAll() etc. methods), and Customer extends ORM. However, in the future I may be wanting to add extra public methods to Customer (or any other model I create), so should this be extending ORM or not?
I know I haven't provided much information here, but hopefully this is understandable on a vague explanation, as opposed to posting up 300+ lines of code.
I agree with the other answers here - put the additional methods into a descendant class. I'd also add an asterisk to that though: each time you extend the class with extra methods, think about what you are trying to achieve with the extension, and think about whether or not it can be generalised and worked back into the parent class. For example:
// Customer.class.php
function getByName($name) {
// SELECT * FROM `customer` WHERE `name` = $name
}
// ** this could instead be written as: **
// ORM.class.php
function getByField($field, $value) {
// SELECT * FROM `$this->table` WHERE `$field` = $value
}
You're certainly thinking correctly to put your business logic in a new class outside your 'ORM'. For me, instead simply extending the ORM-class, I'd rather encapsulate it with a new, value object class to provide an additional degree of freedom from your database design to free you up to think of the class as a pure business object.
Nope. You should use composition instead of inheritance. See the following example:
class Customer {
public $name;
public function save() {
$orm = new ORM('customers', 'id'); // table name and primary key
$orm->name = $this->name;
$orm->save();
}
}
And ORM class should not extend Database. Composition again is best suited in this use case.
Yes, place your business logic in a descendant class. This is a very common pattern seen in most Data Access Layers generation frameworks.
You should absolutely extend the ORM class. Different things should be objects of different classes. Customers are very different from Products, and to support both in a single ORM class would be unneeded bloat and completely defeat the purpose of OOP.
Another nice thing to do is to add hooks for before save, after save, etc. These give you more flexibility as your ORM extending classes become more diverse.
Given my limited knowledge of PHP I'm not sure if this is related, but if you're trying to create many business objects this might be an incredibly time consuming process. Perhaps you should consider frameworks such as CakePHP and others like it. This is nice if you're still in the process of creating your business logic.
You're definitely thinking along the right lines with inheritance here.
If you're building an ORM just for the sake of building one (or because you don't like the way others handle things) than go for it, otherwise you might look at a prebuilt ORM that can generate most of your code straight from your database schema. It'll save you boatloads of time. CoughPHP is currently my favorite.
I have solved it like this in my Pork.dbObject. Make sure to check it out and snag some of the braincrunching I already did :P
class Poll extends dbObject // dbObject is my ORM. Poll can extend it so it gets all properties.
{
function __construct($ID=false)
{
$this->__setupDatabase('polls', // db table
array('ID_Poll' => 'ID', // db field => object property
'strPollQuestion' => 'strpollquestion',
'datPublished' => 'datpublished',
'datCloseDate' => 'datclosedate',
'enmClosed' => 'enmclosed',
'enmGoedgekeurd' => 'enmgoedgekeurd'),
'ID_Poll', // primary db key
$ID); // primary key value
$this->addRelation('Pollitem'); //Connect PollItem to Poll 1;1
$this->addRelation('Pollvote', 'PollUser'); // connect pollVote via PollUser (many:many)
}
function Display()
{
// do your displayĆng for poll here:
$pollItems = $this->Find("PollItem"); // find all poll items
$alreadyvoted = $this->Find("PollVote", array("IP"=>$_SERVER['REMOTE_ADDR'])); // find all votes for current ip
}
Note that this way, any database or ORM functionality is abstracted away from the Poll object. It doesn't need to know. Just the setupdatabase to hook up the fields / mappings. and the addRelation to hook up the relations to other dbObjects.
Also, even the dbObject class doesn't know much about SQL. Select / join queries are built by a special QueryBuilder object.