Using Contracts in Laravel Lucid context - php

Using the great Lucid structure thing have a question:
what about the storage abstraction and using something like contract with several implementations?
For example, Shopping Cart functionality.
When user logged in, shopping cart data should be stored in a database.
When user logged out, the data storing in the session.
So, there is an option:
create set of jobs named, for example, Eloquent:
App\Domains\Cart\Jobs\Eloquent\AddToCartJob,
App\Domains\Cart\Jobs\Eloquent\FlushCartJob
...
similarly create other set of jobs, Session:
App\Domains\Cart\Jobs\Session\AddToCartJob,
App\Domains\Cart\Jobs\Session\FlushCartJob
...
But how to switch between each of jobs set depends of the condition: user logged in or no?
It looks like should be some kind of the repository, inside each of methods should be used some job(s) from first or second set.
Some kind of:
//...
use App\Domains\Cart\Jobs\Eloquent\AddToCartJob;
class EloquentCart implements CartContract
{
//...
public function addToCart(array $data)
{
//...
return $this->run(new AddToCartJob($data));
}
}
and:
//...
use App\Domains\Cart\Jobs\Session\AddToCartJob;
class SessionCart implements CartContract
{
//...
public function addToCart(array $data)
{
//...
return $this->run(new AddToCartJob($data));
}
}
in the AddToCartFeature:
//...
class AddToCartFeature extends Feature
{
//...
public function handle(Request $request, CartContract $service)
{
//...
return $service->addToCart($request->all());
}
}
and, finally, using of contextual binding with condition is user logged in?.
Is it normal solution or contract-implementation should be developed by another way in Lucid context? Is it normal practice to create one more layer between Feature and Job, or exists another way to switch between implementations?

When it comes to abstraction and design patterns it is recommended that they exist within the code rather than in Lucid's components (Feature, Operation, Job); keeping the architecture in the periphery rather than the foreground of your code.
Your multi-repository approach is a great starting point. Assuming you have:
App\Data\Repositories\CookieRepository
App\Data\Repositories\DatabaseRepository
Now we can have two separate jobs, each accessing the corresponding repository:
Cookie
App\Domains\Cart\Jobs\AddToCookieCartJob
App\Domains\Cart\Jobs\FlushCookieCartJob
Eloquent
App\Domains\Cart\Jobs\AddToDatabaseCartJob
App\Domains\Cart\Jobs\FlushDatabaseCatJob
This ensures that jobs remain atomic and are named explicitly for what they do. This helps when skimming through a Feature or an Operation to know what we're doing without having to check namespaces and get confused with similar job names, or having to deal with namespace aliases (see more on Jobs in the docs).
Now that we've established the groundwork, we'll need to call these jobs depending on the logged in? condition. Given that features shouldn't deal with the intricacies of the units of work, this would be a greate place for an Operation.
App\Operations\AddToCartOperation
if logged in → AddToDatabaseCartJob
else → AddToCookieCartJob
Same goes for App\Operations\FlushCartOperation
Now our Feature won't have to know these details, just run the operation:
class AddToCartFeature extends Feature
{
//...
public function handle(Request $request, CartContract $service)
{
//...
$status = $this->run(AddToCartOperation::class, [...]);
//...
return $this->run(SomeOtherJob::class, compact('status'));
}
}
As for the rest of the code, you may use any design patterns that fit your case.
The names above are only for the example, please rename according to your conventions.
I hope that I've understood your question correctly and that this answer helps!

Related

How to avoid model bloat with eloquent models?

I've been trying to make a small game in Laravel in my spare time and I've been running into trouble with how best to structure the application and issues with certain models getting very bloated.
I'm currently using eloquent models and attaching functionality directly to them. So for example, I have a User model, which started out with the below functions
$user->verify()
$user->creditGold()
$user->debitGold()
which seemed reasonable. As I added functionality to the site, the class started getting bigger and unwieldy though, for example:
$user->creditItem()
$user->debitItem()
$user->equipItem()
$user->unequipItem()
$user->moveToTown()
$user->takeQuest()
$user->ban()
$user->unban()
// etc. etc.
there's a lot of code that feels very unrelated that's been shoved into this one class and it's very messy.
What I've started doing is making helper models that are instantiated and held by the User class. example below
$user->inventory()->creditItem()
$user->inventory()->debitItem()
$user->inventory()->useItem()
It's easy to call and work with but it feels incorrect.
Does anyone have advice for how to best break down a large mass of code that all conceptually belongs to the same entity? I like the idea of functionality being coupled with data because I think that's the most natural way of understanding OO, but would it be better for me to abstract the code out to a Service layer and have service classes that take the user as a parameter and acts on it instead (i.e. $service->giveItemToUser($user, $item) )?
This is where the principle of SoC (Separation of Concerns) becomes very important. What this means is making sure each piece of your app is only concerned with what it needs to be concerned with.
Separation of Concerns
Lets start by identifying some of the concerns in your User class.
Inventory
Equipment
Quests
The above are the general resources that will be utilized by your user. Each of these also have things they are concerned with:
Inventory
Item
Equipment
Item
Quests
Quest
You can already see we have several separate parts of the user which require the same information.
Separating Logic From State
At this stage, we now need to separate some other concerns. Specifically, the business logic (what we want to do with our data) and the data access layer itself (the ORM/Models). Personally, I like to keep these things separate by using the Repository Pattern. Classes that work on models and are concerned with the overall logic and application process. I feel that models are a representation of state, and should only worry about fetching or persisting that state.
So I split these things out as such:
Models
User
Item
Quest
Repositories (dependencies)
UserRepository (User, Item, Inventory, Equipment, Quests)
InventoryRepository (Item)
EquipmentRepository (Item, Collection)
QuestRepository (Quest)
Code Examples
Now this gives me a clear definition of the setup and organization I want. But lets give some example code. This does not concern how the data is persisted (either manually, or via Eloquent relationships, etc).
<?php namespace App\Repositories;
use App\Models\Item;
use Illuminate\Support\Collection;
class Inventory {
protected $contents;
public function __construct(Item $item, Collection $contents)
{
$this->item = $item;
$this->contents = $contents;
}
public function add(Item $item)
{
$this->contents->push($item);
}
public function remove(Item $item)
{
$this->contents->forget($item->id);
}
public function contains(Item $item)
{
return $this->contents->has($item->id);
}
}
The InventoryRepository is only concerned with managing its collection of items. Adding them, removing them and checking if other items are there. To do this it depends on the Collection class and the Item model.
<?php namespace App\Repositories;
use App\Models\Item;
class Equipment {
protected $slots = [
'head' => null,
'body' => null,
'legs' => null,
'feet' => null,
'arms' => null,
];
public function __construct(Item $item)
{
$this->item = $item;
}
public function get($slot)
{
return $this->slots[$slot];
}
public function set($slot, Item $item)
{
$this->slots[$slot] = $item;
}
public function empty($slot)
{
$this->slots[$slot] = null;
}
public function hasEquipment($slot)
{
return !empty($this->get($slot));
}
public function isEquipped(Item $item)
{
if ($this->hasEquipment($item->slot))
{
return $this->get($item->slot)->id == $item->id;
}
}
}
Another class only concerned with the items currently equipped. Equipping, unequipping, etc.
Bringing It All Together
Once you've defined your separate pieces, you can then bring them all into your UserRepository class. By pulling them in as dependencies, the code contained within your UserRepository will be explicitly User management based, while accessing the loaded dependencies gives you all the functionality you require.
<?php App\Repositories;
use App\Models\User;
use App\Repositories\Inventory;
use App\Repositories\Equipment;
class User {
protected $user;
protected $quests;
protected $equipment;
protected $inventory;
public function __construct(
User $user,
Quests $quests,
Equipment $equipment,
Inventory $inventory
) {
$this->user = $user;
$this->quests = $quests;
$this->equipment = $equipment;
$this->inventory = $inventory;
}
public function equip(Item $item)
{
if ($this->inventory->contains($item))
{
$this->equipment->set($item->slot, $item);
}
}
public function unequip(Item $item)
{
if ($this->equipment->isEquipped($item))
{
$this->equipment->empty($item->slot);
}
}
}
This is again just a concept for organizing code. How you want to load and persist the data to the DB is up to you within this type of setup. This is also not the only way to organize the code. The takeaway here is how to break your code out into separate parts and concerns to better modularize and isolate functionality into easier to manage and digest bits.
I hope this was helpful, don't hesitate to ask any questions.
I think that your user has so many responsabilities. Take a look into SOLID principles. Start with Single Responsability Principle.
So take out from user inventory actions and put inventory responsabilities into Inventory service for example.
Yes I would abstract the business logic out to a service or repository layer.
Here is a good article:
https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/
One of the issues of passing around model classes with attached functionality is the bloat that's inherent in a model class. Basically each model class carries around with it the weight of the entire database model, which is quite heavy. That's typical of an Active Record ORM implementation like Eloquent, as opposed to a Data Mapper style ORM like Doctrine. However I am guessing that having bitten the Laravel bullet you are more or less wedded to Eloquent.
One thing that I found, that loses the weight of the data model but keeps the OO style interface is to use Laravel's Fluent class. To aid in that I wrote a small extension here:
https://packagist.org/packages/delatbabel/fluents
Pull it in using:
composer require delatbabel/fluents

How to properly structure and pass objects in a MVC structure in PHP

Over the past two years, I have become fairly familiar with PHP MVC style architecture, and have developed all my projects using MVC structures since then.
One question that has continued to bother me is how to group functions and database calls. I run into needing to perform the same actions across models. I would prefer not to duplicate these operations and sql query inside each of the models, but would rather group all user operations into a separate class.
For example, say I have a website with a forum, a blog, and a profile page, each with a separate model, view, and controller. However, say each of these pages needs to perform the same operation to the user table.
My Model class is constructed with a database object automatically. If I need to call a function from the user class, is it ok to pass the db object to that new User class? ... to do something like the following? I am not sure if passing objects like I am doing is fine, or is there a much better way of setting things up? Am I wasting resources, or is this a clumsy way of doing things?
Profile Model
class Profile_Model extends Model{
public function __construct() {
parent::__construct();
}
public function someFunction(){
$this->db->insert( "SOME SQL" );
$user = new User( $this->db ); // OK TO PASS DB OBJECT LIKE THIS?
$user->setSomething();
}
public function anotherFunction(){
//do something else that does not need a user object
}
}
User Class
class User{
public function __construct($db){
$this->db = $db; // OK TO SET DB OBJECT AS CLASS VARIABLE AGAIN?
}
public function setSomething(){
$this->db->insert( "SOME SQL" );
}
}
I'm trying to give you a really basic example of how I'd implement this architecture; Since it's really basic and I'm just a passionate developer and nothing more it could be I'm breaking some architectural rules, so please take it as a proof of concept.
LET'S START quickly with the Controller part where you get some request. Now you need someone that takes care of doing the dirty work.
As you can see here I'm trying to pass all the "dependencies" via constructor. These way you should be able to easily replace it with Mocks when testing .
Dependency injection is one of the concepts here.
AND NOW the Model (please remember Model is a layer and not a single class)
I've used "Services (or cases)" that should help you to compose a group of behaviors with all the actors (Classes) involved in this behavior.
Idendifying common behaviours that Services (or Cases) should do, is one of the concepts here.
Keep in mind that you should have a big picture in mind (or somewhere else depending on the project) before starting, in order to respect principle like KISS, SOLID, DRY, etc..
And please pay attention to method naming, often a bad or long name (like mine for example) is a sign that the class has more than a single Responsability or there's smell of bad design.
//App/Controllers/BlogController.php
namespace App\Controllers;
use App\Services\AuthServiceInterface;
use App\Services\BlogService;
use App\Http\Request;
use App\Http\Response;
class BlogController
{
protected $blogService;
public function __construct(AuthServiceInterface $authService, BlogService $blogService, Request $request)
{
$this->authService = $authService;
$this->blogService = $blogService;
$this->request = $request;
}
public function indexAction()
{
$data = array();
if ($this->authService->isAuthenticatedUser($this->request->getSomethingRelatedToTheUser())) {
$someData = $this->blogService->getSomeData();
$someOtherData = $this->request->iDontKnowWhatToDo();
$data = compact('someData', 'someOtherData');
}
return new Response($this->template, array('data' => $data), $status);
}
}
Now we need to create this Service that we've used in the controller. As you can see we're not talking directly with the "storage or data layer" but instead we're calling an abstraction layer that will handle that for us.
Using a Repository Pattern to retrieve data from a data layer, is one of the concepts here.
this way we can switch to whatever repository (inMemory, other storage, etc) to retrieve our data without changing the interface that the Controller is using, same method call but get data from another place.
Design by interfaces and not by concrete classes is one of the concepts here.
//App/Services/BlogService.php
<?php
namespace App\Services;
use App\Model\Repositories\BlogRepository;
class BlogService
{
protected $blogRepository;
public function __construct(BlogRepositoryInterface $blogRepository)
{
$this->blogRepository = $blogRepository;
}
public function getSomeData()
{
// do something complex with your data, here's just simple ex
return $this->blogRepository->findOne();
}
}
At this point we define the Repository that contains the persistance handler and knows about our Entity.
Again decoupling storage Persister and knowledge of an entity (what "can" be coupled with a mysql table for example), is one of the concepts here.
//App/Model/Repositories/BlogRepository.php
<?php
namespace App\Models\Respositories;
use App\Models\Entities\BlogEntity;
use App\Models\Persistance\DbStorageInterface;
class DbBlogRepository extends EntityRepository implements BlogRepositoryInterface
{
protected $entity;
public function __construct(DbStorageInterface $dbStorage)
{
$this->dbStorage = $dbStorage;
$this->entity = new BlogEntity;
}
public function findOne()
{
$data = $this->dbStorage->select('*')->from($this->getEntityName());
// This should be part of a mapping logic outside of here
$this->entity->setPropA($data['some']);
return $this->entity;
}
public function getEntityName()
{
return str_replace('Entity', '', get_class($this->entity));
}
}
At the end a simple entity with Setters and Getters:
//App/Model/Entities/BlogEntity.php
<?php
namespace App\Models\Entities;
class BlogEntity
{
protected $propA;
public function setPropA($dataA)
{
$this->propA = $dataA;
}
public function getPropA()
{
return $this->propA;
}
}
AND NOW? how can you inject this classes passed as dependencies? Well, this is a long answer.
Indicatively you could use Dependency Injection as we've done here have a init/boot file where you define things like:
// Laravel Style
App::bind('BlogRepositoryInterface', 'App\Model\Repositories\DbBlogRepository');
App::bind('DbStorageInterface', 'App\Model\Persistence\PDOStorage');
or some config/service.yml file like:
// Not the same but close to Symfony Style
BlogService:
class: "Namespace\\ConcreteBlogServiceClass"
Or you may feel the need of a Container Class from where you can ask the service you need to use in your controller.
function indexAction ()
{
$blogService = $this->container->getService('BlogService');
....
Dulcis in fundo here are some useful links (You can find tons of docs about this):
Services in Domain-Driven Design
Wicked Domain Model
Dependency Injection Container
Inversion of Control and Dependency Injection
Managing common Dependencies with parent Services
Whenever you need to use an object from another class there is only one safe way to do it: Dependency Injection.
Example:
Instead of having:
public function myMethod(){
$anotherObject = new Object();
}
You should inject the object with the constructor:
function __construct($dependency) {
$this->anotherObject = $dependency;
}
Once you have this structure you can use type hint and an Inversion of Control container to build thing automatically, e.g. define:
function __construct(DependencyInterface $dependency) {
$this->anotherObject = $dependency;
}
And then set your IoC container to inject the right dependency when you need to use this object
Do you use any frameworks? If not, try having a look at some popular ones, like Zend Framework or Symfony. You'll find they solve your problem and probably many more and are a great way to expand your knowledge on how to structure your project.
That aside you are close. Although adding the database directly to your User-model is probably not want you want to do. If you can get Martin Fowler's Patterns of Enterprise Application Architecture (PEAA) you will find a whole chapter outlining how to connect your models to your database. I prefer a Gateway-class (search for the Gateway-pattern or look at Zend_Db) when building something on my own, as it is relatively easy to implement and build.
Basically you have a class which performs queries and then will pass the data to your model. Just look at Data Source Architectural Patterns in Martin Fowler's pattern catalog (http://martinfowler.com/eaaCatalog/) to get a quick glance how to structure it and definitely read the book to get a real understanding when and how to use the patterns.
I hope this helps.
Part of the answer is to use dependency injection, but there is more to it than that. Cognitively speaking, grouping starts in the mind and is teased out better by brainstorming and modeling: Entity Relationship Diagrams and UML Diagrams.
Grouping of methods into classes and delegating tasks to injected objects makes sense, but there is usually room for one level of inheritance (at minimum). The use of abstract super classes and a Strategy Pattern for child classes that inherit base functionality from the abstract parent can help reduce code duplication (DRY).
All that being said, this is one reason why dependency injection containers are popular. They allow you to obtain the objects, and hence functionality, you need anywhere, without coupling object instantiation to usage.
Do a search for Pimple in Google. It may give you some ideas.

API Internal requests on own website?

I want to develop a website and an App for Android and Apple. An App will fetch the data via API from our domain.
Let say on our website, it will show a list of products or create user account; In the controller, I could use internal API request which will then fetch the data via MySQL rather than using MySQL query method directly on it own. Is this common practice or bad practice?
This is example of dingo/api internal request (Laravel):
Route::api(['version' => 'v1', 'prefix' => 'api'], function () {
Route::get('users', function () {
// fetch from database
return User:all();
});
});
In the Controller
class UsersController
{
public function showUsers()
{
$users = API::get('users');
return View::make('users-list')->with('users', $users);
}
}
In this example they have an API route setup for get method at users and API::get('users'); will make an internal request to that end point and return you what ever that method returns
Yes I would consider this common practice. I personally even think it's good practice to consume your own API internally. It definitely helps keeping your code DRY (Dont Repeat Yourself).
Of course it causes a bit of an overhead compared to a direct method call, but I doubt it will be noticeable. Anyways, for your consideration, an alternative would be to keep the API controllers very very flat and have most of your logic somewhere else (in the Model, a Repository or a Service Layer). I recommend doing that anyways. This would mean that you could easily do the same thing in your in your "normal" controller as you do in the API controller because it's basically just a (few) call(s) to another class.
Here's an example to illustrate what I mean
Let's say your users endpoint is a bit more complicated (This includes some eager loading and filtering)
public function index(){
return User::has('profile')
->with('profile', 'city')
->active()
->get();
}
Now of course it still isn't a lot of code and you could easily do the same in the other controller as well. But imagine you wanted to add a new relationship to eager load. You would need to change your code in two places. (If you would forget one you probably wouldn't even notice it...)
One solution to this problem is creating a repository. I won't go into the details on how to implement this pattern (there are a lot resources about this on the internet) but basically in the end you'd have a class like this:
class UserRepository {
public function getAll(){
return User::has('profile')
->with('profile', 'city')
->active()
->get();
}
}
(Ideally you would also have an interface defining your repository...)
Then use dependency injection to make an instance of the class available in your controller: (Again this is not complete you'd need a few more things to set up DI)
public function __construct(UserRepository $repo){
$this->user = $repo;
}
public function index(){
return $this->user->getAll();
}
And in your other controller(s) you could use the exact same call getAll().

MVC .. should one database_model contain CRUD for all object_models? Active record vs. registry pattern

I'm writing a fairly simple "fact database" in PHP (with Codeigniter .. but I am trying to get away from the framework internals for learning purposes), and trying to better my MVC/OOP practices.
Previously I would have done this: a fact model, a user model, a source model .. and inside each of those models I would place the CRUD logic for each. So it would look like this..
$this->fact_model->save($fact);
$this->user_model->deactivate($uid);
$this->source_model->get_id($sid);
But after reading more, it seems to make sense to have a separate persistence model (ie 'database_model'). But then it seems it would have to contain a full range of CRUD for each type of object, which seems wasteful to me. I guess I'm looking for how to go to this...
$this->db_m->save(Fact $fact);
$this->db_m->update(User $user);
// .. etc .. but also ..
$this->db_m->get_user_id($uid);
// .. and ..
$htis->db_m->get_all_facts();
Is this heading in the right direction? Do I just end up testing for type inside the database model and switching when I need to? Or do I extend the database model for each type of object?
$this->fact_db_m->save(Fact $fact);
$this->fact_db_m->get_all();
$this->source_db_m->get_id($sid);
Or something like this, which I guess is the closest to CIs AR implementation.
$this->db_m->save('facts', Fact $fact);
$this->db_m->get('user', array('id'=>$uid));
I guess this is a case of "active record vs repository". I understand that repository is easier to test, and the CRUD logic is separate from the object data, and that separation makes sense to me. But still.. it means you have to write a separate repository model for each entity. Is this right?
BTW - I know Codeigniter has a Database class and uses active record, and in a way I am just kind of re-creating it with some of those approaches. I'm just trying to understand things without relying on the framework internals. Any comments? Is it just a matter of choice?
Trying to do a little research on my own, thanks to your question, I came across this article: http://msdn.microsoft.com/en-us/magazine/dd569757.aspx , which explains the differences between different data access patterns.
I hope i understood the question correctly, but here goes.
My approach would be to use the separation of models, however the one twist i usually do. i will try to be clear.
Lets say my application is going to require 3 unique features. One for users, facts, sources, All of these models might need to use some common functions like SAVE or LOAD, or UPDATE, or DELETE. Instead of duplicating the common functions into each model, i would simply make a base class with all the common functions, a nd have the base class extend the CI_Model, then all my new model files ( users,facts,sources ) i would have extend my common class.
To better illustrate this, i will throw some basic code up
db_common_model Common Class (db_common_model.php)
class db_common_model extends CI_Model
{
public function __construct()
{
parent::__construct();
}
/**
* All Common Functions Here */
public function save()
{
// Do stuff
}
public function update()
{
// Do stuff
}
public function etc()
{
// Do stuff
}
}
users_model Class (db_common_model.php)
class users_model extends db_common_model
{
public function __construct()
{
parent::__construct();
}
/**
* user specific functions */
public function get_one()
{
// Do stuff
}
public function get_all()
{
// Do stuff
}
public function get_latest()
{
// Do stuff
}
public function etc()
{
// Do stuff
}
}
/**
* When using it in CI Controller
*/
$this->user_model->get_one(); // loads user specific function
$this->user_model->save(); // Calls all inherited methods from parent db_common_model
// Etc
This way of setting up your models allows you expand common features in the db_common_model, that are automatically available to all children classes.
This allows for clean organization, and allows you to not have to re-invent your common functions in every model.
Hope this helps.

multiple functions is one big function in PHP?

so I'm writing DataBase class which will be an encapsulation layer between PHP Controller and MySQL View.
interface iDataBase {
public function drug($action, $drug);
public function company($action, $company);
public function activeIngredient($action, $activeIngredient);
}
At First I thought of making all setters and getters seperate like getAllDrugs(), updateDrug(), removeDrug(), getForUpdate(), getDrug() and so one, but then I realised that I was polluting database interface with too much functions, plus this is a very small-scale version, I'm considering adding much-more classes and much more functionality. So, instead of using a lot of function I just setteled for 3. $action will determine what kind of thing does user want to do with certain class. so, for now, possible actions are these: "add", "getAll", "getForUpdate", "update", "remove"
but these functions masked by $action have different things to do, so their their return result is different and second argument can also be different.
Is my solution a good practice? I'm sure many of you had the same problem, how did you solve it? Are there any possible problems?
P.S. Drug, Company, ActiveIngredient are all classes
A function should have clearly defined, narrow responsibilities with clearly defined, minimalist return types. If you start to create "god functions" which do everything and the kitchen sink depending on what arguments you pass, you're going heavily into the territory of hard to maintain spaghetti code. You do not want a function that does A and returns B if you pass it X, but does C and returns D if you pass it Y etc...
It is a good idea to start concrete and generalize over time as you see similar patterns emerge. So, create the methods you actually need:
public function findUserById($id)
public function findUserByEmail($email)
public function updateCompanyName($id, $newName)
If you find you have shared code between these functions, unify the code behind the scenes to keep it DRY:
public function findUserById($id) {
return $this->find('SELECT * FROM user WHERE id = ?', $id);
}
public function findUserByEmail($email) {
return $this->find('SELECT * FROM user WHERE email = ?', $email);
}
protected function find($query, $arg) {
...
}
Don't start the other way around, thinking you "only need X,Y and Z" which seem similar enough to be unified into one method, then later finding out there are small differences between X, Y and Z and littering your code with special cases for each. That just leads to functions which are either ginormous or so general they basically do nothing on their own.
What you are likely looking for is called a TableDataGateway (emphasis mine):
A Table Data Gateway holds all the SQL for accessing a single table or view: selects, inserts, updates, and deletes. Other code calls its methods for all interaction with the database.
This means you will have one generic database adapter, for instance a PDO object. You inject this into your various TDG's. The TDG's then use that adapter to CRUD data from the database.
Example
class CompanyTableGateway
{
private $dbAdapter;
public function __construct(DBAdapter $dbAdapter)
{
$this->dbAdapter = $dbAdapter;
}
public function create($name, $street, $whatever)
{
$this->dbAdapter->exec( 'INSERT INTO companies …' );
}
public function findById($id)
{
return $this->dbAdapter->exec(
sprintf('SELECT * from companies where id = %d', $id)
);
}
// more methods …
}
If you have multiple of these Gateways, you can abstract the general CRUD logic into an Abstract class and then extend the concrete Gateways from it.
You will then use a TableModule or similar other object to call the methods on the individual Gateways.
The never ending discussion of Separation of Concerns vs Single Responsibility Principle.
Separation of Concerns (SoC) – is the process of breaking a computer program into distinct features that overlap in functionality as little as possible. A concern is any piece of interest or focus in a program. Typically, concerns are synonymous with features or behaviors.
http://en.wikipedia.org/wiki/Separation_of_concerns
Single Responsibility Principle (SRP) – every object should have a single responsibility, and that all its services should be narrowly aligned with that responsibility. On some level Cohesion is considered as synonym for SRP. http://en.wikipedia.org/wiki/Single_responsibility_principle
Try to get the best of both, and model your classes accordingly.
What I would recommend you doing is do a global database class, which controls the basic input / output of the database, and then extend this down to each table.
An example of this could be a Users table. What you can do to this table is
Create
Update
Delete
You will then extend the Super Database Class, with a Users Class, which will have getters and setters for each function you want to have, ie:
class Users extends DatabaseClass {
public function update ( $params )
{
// Make the code for an update, and let the SuperClass execute the code.
...
}
public function add ( $params )
{
...
}
public function delete ( $params )
{
...
}
}
This will allow you to later, easily add more functionality to the Users table, and optimize queries specifically for the table/data you're using.

Categories