I'm in the process of designing the base architecture of a web application. The project follows the Domain-Driven Design approach because the business model and logic is very complex.
The project also aims to be a SOA project (Service Oriented Architecture). So I'm learning a lot about Services and how to construct the project around it.
Following a previous question of mine, I have a question regarding associations in model classes.
I understand that model classes shouldn't know and do anything related to persistence. However I have trouble deciding for situations with association between model classes.
For example:
class Person
class Car has one driver (for the example)
Where should the getDriver and getCars be?
in the model classes: $car->getDriver()
in the service layer with primitive types: $personService->getPerson($car->getDriverId())
in the service layer using OOP: $carService->getDriver($car)
Solution 1. seems the more natural. I'm using Doctrine 2, so the model associations are handled with DB mapping annotations. That way, the model doesn't do anything related to persistence (even though it does through Doctrine actually). It's my favorite solution, but then what's the point of the Service except load the list of "cars" to start with?
Solution 2. seems just stupid because it throws away OOP and the Model/Service user has to know about the Database model to fetch association (he has to know that this ID is a "Person" id). And he has to do the association himself.
Solution 3. is a bit better than solution 2, but still where is the OOP in that?
So, for me solution 1. is the best. But I have seen Solution 2. and Solution 3. used in real projects (sometimes mixed together), and so I have doubts.
And the question becomes more complex when there are additional parameters, for example:
$person->getCars($nameFilter, $maxNumberOfResults, $offset);
(in this case, it really looks like a SQL query/persistence query)
So, which one should be used for a Model/Service architecture on a project following the Domain-Driven Design approach? With SOA, should my model be only "dumb" data container with no logic? If so, then where is the DDD approach?
In the context of DDD, this is a problem of deciding whether a relationship between entities is expressed via direct object association vs. repository. Both approaches can be valid and depend on the nature of the relationship. For example, in your domain, a person may have a lot of cars associated with them, and it doesn't really make sense to have a direct association to the set of cars from the person entity. Remember, the job of the entity, or more specifically the aggregate root, is to protect invariants and enforce business rules. If the set of cars associated with a person isn't required for any behavior that exists on the person class, then there is no reason to put the association on the person entity. Further more, as your example shows, the query for cars may need to be filtered. To answer your question, I would place the responsibility of representing the person-to-cars relationship in a repository. SOA is orthogonal to DDD and is more focused on how business functionality is accessed and deployed. It is informative to consider the interplay between DDD and SOA from the perspective of hexagonal architecture also called onion architecture. Your domain is at the core, encapsulated by a set of application services which form an API facade around your domain. These are different from services in SOA, which are ports/adapters in the hexagonal/onion architecture and they serve ti expose these application services as SOA services.
If your project is DDD I don't get it why you want a Model/Service architecture. IMO this creates an anemic model and everything is pretty much procedural .
Now, being DDD it means you don't care for the db. You have though (at least logically) 2 models: the domain and the persistence. The Domain model deals with the associations in the most natural way, best suitable to represent the business case. 'Has one driver' or has many it's a db centric thinking that has no place in DDD. The Persistence model handles the way the Aggregate Root will be stored in the db (here's where you define the ORM entities and their relationships et all).
About your questions, first of all it matters the context and the purpose. If it's strictly for queries (to display to a user) then a simple model can be used, no need for DDD and business rules. The controller can ask directly the specialised query repository for the data, returned as a DTO.
If you want to update the Person or a car, then in the Application Layer (I'm usually using a command based approach so in my case all these happen in a command handler, but architecturally it's still part of the Application Layer) you can retreieve the AR best suited for the task from the (domain) repository. The domain repository knows that getPerson($id) should return a domain entity as opposed to the query repository which returns a simple DTO.
$person=$repo->getPerson($id);
//do stuff
$repo->save($person);
//optionally raise event (if you're using the domain events apprach)
But what's tricky is to decide what is the AR in what context. A car has one driver in what context? A driver really belongs to a car? Is there the concept of the owner? You have the Person class, but a person can be the driver or the owner (or not if it's a rental company). As you see, it pretty much depends on the domain and only after you have a clear image of the domain you can start thinking about how do you store data and what object (entity) is returned by the repository.
When thinking about what goes where, consider the purpose of both the service and the model. Services reside in the application layer while models reside in the domain layer. So, what does your application need to know about a Person? Not much, probably. The UI will likely send some ids to process with a requested action.
Here, the AR is a Driver model. Keep in mind that services may contain other services and that Doctrine entites are POPOs and do not need to be anemic. Also, try to decouple the development thought-processes away from the persistence. For example, a $driverId does not need to be an integer, it can be any unique identifier that is relevant to the domain.
// DriverService
// If more parameters are needed, consider passing in a command object
public function beginTrip($driverId, $carId, $fromLocationId, $toLocationId)
{
$driver = $this->repository->find($driverId);
$car = $this->carService->getAvailableCar($carId, $driverId);
$withItenerary = $this->locationService->buildItenerary(
[$fromLocationId, $toLocationId]
);
$driver->drive($car, $withItenerary); // actual 'driving' logic goes here
$this->eventService->publish(new BeginTripEvent($driver, $car, $withItenerary));
}
OK first I understand I mixed SOA and application services.
True. You are mixing Domain Layer (DDD) methods with Domain Objects and Service Layer (SOA) methods with Data Transfer Objects in the question.
Domain Layer objects are different objects than Service Layer objects! For example, Service Layer may have a CarDTO object instead of Car object and DriverDTO object instead of Driver object.
$car->getDriver() is a perfectly correct way to access Driver in Domain Layer, and can also be used in a Service Layer with a restriction that wherever Service consumer requests Car data, Service always returns a Car with a Driver.
$personService->getPerson($car->getDriverId()) is valid only in Service Layer and invalid in Domain Layer. The reason for this method is Driver data is too large and complex to be always returned with a Car. Thus Service provides a separate method to request Driver data.
$carService->getDriver($car) is invalid in Domain Layer and strange to see in Service Layer, because this construction means that Service consumer must send all Car data to the a CarService to get Driver data. It is better to send only CarID and maybe to a PersonService, not to a CarService (Variant 2).
A more complex example $person->getCars($nameFilter, $maxNumberOfResults, $offset); looks strange in Domain Layer, since it doesn't contain much Business Logic. But if changed into $CarService->getCars($nameFilter, $maxNumberOfResults, $offset); it becomes suitable in Service Layer for partial requests.
Related
Read a lot of articles where people say that I should return Domain Model... But that will ruin the whole idea of my repository then.
I am using laravel Eloquent Models (that, if I am correct - Domain Models). I have repository, so in case I will decide to switch to Doctrine, I could just swap it all in a service provider. But if I will return an instance of Domain Model (in this case, Eloquent Model) that makes no sense. I need to return the same result from repository, and DTO seems just what I need...
Can someone explain me why am I wrong?
What is what
First off I'd like to give my interpretation of the terms you're using.
DTO (Data transfer object)
Typically a PHP class with public properties
Only responsible for carrying data
Does not does not validate the data
Does not know about any implementation specific things (e.g. which ORM it's tied to)
Usually used for passing data between parts of the application, without either part knowing about the implementation of the other
Domain model
Typically a PHP class with private properties
Should only contain valid data
Validates that any changes result in a valid state
Does not know about any implementation specific things (e.g. which ORM it's tied to)
Repository
Is only responsible for storing and retrieving data
Does know about it's implementation (e.g. which ORM it's tied to)
Is not responsible for returning valid data
What this means for your case
The answer really depends on how pure you'd like to think in terms of splitting responsibilities.
If you're talking to purists they'd say that Eloquent models are not DTOs and they are not domain models either. A repository will return an eloquent model, which will be mapped to a domain model. That domain model can then be modified or converted to a DTO, which can be used for reading data. In this case the responsibilities are separated at the cost of having more code.
If you're talking to pragmatists they'd say that Eloquent models are DTOs and domain models (and sometimes even repositories as well). As the eloquent models are responsible for storing data, retrieving data, modifying data and passing this data to other parts of the application.
In the end it's all about preference. You can go pure, you can go pragmatic, you can even pick something in between. It purely depends on how advanced a coder you are, how big the project is, how maintainable it should be, how quick changes have to be made etc.
Tdlr
A repository can return a DTO or a domain model depending on how pure you're thinking in terms of separating responsibilities.
I've been investigating a lot about dependency injection theory and it makes great sense except for the fact that it seems to introduce complexity/bloat in certain scenarios.
Firstly, it is assumed that a DI Container instance is never passed into any object. Bad practice and all that...
For example: Consider a "user" class that relates to all other business objects created in the system by/for a specific user.
If a user instance is to be deleted, all related objects (i.e. records, files, images, etc.) also have to be deleted. Does this mean that an instance of each and every dependency is to be injected into the user instance to allow for the lookup and deletion of all related objects? i.e. an instance of ImageMapper (or ImageMapperFactory) must be passed in in order to delete all images created/uploaded by the user instance being deleted?
If not, is such a scenario a good example of where a service locator should be used?
I find it repeated over and over again in the articles & tutorials that a programmer must avoid using "new" within any class like the plague. However, is this really feasible for instances of controllers that may need to create a variety of views or the like?
A concrete example of adherence to the SOLID mantra, at least as far as DI is concerned, would be appreciated... One that makes it clear how one would either stuff instances of ALL required dependencies into a controller class or how best instances of such dependencies would be located or created?
I don't know PHP but I'll try to explain some things so your question doesn't get neglected, so bear with me. ;-)
I find that dependency injection works best by separating your application in layers:
Presentation Layer - Some (user) interface that provides interaction with your application.
Business Logic/Service Layer - The actual behavior of your application.
Persistence/Data Access Layer - The layer that stores/reads data from a back-end (try searching for repository pattern).
These layers all transfer data to each other in a structured way, using domain models. These models can be for example a user and an image.
When your application logic states that a user's images are to be deleted when a user is deleted you'll want this in the middle layer (Business Logic). The business logic layer calls the data access layer in order to delete entities.
Let's demonstrate using Python (I hope you can read that).
# Define a class that manages users.
class UserService:
# A constructor accepting dependent DAL instances.
def __init__(self, user_repo, image_repo):
self.user_repo = user_repo
self.image_repo = image_repo
def delete(self, user):
self.user_repo.delete(user)
self.image_repo.delete(user.profile_picture)
The repo arguments that go in the constructor are instances of repository classes, this is dependency injection (constructor injection).
The important thing to remember is that an object doesn't instantiate another object, it accepts instances of objects.
So I've been studying the role of the repository pattern as a means of decoupling the persistence layer from my models in an MVC framework. Prior to this, I might have my UserModel calling active record methods directly in order to store/retrieve domain objects.
Here's a sketch of what I'm thinking in regards to the call stack in a request that should create a new User:
Here are my questions:
Is this a correct implementation of the repository pattern?
I understand that the controller should take the user's information from the request and pass it into the model. How does that usually happen? Should the controller create a User object and then pass that into the model? I sure as heck don't wanna just pass in an array of values into the model--nor do I want to pass in 15 arguments to the model method that creates a user.
In order for this pattern to really work, it looks like to me I would need to have a domain object that is just a simple data structure with no behavior and then if I'm using an ORM, I would have an ORM object which will describe how the object is persisted. Initially I resisted this because it feels like duplicate code, but if I'm really separating persistence from the business logic, this would be needed right? For example, what if I went with an in-memory store? I would no longer use the ORM object.
Am I thinking correctly here? Is this acceptable. Please help me connect the dots in my head.
1. Is this a correct implementation of the repository pattern?
I'm not sure where you been doing that research, but you have got it wrong.
Repositories as for separating the domain objects from data mappers.
There no such thing as "models". Model in MVC design pattern is one of the to main layers: presentation layer and model layer.
And the repository pattern is incompatible with active record (anti)pattern, which combines domain and storage logic in single instance, thus causing a major SRP violation.
To use a real world example for, when and how to use a repository here is an example:
You are creating some document management tool, where said documents can come from several sources (for example: local SQL database, SOAP service and cache). In this situation you create a repository, which deals with the "routing" of storage. It is the part of application, that decides which data mapper to use for storing/retrieving each document.
The goal of repository is to separate the domain logic from the interaction with storage. For the system, that was described above, a repository would also let add new data sources, without need to rewrite large amounts of code (if any). You could just add another type of mapper for the document.
2. Should the controller create a User object and then pass that into the model?
To begin with, controller itself should not create anything. Instead your controller should use a factory for acquiring instance of the object that you need. This factory can be provided to the controller through constructor or some other method. This is called: Dependency Injection (to learn more about it, watch this lecture).
Also, as noted above, model is a layer, not any specific class or object. The responsibility of controller is to alter the state of model layer (by passing data to it). You could interact with domain objects and mappers (or repositories) directly in the controller, but it would mean leaking some of the business logic in the controller. It is recommended to instead use services, which then manipulates said domain objects and storage related structures.
As for the issue with 10+ parameter, that you would require for creation of new user account, let's assume you have action with following footprint:
public function postUser( Request $request )
{
....
}
If the action gets called with specific Request instance, you have two options how to deal with large amount of parameters:
Wrap the instance in a decorator, which would let you call a single method for forming the data from request in a specific array. Then you pass this array to the service(s).
Form the array inside the controller's action and pass it, where th data is required.
The former solution is more suited for large scale applications, where such formation of data would be required repeatedly though-out the code. But in a small/medium projects the second option is the common-sense approach.
Thing is, the job of the controller is to take the user's input, and distribute it to the model layer and current view. And formation of such array fits right-in with this mandate.
3. (..) main object that is just a simple data structure with no behavior and then (..)
No. Domain object is not "simple data". It is where most of the domain business logic resides in the application.
And forget about magical ORMs. First step for implementing a repository is to separate the domain and storage logic. Domain object handles the validation and business rules, mapper deals with persistence and data integrity (small example here).
Another thing that you must realize is that repositories for web application do not really interact with in-memory persistence (apart from cache). Instead your repository would be juggling mappers for different data sources.
Should the controller create a User object and then pass that into the model?
I'm not sure what you mean by "pass that into the model" -- the User object is the model. "Controller" and "model" represent different layers in the design, they are not specific objects, and there shouldn't be a separate UserModel object as you mentioned.
The repository interface itself is generally considered part of the model, though the domain objects shouldn't be saving themselves -- this should be done in the controller.
Your controller's job would then be to interpret the request and create a User object, then use the repository to save the user:
$user = new User(...); // based on Request
$repository->save($user);
it looks like to me I would need to have a domain object that is just a simple data structure with no behavior
This is not true, you can and should encapsulate behaviour in your domain objects. As for how persistence is actually implemented, a good ORM should take care of most of the details and you shouldn't have to create additional classes by hand.
Looking through several tutorials and books regarding data access in Zend Framework, it seems as if most people do data access within their models (Active Record Pattern) or even controllers. I strongly disagree with that. Therefore I want to have a Data Access Layer (DAL) so that my domain layer remains portable by not having any "ZF stuff" in it. I have searched around but have not really found exactly what I wanted. Heads up: I am new to ZF.
DAL structure
So, the first problem is where to place the Data Access Layer. While it could certainly be placed within the library folder and adding a namespace to the autoloader, that does not seem logical as it is specific to my application (so the applications folder is suitable). I am using a modular structure. I am thinking of using the below structure:
/application/modules/default/dal/
However, I am not sure how include this folder so that I can access the classes within the controllers (without using includes/requires). If anyone knows how to accomplish this, that would be super! Any other ideas are of course also welcome.
The idea is to have my controllers interact with the Data Access Objects (DAO). Then the DAOs use models that can then be returned to the controllers. By doing this, I can leave my models intact.
Implementation
In other languages, I have previously implemented DAOs per model, e.g. DAL_User. This resulted in an awful lot of DAO classes. Is there a smarter way to do this (using a single class does not seem easy with foreign keys)?
I would also appreciate suggestions on how to implement my DAO classes in ZF. I have not spent an awful lot of time reading about all of the components available for database interaction, so any ideas are very welcome. I suspect that there is something smarter than standard PDO available (which probably uses PDO internally, though). Name drops would be sufficient.
Sorry for the many questions. I just need a push in the right direction.
Well, the first thing you have to take into account when dealing with the Data Access Layer, is that this layer also have sub-layers, it's unusual to find folders called "dal" in modern frameworks (I'm taking as basis both Zend Framework and Symfony).
Second, about ActiveRecord, you must be aware that by default Zend Frameworks doesn't implement it. Most of the tutorials take the easiest path to teach new concepts. With simple examples, the amount of business logic is minimal, so instead of adding another layer of complexity (mapping between database and model's objects) they compose the domain layer (model) with two basic patterns: Table Data Gateway and Row Data Gateway. Which is enough information for a beginner to start.
After analyzing it, you will see some similarity between ActiveRecord
and Row Data Gateway patterns. The main difference is that
ActiveRecord objects (persistable entities) carries business logic and
Row Data Gateway only represents a row in the database. If you add
business logic on a object representing a database row, then it will
become an ActiveRecord object.
Additionally, following the Zend Framework Quick Start, on the domain model section, you will realize that there's a third component, which uses the Data Mapper Pattern.
So, if the main purpose of your DAL is to map data between business objects (model) and your storage, the responsibility of this task is delegated to the Data Mappers as follows:
class Application_Model_GuestbookMapper
{
public function save(Application_Model_Guestbook $guestbook);
public function find($id);
public function fetchAll();
}
Those methods will interact with the Database Abstraction Layer and populate the domain objects with the data. Something along this lines:
public function find($id, Application_Model_Guestbook $guestbook)
{
$result = $this->getDbTable()->find($id);
if (0 == count($result)) {
return;
}
$row = $result->current();
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
}
As you can see, the Data Mappers interacts with a Zend_Db_Table instance, which uses the Table Data Gateway Pattern. On the other hand, the $this->getDbTable->find() returns instances of the Zend_Db_Table_Row, which implements the Row Data Gateway Pattern (it's an object representing a database row).
Tip: The domain object itself, the guestbook
entity, was not created by the find() method on the DataMapper,
instead, the idea is that object creation is a task of factories
and you must inject the dependency in order to achieve the so called
Dependency Inversion Principle (DIP) (part of the SOLID principles). But that's
another subject, out of the scope of the question. I suggest you
to access the following link http://youtu.be/RlfLCWKxHJ0
The mapping stuff begins here:
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
So far, I think I have answered your main question, your structure will be as following:
application/models/DbTable/Guestbook.php
application/models/Guestbook.php
application/models/GuestbookMapper.php
So, as in the ZF Quick Start:
class GuestbookController extends Zend_Controller_Action
{
public function indexAction()
{
$guestbook = new Application_Model_GuestbookMapper();
$this->view->entries = $guestbook->fetchAll();
}
}
Maybe you want to have a separated folder for the data mappers. Just change:
application/models/GuestbookMapper.php
to
application/models/DataMapper/GuestbookMapper.php
The class name will be
class Application_Model_DataMapper_GuestbookMapper
I've seen that you want to separate your domain model objects into modules. It's possible too, all you need is to follow the ZF's directory and namespace guidelines for modules.
Final tip: I've spent a lot of time coding my own data mappers for
finally realize that it's nightmare to maintain the object mapping when
your application grows with a lot of correlated entities. (i.e Account
objects that contain references to users objects, users that contain
roles, and so on) It's not so easy to write the mapping stuff at this
point. So I strongly recommend you, if you really want a true
object-relational mapper, to first study how legacy frameworks perform
such tasks and perhaps use it.
So, take some spare time with Doctrine 2, which is the
one of the best so far (IMO) using the DataMapper pattern.
That's it. You still can use your /dal directory for storing the DataMappers, just register the namespace, so that the auto loader can find it.
In my opinion you should have a gateway abstraction (not just Database access) per model. A DAO is not enough. What if you need to get the data from the cloud at some point? This is quickly coming a reality. If you abstract your gateway logic into something generic and then implement it using a database you can have the best of both worlds.
The implementation of a specific gateway interface could use a generic data mapper if you so chose. I work for a small company and have always just created my implementation using PDO. This lets me be close enough to the database to deal with any interesting bits of SQL I might need but am able to support a very abstracted interface.
I have not used the Zend Framework at all. I do not know if they have data-mapper tools that could help you implement the gateway interfaces.
The last few days, I have extensively read books and web pages about OOP and MVC in PHP, so that I can become a better programmer. I've come upon a little problem in my understanding of MVC:
Where do I put a mysql_query?
Should I put it in the controller and call a method on a model that returns data based on the provided query? Or should I put it in the model itself? Are both of the options I'm providing total garbage?
Materials on the subject of MVC
You could have listed the books you were reading, because most (if not all) php books, which touch on MVC, are wrong.
If you want to become a better developer, i would recommend for you to start with article by Marting Fowler - GUI Architectures. Followed by book from same author - "Patterns of Enterprise Application Architecture". Then the next step would be for you to research SOLID principles and understand how to write code which follows Law of Demeter. This should cover the basics =]
Can I use MVC with PHP ?
Not really. At least not the classical MVC as it was defined for Smalltalk.
Instead in PHP you have 4 other patterns which aim for the same goal: MVC Model2, MVP, MVVM and HMVC. Again, I am too lazy to write about differences one more time, so I'll just link to an old comment of mine.
What is Model ?
First thing you must understand is that Model in MVC is not a class or an object. It is a layer which contains multitude of classes. Basically model layer is all of the layers combined (though, the second layer there should be called "Domain Object Layer", because it contains "Domain Model Objects"). If you care to read quick summary on what is contained in each part of Model layer, you can try reading this old comment (skip to "side note" section).
The image is taken from Service Layer article on Fowler's site.
What does the Controllers do ?
Controller has one major responsibilities in MVC (I'm gonna talk about Model2 implementation here):
Execute commands on structures from model layer (services or domain objects), which change the state of said structures.
It usually have a secondary responsibility: to bind (or otherwise pass) structures from Model layer to the View, but it becomes a questionable practice, if you follow SRP
Where do I put SQL related code ?
The storage and retrieval of information is handled at the Data Source Layer, and is usually implemented as DataMapper (do not confuse with ORMs, which abuse that name).
Here is how a simplified use of it would look like:
$mapper = $this->mapperFactory->build(Model\Mappers\User::class);
$user = $this->entityFactory->build(Model\Entities\User::class);
$user->setId(42);
$mapper->fetch($user);
if ($user->isBanned() && $user->hasBannExpired()){
$user->setStatus(Model\Mappers\User::STATUS_ACTIVE);
}
$mapper->store($user);
As you see, at no point the Domain Object is even aware, that the information from it was stored. And neither it cases about where you put the data. It could be stored in MySQL or PostgreSQL or some noSQL database. Or maybe pushed to remote REST API. Or maybe the mapper was a mock for testing. All you would need to do, to replace the mapper, is provide this method with different factory.
Also, please see these related posts:
understanding MVC Views in PHP
testable Controllers with dependencies
how should services communicate between each other?
MVC for advanced PHP developers
Model and Entity Classes represents the data and the logic of an application, what many calls business logic. Usually, it’s responsible for:
Storing, deleting, updating the application data. Generally it includes the database operations, but implementing the same operations invoking external web services or APIs is not an unusual at all.
encapsulating the application logic. This is the layer that
should implement all the logic of the application
Here is the MVC Sequence Diagram which shows the flow during a http request:
In this case Model is the best place to implement the code realted to access database.
The model contains the domain objects or data structures that represent the application's state. [wikipedia]. So the model would be the place to make the database call.
In the 'classic' (lack of a better word atm) MVC pattern the view would get the current state from the model.
Don't make the mistake by saying that the model is for accessing the database. It's more than just accessing the database.
For one, don't use mysql_query() and family; they're being deprecated, so consider also learning about PDO and/or mysqli.
The model takes care of data handling; it provides an interface to the controller by which it retrieves and/or stores information. So this would be a primary place where database actions take place.
Update
To answer a question asked by the OP in the comments: "one generic model for the whole db or a model for each table/action?"
Models are meant to abstract away individual tables (although there are models that exclusively handle a single table); for instance, instead of asking for all articles and then query the usernames for the authors you would have one function like this:
function getArticles()
{
// query article table and join with user table to get username
}
How many models you will create largely depends on how big the project is and how inter-related the data is. If you can identify independent groups of data, it's likely that you'd create a model for each group; but this is no hard & fast rule.
Data manipulation can be part of the same model, unless you want a clear separation between read-only and write-only models (I wouldn't know of a situation that warrants this, but who knows).
To go even further, your model should not contain the database access code. This belongs to another layer outside the Model/View/Controller: this is called the persistence layer, which can be implemented using an Object-Relational Mapper such as the popular Doctrine 2 for PHP.
This way, you never touch any (my)SQL code. The persistence layer takes care of this for you.
I really advise you to have a look at a Doctrine tutorial, this is a really professional way to create your applications.
Instead of working with raw data loaded from the database, you create objects that hold your data, and the behavior associated with it.
For example, you might have a User class, such as:
class User
{
protected $id;
protected $name;
protected $privileges;
public function setName($name) { ... }
public function getName() { ... }
public function addPrivilege(Privilege $privilege) { ... }
public function getPrivileges() { ... }
}
You controller will only interact with objects:
class UserController
{
public function testAction()
{
// ...
$user = $em->getRepository('User')->find(123); // load User with id 123
$user->setName('John'); // work with your objects,
echo $user->getName(); // and don't worry about the db!
$em->flush(); // persist your changes
}
}
Behind the scenes, the ORM takes care of all the low-level work of issuing a SELECT query, instantiating your object, detecting modifications to your object, and issuing the necessary UPDATE statement!