Using Doctrine to abstract CRUD operations - php

This has bothered me for quite a while, but now it is necessity that I find the answer.
We are working on quite a large project using CodeIgniter plus Doctrine.
Our application has a front end and also an admin area for the company to check/change/delete data.
When we designed the front end, we simply consumed most of the Doctrine code right in the controller:
//In semi-pseudocode
function register()
{
$data = get_post_data();
if (count($data) && isValid($data))
{
$U = new User();
$U->fromArray($data);
$U->save();
$C = new Customer();
$C->fromArray($data);
$C->user_id = $U->id;
$C->save();
redirect_to_next_step();
}
}
Obviously when we went to do the admin views code duplication began and considering we were in a "get it DONE" mode so it now stinks with code bloat.
I have moved a lot of functionality (business logic) into the model using model methods, but the basic CRUD does not fit there.
I was going to attempt to place the CRUD into static methods, i.e. Customer::save($array) [would perform both insert and update depending on if prikey is present in array], Customer::delete($id), Customer::getObj($id = false) [if false, get all data]. This is going to become painful though for 32 model objects (and growing).
Also, at times models need to interact (as the interaction above between user data and customer data), which can't be done in a static method without breaking encapsulation.
I envision adding another layer to this (exposing web services), so knowing there are going to be 3 "controllers" at some point I need to encapsulate this CRUD somewhere (obviously), but are static methods the way to go, or is there another road?
Your input is much appreciated.

Why not use a facade?
class RegistrationManager {
public function register( $postData, $callBack ){
$data = get_post_data();
if (count($data) && isValid($data)){
$U = new User();
$U->fromArray($data);
$U->save();
$C = new Customer();
$C->fromArray($data);
$C->user_id = $U->id;
$C->save();
$callBack(); //I like this but you need PHP5.3
}
}
}
In your app controllers:
$r = new RegistrationManager;
$r->register( get_post_data(), function(){ redirect_to_next_step(); } );
Facades are Models too (in my opinion), you may use them to hide wirings or complexities and reduce code-duplication.

I think you need to put that logic to tables class'es
class UserTable extends Doctrine_Table
{
public function register()
{
// There you do data model (not concrete object) related stuff
}
}
http://www.doctrine-project.org/projects/orm/1.2/docs/cookbook/code-igniter-and-doctrine/en

Related

Is it bad practise to use 2 models in one controller

We are using Laravel and we have multiple models controllers.
Ex:
Model1 and Model2 and they corresponding controllers Controller1 and Controller2. We need to make a new entry for Model2 every time we create new entry for Model1.
The question is, is it bad practice to make new entries in Model1 and Model2 in Controller1
public function store(Request $request)
{
//Create new Model1
$model1 = new Model1;
$model1->bla = "Model1";
$model1->save();
//Create new Model2
$model2 = new Model2;
$model2->bla = "Model2";
$model2->save();
}
I have multiple projects that are doing what you just have said, saving entries on a multiple tables at once. I believe that this is really happening on an app in a real world scenario.
Here's what I am doing though:
public function store(Request $request)
{
$main = $this->saveModel1($request);
$this->saveModel2($request, $main->id);
return redirect()->route('my.route.name.for.edit', $main->id);
}
private function saveModel1($request)
{
$model1 = new Model1;
$model1->bla = "Model1";
$model1->save();
return $model1->id;
}
private function saveModel2($request, $model1_id)
{
$model2 = new Model2;
$model2->bla1 = $model1_id;
$model2->bla2 = "Model2";
$model2->save();
}
UPDATE:
This answer has been selected as correct, but I just want to add that on condition like this, it is safe to enclose your saving query into a transaction.
DB::beginTransaction();
try
{
}
catch (\PDOException $e)
{
}
It is not good practice. Generally in OOP there is an important principle named 'Single responsibility Principle'. According to that, a function or a module should have only one responsibility. (Although originally it was a 'class' should have one responsibility.)
In my point of view better approach will be,
public function store(Request $request)
{
Model1::StoreNewData();
Model2::StoreNewData();
}
//And then in model1 and model2 implement the store function.
public static function StoreNewData()
{
$model1 = new Model1;
$model1->bla = "Model1";
$model1->save();
return;
}
Laravel specifically, you should strive for 'fat models, skinny controllers'. It will help you in the long run. For example, suddenly client tells you that you need to validate model1 and/or change the data or insert new data into ten more fields then it will be very hard to change. In real world there might be 20 fields for a table and in same url it will update 5 tables. Debugging it will be hard. But now you know where to change and you can easily go to specific function.
But originally you are using same function to store both model1 and model2. It should not be done. Although, countless tutorial works this way but in professional environment single responsibility principle is important.
I generally use controller functions only to redirect to another page. If there is validation and/or something then I'd use different function or trait.
You should look up SOLID principle in OOP and try to master it. Also check out this link.

Instantiate an object with only some of its members

I'm working in an PHP application, and I'd like to be able to instantiate an object, but I need it to get instantiated only with SOME of it's properties, not all of them. Eg.
class User {
public function __construct() {
$this->user_id = 0;
$this->name = '';
$this->profile = array();
//...many other members here
}
}
Every time I instantiate this object it brings many collections of data, (for example, it brings all it's "profile" properties and so on). And this is sometimes not the wanted behavior because, let's say I need to use only the name of the user, why having in memory all the rest of the properties? But in other cases, I will need them all right away.
Some ideas:
I could create another class that extends User, and in the constructor method unset any unwanted properties. However, I'm looking for a more reusable way, so I can do the same with some other objects in my application.
I could take the properties out of the constructor method, but this would probably force me to change the core of the application (classes above User class), and alter many things in the application.
Is there a more reusable way like using an standard intermediary class or some design pattern?
Thank you.
The Keywords you are looking for are eager loading vs lazy loading.
In Short:
Eager Loading is what you are doing at the Moment: Once an object is created, you are loading all related objects and attributes, no matter how Long it takes.
Lazy loading is the opposite: There you will ONLY load Information, when it is required. (The Moment, it is really accessed)
--
A (very Basic) implementation of both would look like the example bellow.
//Data Model
abstract class UserModel{
protected $userData = null;
protected $userPosts = null;
protected function loadUserData(){
//do whatever required and store in $result
$this->userData = $result;
}
protected function loadUserPosts(){
//do whatever required and store in $result
$this->userPosts = $result;
}
public abstract function getUserData();
public abstract function getUserPosts();
}
//Eager Loading
class EagerUserModel extends UserModel {
public function __construct() {
$this->loadUserData()
$this->loadUserPosts();
}
public function getUserData(){
return $this->userData;
}
public function getUserPosts(){
return $this->userPosts;
}
}
//Lazy Loading
class LazyUserModel extends UserModel {
public function __construct() {
//do nothing
}
public function getUserData(){
if ($this->userData == null){
$this->loadUserData();
}
return $this->userData;
}
public function getUserPosts(){
if ($this->userPosts== null){
$this->loadUserPosts();
}
return $this->userPosts;
}
}
The Example will allow BOTH ways. However you could implement either eager or lazy loading within a single class, if you dont want to have the "choice", of which type to use.
Eager Loading has the Advantage that EVERY Information is "just there". Lazy Loading however requires a more complex architecture. To load the "UserPosts", you might require additional data about the user, which means you have to load the UserData first. This is something you Need to take into account!
So, Lazy loading is always faster?
No! That's the pitfall. Imagine, you have a class with 10 Attributes. If you are loading every Attribute in a lazy way, that would require 10 SQL-Queries to be fired (SELECT Name FROM user..., SELECT email FROM user... and so on). Doing this in an Eager way, would allow you to run only ONE Query: Select Name, email FROM user....
You have to find the Balance between both methods. Are Foreign Objects tightly Coupled? (I.e. user <-> Group)? -> Load Eager. Are foreign objects loosely coupled (User -> Posts on Image 545458) -> Load lazy.
Also Note, that this is an extreme example (100% eager vs 100% lazy). In practice, you may want to load some things eager (user data, Group allocation), and others lazy (comments, Group permissions) - You cant create a own Extension of the base class for every usecase. However having a "BaseClass" is always a good idea, because it gives you flexibility, whenever another implementation is required.
One way to go about it would to create a base-class that contains as little specialization as possible for it to work. Extending the base class and incrementally adding properties/features as needed would allow you to control what gets added.
This would conform to generally accepted object-oriented design patterns.
If you have entity written properly, I prefer to keep it and not to be worry about some empty properties, if the entity keeps its consistent state missing some values. If you don't need them, don't use them. If your script is more complex or long time running, take care of destructing objects when you don't need them anymore.
If the entity can be generalized to more common entity and to be used as base class for other entity later, and makes it sense, then go this way. This would be more difficult way, because refactoring would be needed.
You can also use object composition, when user entity keeps only main user data and one of value will be prepared for another object named profile, for example:
class User {
public function __construct() {
$this->user_id = 0;
$this->name = '';
$this->profile = null;
}
public function hasProfile()
{
return $this->profile != null;
}
}
class Profile {
public function __construct() {
$this->profile_id = 0;
$this->userPrefOne = '';
//...other members here
}
}
// then
$user = new User();
if ($profileDataNeeded)
{
$user->profile = new Profile();
$user->profile->userPrefOne = 'something';
}

The best option for calling model functionality in a PHP controller

I am building a custom MVC framework using PHP. My problem is when I want to access any model class through the controller class. One way I have seen this done is through a registry design pattern using magic methods such as get and set, though PHP get and set are considered bad practise by some. I have read about dependency injection done through a container, but I can not see this working effectily as the container would have to call the models or it would have to contain the models which would defeat the purpose of MVC and create a massive super class. Singleton is seen as bad practise. Is there any solutions or improvements of the methods I have mentioned. It may just be my understand and knowledge of PHP needs improving.
Currently I have this: router.php (loads up controllor through a GET varible
<?php
class router {
function __construct() {
if (file_exists("controller/".$_GET['url']."Controller.php")) {
function __autoload($controller) {
$controlinclude = "controller/".$controller.".php";
include $controlinclude;
}
$control = $_GET['url']."Controller";
new $control();
}
else {
// throw exception
}
}
}
?>
Hope that makes sence
First of all ... Do no put autoloading script in routing mechanism. You are mixing the responsibilities. You will be better off creating a separate class for this based on spl_autoload_register.
Neeext .. do no put complicated operations on constructor. It is makes you code somewhat untestable. Maybe you should be something like:
// you might want to replace $_GET with $_SERVER['QUERY_STRING'] later
$router = new Router( $_GET['url'] );
// where 'default' is the name of fallback controller
$controller_class = $router->get_controller( 'default' );
$method_name = $router->get_action( 'index' );
$model_factory = new ModelFactory( new PDO( ... ) );
$controller = new {$controller_class}( $model_factory );
$controller->{$method_name}();
Additionally, you should look into php namespaces. There is no point in ending class with ...Controller just to know where the class will be located.
Ok ... back to the Model.
There is quite common misconception about models in web development community ( i blame RoR for this mess ). Model in MVC is not a class, but an application layer which contains multitude of instances. Most of the instances belong to one of two types of classes. With following responsibilities:
Domain Logic :
Deals with all the computation, calculation and all the domain specific details. Objects in this group have no knowledge of where and how data is actually stored. They only manipulate the information.
Data Access
Usually made of objects that fit DataMapper pattern (do not confuse with ORM of same name .. nothing in common). Responsible for storing data from Domain Objects and retrieving them. Might be in database.. might not. This is where your SQL queries would be.
In semi-real world situation () it might looks something like this (related to code abowe):
class SomeController
{
// ... snip ...
protected $model_factory = null;
// ... snip ...
public function __construct( ModelFactory $factory )
{
$this->model_factory = $factory;
}
// ... snip ...
public function action_foobar()
{
$user = $this->model_factory->build_object( 'User' );
$mapper = $this->model_factory->build_mapper( 'User' );
$user->set_id(42);
$mapper->fetch($user);
if ( $user->hasWarning() )
{
$user->set_status( 'locked' );
}
$mapper->store( $user );
}
// ... snip ...
}
As you see, there is no indication how the data was stored. It does not even matter if user account was new, or already existing.
Some materials you might find useful
Videos
Advanced OO Patterns (slides)
Clean Code Talks: Don't Look For Things!
Clean Code Talks: Unit Testing
Clean Code Talks: Global State and Singletons
Books:
Real-World Solutions for Developing High-Quality PHP Frameworks and Applications
Patterns of enterprise application architecture
Clean Code: A Handbook of Agile Software Craftsmanship
SQL Antipatterns: Avoiding the Pitfalls of Database Programming
A great Dependency Injection container is "pimple", which may be considered a service locator by some. It uses php 5.3's closures to create a class, that is used to create all of your project's objects through lazy loading. So, for instance, you can create a closure that contains the code for initializing a given object. You would then use the DI container's get() method, which would in turn, call the closure to create the object. Or simply pass you the object, if it has already been created.
// simplified dic class
class dic {
protected $closures = array();
protected $classes = array();
public function addResource($name, Closure $initialization_closure) {
$this->closures[$name] = $initialization_closure;
}
public function get($name) {
if (isset($this->classes[$name]) === false) {
$this->classes[$name] = $this->closures[$name]();
}
return $this->classes[$name];
}
}
//setup
$dic = new dic();
$dic->addResource('user', function() {
return new UserClass($some_args);
});
$dic->addResource('userContainer', function() use ($dic) {
return new UserContainerClass($dic->get('user'));
});
// usage
$userContainer = $dic->get('userContainer');
This allows you to keep the flexibility of being able to change how and what objects get created throughout your project by only changing a very small amount of code.

What is the Algorithm for an ORM?

I've been digging around for an ORM to use in a php/mysql application. However none quite grab my attention past "hello world" tests. So, I decided to do some research and try to code my own custom ORM. However I haven't been able to find resources that explain at code level how to handle db relationships. The concept of how an ORM works is clear but when trying to lay it out in code I don't know what the best approach is. Is it best to build several small queries or to build one complex query for every posible scenario? Any insight into the algorithm or architecture of an ORM is welcome!
Well let us make some ORM framework on the fly. As you marked php tag let us code it in PHP.
But before we write it we must know some basic concepts or some basic terminology
about orm related subjects. In this example we will have:
ORM framework - ORM framework takes responsibility to take care about server connections and server connection abstractions. (Full orm frameworks also support automatic class to table mappings).
Data layer - This part is responsible for mapping classes to tables.
For example data access layer knows how to save specific class object to actual table and how to load specific table to specific class object. (NOTE: Almost any recent ORM framework can avoid you from this layer. For example http://dbphp.net or Doctrine will support every aspect of this layer plus relations and even auto table generation).
Business layer - This layer contains your actual working classes business layer often stands for model or model includes business layer
Let us begin our example from Business layer or model. Our very very simple project which saves and loads users will have one class business layer:
<?php
class user
{
public $id;
public $name
public function __construct ($name=null)
{
$this->name = $name;
}
}
?>
As you see your business layer or model knows nothing about where and how it is saved or loaded. It just does only handle project related business. That's the point the layer name comes from.
Second, let us make a simple ORM framework:
<?php
//The connection link which can be changed any time
class link
{
public $link;
public function __construct ($hostname, $database, $username, $password)
{
$this->link = new \PDO ('mysql:host='.$hostname.';dbname='.$database, $username, $password);
$this->link->query('use '.$database);
}
public function fetch ($query)
{
$result = $this->link->query($query)->fetch();
}
public function query ($query)
{
return $this->link->query($query);
}
public function error ()
{
return $this->link->errorInfo();
}
}
//A structure which collects all link(s) and table/class handlers togather
class database
{
public $link;
public $tables = array ();
public function __construct ($link)
{
$this->link = $link;
table::$database = $this;
}
}
//A basic table handler class
//In recent ORM frameworks they do all the default mappings
class table
{
public static $database;
}
?>
As you noticed our table class in our ORM framework seems very poor. But if this framework was a
complex framework it would support also data layer and had all functionality to work with any table.
But because you need to know how ORM frameworks work in this case we will make data layer
handlers for every class in our business layer.
So this is your data layer. It is so self descriptive that I think it does not
need any documentation:
<?php
class users extends table
{
public function create ($row)
{
$return = new user ();
$return->id = $row[0];
$return->name = $row[1];
var_export($row);
return $return;
}
public function load ($id=null)
{
if ($id==null)
{
$result = self::$database->link->fetch("select * from users");
if ($result)
{
$return = array();
foreach ($result as $row)
{
$return[$row[0]] = $this->create($row);
}
return $return;
}
}
else
{
$result = self::$database->link->fetch("select * from users where id='".$id."'");
if ($result)
{
return $this->create(reset($result));
}
else
{
echo ("no result");
}
}
}
public function save ($user)
{
if (is_array($save))
{
foreach ($save as $item) $this->save ($item);
}
if ($user->id==null)
{
return self::$database->link->query("insert into users set
name='".$user->name."'");
}
else
{
return self::$database->link->query("update users set name='".$user->name."'
where id='".$user->id."'");
}
}
public function delete ($user)
{
self::$database->link->query ("delete from users where id='".$user->id."'");
}
}
?>
At last let us init $database object
Establish some to some sql server link.
Add user class handler to database.
Use it.
Here is it in work:
<?
$database = new database (new link('127.0.0.1', 'system_db', 'root', '1234'));
$database->tables['users'] = new users();
if (!$database->tables['users']->save (new user('Admin')))
{
var_export($database->link->error());
}
var_export($database->tables['users']->load(2));
?>
If you need to dive in other concepts of php ORM's feel free to visit
Doctrine - http://www.doctrine-project.org/ - Full functional complex php ORM framework
db.php - http://dbphp.net/ - Full functional but very easy php ORM framework.
Many ORMs these days are built around the Active Record pattern or variations thereof. In this scheme, you usually have automatically generated classes that correspond to each table in the database, each of those classes return an instance of themselves or of a subclass that correspond to each row in the table:
For example, if you have a Users table:
$user_list = Users.getAllUsers(); //SELECT * FROM Users
//foreach row, create a new User() instance
$user_list[0].name = "Peter";
//UPDATE Users SET name = 'Peter' WHERE user_id = <$user_list[0].id>
$user_list[0].commit();
About implementation, it's best to try to minimize the amount of queries sent to the server, but it's not always trivial nor desirable.
ORMs are not simple. Your ORM will be neither simple or efficient. If it's either of these then your application is simple enough to not need one in the first place, or you're punting when the problem gets hard and simply not using it.
Simple CRUD mapping an object to a table is easy. Start adding in relationships or collections, and everything goes to pot. Then there's queries, etc. The complexity increases in a non-linear, accelerating fashion.
Then the inevitable need for caching just to get it to perform adds even more fun and excitement to the project.
Pretty soon your project is consumed in tweaking, maintaining, and debugging the internal ORM, instead of advancing your project. If you took the time you invested in your ORM and simply wrote a DAO layer with SQL, your project would be farther along, simpler, and more efficient.
Frankly, adopting an ORM is hard enough to justify, depending on the project scale. Writing your own is even more likely not worth the investment.

Model & Mapper relationship

I currently work on a small application with models, mappers and controllers.
My question is, (because I did not found any matching answer), how does the mapper interact with the model (& the controller), when we have the following situation.
$user = new UserModel();
$user->setId('21');
$userMapper = new UserMapper($user);
$userMapper->retrieve();
This will work as fine as possible, the model has an id with which the mapper can retrieve the needed user (and map it back into an user object).
My problem is, how can I wrap this code, I mean, this code is very raw and it is definitly not very recommended to be used in a controller.
I want to shorten it, but I do not exactly know how:
public function view($id)
{
$user->find($id); // this seems always to be tied with the user object/model (e.g. cakephp), but I think the ->find operation is done by the mapper and has absolutly nothing to do with the model
$view->assign('user',$user);
}
It should look more like:
public function view($id)
{
$mapper = $registry->getMapper('user');
$user = $mapper->find($id);
// or a custom UserMapper method:
# $user = $mapper->findById($id);
$view->assign('user',$user);
}
But this is much more code.
Should I include the getMapper procedure within the parent controller class, so I can easily access $this->_mapper without explicitly calling it?
The problem is, I do not want to break the mapper pattern, so the the Model should not access any SQL/Mapper method directly by $model->find(), but I do not want to have a lot of code just for first creating a mapper and do this and this etc.
I hope you'll understand me a little bit, myself is already confused enough, because I am new to many patterns and mapping/modelling techniques.
You could add a Service Layer, e.g.
class UserService
{
public function findUserById($id)
{
// copied and adjusted from question text
$user = new UserModel();
$user->setId($id);
$userMapper = new UserMapper($mapper);
return $userMapper->retrieve();
}
}
Your controller won't access the UserModel and the UserMapper directly, but through the Service.

Categories