Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm relatively new to Object Oriented Programming. I pretty much understand the concepts, but practically speaking, I am having a really hard time finding information about how to best use Models in my Zend Framework applications.
Specifically, I have a Model (that doesn't extend anything) that doesn't use a Database Table. It uses getters and setters to access its protected members. I find myself struggling with how to best display this model in the view. I don't want logic in my view templates, but I find myself in the following situation:
In my controller:
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object;
In my view template:
<h2><?= $this->object->getName() ?></h2>
I don't really like calling functions in my view templates but I don't know a better way to do this. I don't want my Model's members to be public, but I basically want to achieve the same results:
<h2><?= $this->object->name ?></h2>
I don't want my controller to do all the work of having to know everything about the model:
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object;
$this->view->object->name = $object->getName();
What is the best practice of using models in the Zend Framework? Can anyone recommend any tutorial that would help me understand this Model/View dilemma in Zend Framework?
One possibility is to use the magic __set and __get methods in PHP. I use them like so within my abstract Model class:
abstract class Model_Abstract
{
protected $_data;
// Private Data Members assigned to protected $_data
public function __construct($data = null)
{
// Makes it so that I can pass in an associative array as well as
// an StdObject.
if(!is_object($data)) {
$data = (object) $data;
}
$this->_data = $data;
}
public function __get($key)
{
if (method_exists($this, '_get' . ucfirst($key))) {
$method = '_get' . ucfirst($key);
return $this->$method();
}
else {
return $this->_data->$key;
}
}
public function __set($key, $val)
{
if ( method_exists( $this, '_set' . ucfirst($key) ) ) {
$method = '_set' . ucfirst($key);
return $this->$method($val);
}
else {
$this->_data->$key = $val;
return $this->_data->$key;
}
}
}
class Model_User extends Model_Abstract
{
//Example overriding method for the property firstName in the $_data collection.
protected function _getFirstName()
{
// Do some special processing and then output the first name.
}
}
This makes it so that you can specify getters and setters for properties as necessary but makes it so that you don't have to define boilerplate functions for every property, just the ones where you want to do some sort of processing on it before returning the value. For example I use the functionality in a number of places to change ISO compliant dates (as stored in MySQL) into a more compact and readable format for users.
As far as what to place in your controller, I would recommend looking at this post for some specific feedback on what handling to place within your controller.
Some feel that they would rather have a helper that automatically loads models into the view and skirts the controller altogether. Personally I would say that within the context of Zend Framework and PHP it makes plenty of sense to pass models into the view from the controller because the state of the models in the view frequently depends on what came from the request (which should definitely be handled in the controller).
Update: As per criticisms in the comments, one thing that I would point out is that your database access layer and domain (or model) layer are really two different things, though with the Active Record they are blended together. I asked this question a while back and received some useful feedback on this matter. Whatever you decide to do with the model, you'll want to provide a consistent API for all domain objects regardless of where the data for the model comes from.
I suppose that one benefit offered by Saem's answer is that it offers the ability to directly map properties / function return values from one or more domain objects to the view object. Theoretically the usage within the view then looks like this:
// Mapped from Model_User::_data->last_name and Model_User::_data->first_name
$this->name
If only other developers are going to be working with the templates, I would recommend just passing in the models. Here is a link to a Jeff Atwood post on MVC Understanding Model-View-Controller
This isn't particularly geared towards zend framework, but the problem is rather general, in my mind.
It seems you're on the right path, instead of hard wiring the model to the view, inside the controller. You'd rather have that abstract, especially important if you're mapping a tonne of models, or mapping the same model over and over again.
Something simple would be to write a bunch of mapping functions, which would be fine if all you were avoiding is mapping the same thing over and over.
If you wanted a more general solution, that also addressed avoid writing that boiler plate code, and keeping things more DRY, I suggest creating a mapper class.
You could create a ViewModelMapper, which would take a model, or a few models and map them to the view.
class ViewModelMapper
{
public function __construct($view)
{
//set the properties
}
public function addModel($model, $overrideViewProperty = null)
{
//add the model to the list of models to map, use the view's property
// name to figure out what to map it to? Allow for an override just in case.
}
public function getMappedView()
{
//take the view, map all the models
}
}
You could then instance this on your controller, and setup the mappings, so the controller controls the mapping still, but all the boiler plate and coding logic is centralized, for all controller maps, except for the rare exceptions.
For a good read on model architecture, read this post. It doesn't specifically talk about the view, but it's definitely worth reading.
I ended up adding a getViewClass() function to my models. The controller calls this function to get the protected variables it wouldn't otherwise have access to, and the view doesn't have to worry about calling any getters.
//controller
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object->getViewClass();
//view template
<h2><?= $this->object->name ?></h2>
I don't know if there is a better way to get the job done in the Zend Framework, but this is one solution.
Related
So I've read some already existing questions here (like this and this) and also I'm reading a book, but I still can't decide. Sorry for the long post, I've posted a decent amount of code here.
The routing, controller creating and action calling are working right now. Until this time I've just echo'd a simple text in the controller's action to see if it's working.
After this I've introduced a simple View class with a render() function which returns the "renderable" HTML code:
public function render()
{
if (!isset($this->file)) {
return "";
}
if (!empty($this->data)) {
extract($this->data);
}
// dirty-hack: use output buffering so we can easily check if a file can be included
// if not, simply reject the output and throw an exception (let the caller handle it)
// if the inclusion was successfull then return with the buffered content
ob_start();
if (!include($this->file)) {
ob_end_clean();
throw new \Exception("View file \"{$this->file}\" not found");
}
return ob_get_clean();
}
The Controller class also have a render() and a protected setView() functions
public function render()
{
if (isset($this->renderView)) {
echo $this->renderView->render();
}
}
protected function setView($view)
{
if (!is_object($view) || !($view instanceof View)) {
throw new \Exception("The \"view\" parameter have to be a View instance");
}
$this->renderView = $view;
}
An example controller with an example action:
public function viewHome()
{
$contentView = new Framework\View("HomeView.php");
// fill contentView with variables, using $contentView->setData("name", value)
$this->generateView($contentView);
}
protected function generateView($contentView)
{
if (!is_object($contentView) || !($contentView instanceof Framework\View)) {
throw new \Exception("Invalid \"contentView\" parameter");
}
$layout = new Framework\View("MainLayout.php");
$layout->setData("content", $contentView->render());
$this->setView($layout);
}
So actually the controller's action is assigning data to the view (Edit: actually it's not a view, more like a template, but it's my naming convention) and the view simply uses the data. This could be "reversed" so I could create View subclasses which would get a controller reference and use the controller to get/set the data to/from the presentation. For some reason I stick with the first (current) solution but I can change my mind. :)
The corresponding MainLayout.php test file is the following
<div style="margin-left: auto; margin-right: auto; padding: 5px; width: 800px; border: 3px solid green;">
Main header <br />
<br />
Content: <br />
<?php
if (!isset($content)) {
die("The \"content\" variable is not available");
}
echo $content;
?>
</div>
Note that the codes I've posted serve test purposes, things can be different later on. However my real problem comes with the model layer. I've read two different approach about the MVC pattern:
The first says that the model is a "stupid" layer, a simple memory/object representation of the data. The real work (so the DAO access, queries, business logic) is in the controller.
The other one says that the controllers are the "stupid" things, they are just a glue between the model and the view, the work is done by the model. The second one seems to be easier and it fits more to my current design. What do you think, which one is the preferred approach?
And another one: let's say I've choosen the 2nd approach (described above), so I have a model class for eg. a User. This class have different (static) functions for querying things, like "get all users", "add new user", and so on. However I don't want to connect the model with the Database this strong. My first idea is that I should create (at least) 3 classes for a single model:
an abstract class/interface which defines the "model" itself
at least one subclass (the implementation) for each data-access type
and a factory for the model which instantiates the proper class. If we need a mock model for testing, it would return a UserMock instance instead of a UserDB instance.
Do you have any better ideas?
Edit:
Based on the accepted answer, I've decided to use the service design. Here is a simple (sample) class:
abstract class UserService
{
private static $instance;
public static function setInstance($instance)
{
if (!is_object($instance) || !($instance instanceof UserService)) {
throw new \Exception("Invalid \"instance\" parameter");
}
self::$instance = $instance;
}
public static function get()
{
if (!isset(self::$instance)) {
throw new \Exception("Instance is not set");
}
return self::$instance;
}
public abstract function findAll();
public abstract function findById($id);
public function add($user)
{
if (!is_object($user) || !($user instanceof User)) {
throw new \Exception("Invalid \"user\" parameter");
}
$id = $this->addAndReturnId($user);
$user->setId($id);
}
protected abstract function addAndReturnId($user);
}
This way I can register a service implementation (which uses the database or just filled with test data). However for each service I should copy-paste the set/get code. I could use a base class for this but the "instanceof" check is different for each subclass.
I know this is a bit off-topic but do you have any good idea for this? Or should I copy-paste that two functions for each service?
Note: I'm working a lot with Symfony / Doctrine so my point of view is probably pretty influenced by that. But I think they are pretty well-designed libraries, so I hope this is not a problem.
Why not use both approaches? Let controllers AND models be dumb.
Model classes should only be concerned about holding the data. Basically just a class with some properties and accessor methods for these properties; nothing else.
Also the controllers should not contain too much code and leave all the "interesting stuff" too other classes: Services.
Symfonys documentation describes services as follows:
Put simply, a service is any PHP object that performs some sort of "global" task. It's a purposefully-generic name used in computer science to describe an object that's created for a specific purpose (e.g. delivering emails). Each service is used throughout your application whenever you need the specific functionality it provides. You don't have to do anything special to make a service: simply write a PHP class with some code that accomplishes a specific task. Congratulations, you've just created a service!
Now you could just create services like "UserRepository", "BlogRepository", "SomeModelRepository" and these services contain all the code to work with the corresponding models like loading all users, search users, storing users to the database and so on.
A big advantage: If you also create corresponding interfaces (e.g. UserRepositoryInterface) you can just exchange these repository classes in future if you want to store your model in a different DBS or even in plain text files instead of your old database. You wouldn't need to change your models or controllers at all.
Maybe you should take a look at how Doctrine handles these things.
Also take a look at the Dependency Injection design pattern if you like the idea of services.
Edit (05.10.2016)
Your solution works, so if the following is too complicated for you right now, just stick with it. But it helped me, so I'll try to advertise it. :P
Your UserService should only care about the actual user management methods and not about getting/setting instances of itself. Your approach is using a variation of the Singleton pattern and Singletons are not necessary a thing you really want to have (see here).
If you want to work with "services" you probably should get into "Dependency Injection" (as mentioned above already). It is a bit hard to get into it in the beginning, but once you know how to use it, it improves your code quality a lot (at least it did for me). This introduction seems really good: PHP: The Right Way. Symfony also provides a DI component which you could use in your project to dont bother with the implementation details: Symfony Dependency Injection component
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.
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.
I know there are loads of questions on this, I have done quite a bit of reading. I'd like to ask this in context of my project to see what suggestions you may have.
I have quite a large web application with many classes, e.g. users and articles (which i consider to be the main classes) and smaller classes such as images and comments. Now on a page, lets say for example an article, it could contain many instances of images and comments. Makes sense right? Now on say an articles page I call a static method which returns an array of article objects.
That's the background, so here are the questions.
Since building a large amount of the app I came to realise it would be very useful to have a core system class containing settings and shared functions. There for I extended all of my classes with a new core class. Seemed relatively simple and quick to implement. I know CodeIgniter does something similar. I feel now though my app is becoming a bit messy.
Question Is this a good idea? Creating an instance of core is exactly what I want when calling an instance of an article, but what about when i'm creating multiple instances using the static method, or calling multiple images or comments on a page. I'm calling the core class unnecessarily right? Really it only needs to be called once per page (for example the constructor defines various settings from the database, I don't want to this every time, only once per page obviously), but all instances of all classes should have access to that core class. Sounds exactly like I want the singleton approach, but I know that's a waste of time in PHP.
Here's an idea of what my code looks like at this point. I've tried to keep it as simple as I can.
class core {
public function __construct(){
...define some settings which are retrieve from the database
}
public function usefulFunction(){
}
}
class user extends core {
public function __construct(){
parent::__construct();
}
public function getUser($user_id){
$db = new database();
$user = /* Get user in assoc array from db */
$this->__setAll($user);
}
public static function getUsers(){
$db = new database();
$users = /* Get users from database in assoc array from db */
foreach($users as $user) {
$arrUsers[] = new self();
$arrUsers[]->__setAll($user);
}
return $arrUsers;
}
private function __setAll($attributes) {
foreach($attributes as $key => $value)
{
$this->__set($key, $value);
}
}
public function __set($key, $value) {
$this->$key = $value;
}
}
The other issue I'm having is efficiently using/sharing a database connection. Currently each method in a class requiring a database connection creates a new instance of the database, so on a page I might be doing this 5 or 10 times. Something like the dependency injection principle sounds much better.
Question Now if i'm passing the instance of the DB into the new user class, i know I need something like this...
class user{
protected $db;
public function __construct($db){
$this->db = $db;
}
... etc
}
$db = new database();
$user = new user($db);
... but when I want to run the static function users::getUsers() what is the best way to gain access to the database instance? Do i need to pass it as a variable in each static method? (there are many static methods in many classes). It doesn't seem like the best way of doing it but maybe there isn't another way.
Question If extending all of my classes off the core class as suggested in part 1, can I create an instance of the DB there and access that some how?
Question I also have various files containing functions (not oop) which are like helper files. What's the best way for these to access the database? Again i've been creating a new instance in each function. I don't really want to pass the db as a parameter to each one. Should I use globals, turn these helper files into classes and use dependency injection or something different all together?
I know there is lots of advice out there, but most info and tutorials on PHP are out of date and don't ever seem to cover something this complex...if you can call it complex?
Any suggestions on how to best layout my class structure. I know this seems like a lot, but surely this is something most developers face everyday. If you need any more info just let me know and thanks for reading!
You asked in a comment that I should elaborate why it is a bad idea. I'd like to highlight the following to answer that:
Ask yourself if you really need it.
Do design decisions for a need, not just because you can do it. In your case ask yourself if you need a core class. As you already have been asked this in comments you wrote that you actually do not really need it so the answer is clear: It is bad to do so because it is not needed and for not needing something it introduces a lot of side-effects.
Because of these side-effects you don't want to do that. So from zero to hero, let's do the following evolution:
You have two parts of code / functionality. The one part that does change, and the other part that is some basic functionality (framework, library) that does not change. You now need to bring them both together. Let's simplify this even and reduce the frame to a single function:
function usefulFunction($with, $four, $useful, $parameters)
{
...
}
And let's reduce the second part of your application - the part that changes - to the single User class:
class User extends DatabaseObject
{
...
}
I already introduced one small but important change here: The User class does not extend from Core any longer but from DatabaseObject because if I read your code right it's functionality is to represents a row from a database table, probably namely the user table.
I made this change already because there is a very important rule. Whenver you name something in your code, for example a class, use a speaking, a good name. A name is to name something. The name Core says absolutely nothing other that you think it's important or general or basic or deep-inside, or that it's molten iron. No clue. So even if you are naming for design, choose a good name. I thought, DatabaseObject and that was only a very quick decision not knowing your code even, so I'm pretty sure you know the real name of that class and it's also your duty do give it the real name. It deserves one, be generous.
But let's leave this detail aside, as it's only a detail and not that much connected to your general problem you'd like to solve. Let's say the bad name is a symptom and not the cause. We play Dr. House now and catalog the symptoms but just to find the cause.
Symptoms found so far:
Superfluous code (writing a class even it's not needed)
Bad naming
May we diagnose: Disorientation? :)
So to escape from that, always do what is needed and choose simple tools to write your code. For example, the easiest way to provide the common functions (your framework) is as easy as making use of the include command:
include 'my-framework.php';
usefuleFunction('this', 'time', 'really', 'useful');
This very simple tow-line script demonstrates: One part in your application takes care of providing needed functions (also called loading), and the other part(s) are using those (that is just program code as we know it from day one, right?).
How does this map/scale to some more object oriented example where maybe the User object extends? Exactly the same:
include 'my-framework.php';
$user = $services->store->findUserByID($_GET['id']);
The difference here is just that inside my-framework.php more is loaded, so that the commonly changing parts can make use of the things that don't change. Which could be for example providing a global variable that represents a Service Locator (here $services) or providing auto-loading.
The more simple you will keep this, the better you will progress and then finally you will be faced with real decisions to be made. And with those decisions you will more directly see what makes a difference.
If you want some more discussion / guidance for the "database class" please consider to take a read of the very good chapter about the different ways how to handle these in the book Patterns of Enterprise Application Architecture which somewhat is a long title, but it has a chapter that very good discusses the topic and allows you to choose a fitting pattern on how to access your database quite easily. If you keep things easy from the beginning, you not only progress faster but you are also much easier able to change them later.
However if you start with some complex system with extending from base-classes (that might even do multiple things at once), things are not that easily change-able from the beginning which will make you stick to such a decision much longer as you want to then.
You can start with an abstract class that handles all of your Database queries, and then constructs them into objects. It'll be easy to set yourself up with parameterized queries this way, and it will standardize how you interact with your database. It'll also make adding new object models a piece of cake.
http://php.net/manual/en/language.oop5.abstract.php
abstract class DB
{
abstract protected function table();
abstract protected function fields();
abstract protected function keys();
public function find()
{
//maybe write yourself a parameterized method that all objects will use...
global $db; //this would be the database connection that you set up elsewhere.
//query, and then pack up as an object
}
public function save()
{
}
public function destroy()
{
}
}
class User extends DB
{
protected function table()
{
//table name
}
protected function fields()
{
//table fields here
}
protected function keys()
{
//table key(s) here
}
//reusable pattern for parameterized queries
public static function get_user( $id )
{
$factory = new User;
$params = array( '=' => array( 'id' => $id ) );
$query = $factory->find( $params );
//return the object
}
}
You'll want to do your database connection from a common configuration file, and just leave it as a global variable for this pattern.
Obviously this is just scratching the surface, but hopefully it gives you some ideas.
Summarize all answers:
Do not use single "God" class for core.
It's better to use list of classes that make their jobs. Create as many class as you need. Each class should be responsible for single job.
Do not use singletones, it's old technique, that is not flexible, use dependecy injection container (DIC) instead.
First, the the best thing to do would be to use Singleton Pattern to get database instance.
class Db{
protected $_db;
private function __construct() {
$this->_db = new Database();
}
public static function getInstance() {
if (!isset(self::$_db)) {
self::$_db = new self();
}
return self::$_db;
}
}
Now you can use it like db::getInstance(); anywhere.
Secondly, you are trying to invent bicycle called Active Record pattern, in function __setAll($attributes).
In third, why do you wrote this thing in class that extends Core?
public function __construct(){
parent::__construct();
}
Finally, class names should be capitalized.
everybody! I have a new question about Kohana 3, or rather about a module structure. I develop a small module called Textblock. It's about an ordinary page or a small insertion to the site layout (e.g. a greeting or a slogan, company name). It contains both controllers and models. Models inherit Sprig_MPTT. And one feature I'd like to implement is one could be able to call this module like this:
$textblock = Textblock::get_single(1); //by id
$children = Textblock::get_children_of(4); //id of parent
and not
$textblock = Sprig::factory('Textblock')->get_single(1);
$children = Sprig::factory('Textblock')->get_children_of(4);
Those methods are defined in Model_Textblock class as static.
So, I made a wrapper class Textblock, that inherits Model_Textblock. What if I suddenly want change Sprig to Jelly, for example? Foreground won't change at all. Another advantage, imho, is more clarity for anyone, who wants to use this module (e.g. it could be another programmer in the team).
But there's a doubt if I'm on a wrong way... So, the question itself: is the suggested a right way to organize my module? Or it's preferable to keep ordinary Sprig::factory('Textblock') where Textblock's functionality is needed, remove additional wrapper class and remove static?
There is no need to extend Model_Textblock. You can create a model instance and call its method:
class Textblock {
public static function get_single($id)
{
return Sprig::factory('textblock')->get_single($id);
}
// etc
}
But this way you should copy model methods in your static class (not DRY). Also, what if you have more than one model? All you want (as I understand) is to easily change AR driver. So I'd preffer this kind of class:
class Textblock {
// saved objects, dont create on model twice
protected static $_instances = array();
public static function model($name)
{
if (! isset(self::$_instances[$name]))
{
$model = Sprig_MPTT::factory($name);
// you can add try..catch to prevent exceptions
// or add another checks
self::$_instances[$name] = $model;
}
return clone self::$_instances[$name];
}
}
and use it like Textblock::model('textblock')->get_single($id).