PHP: refactoring to OO -- How to model Joins - php

Let's say I have two models:
class Book
{
public $book_id;
public $book_author_id;
public $title;
}
class Author
{
public $author_id;
public $author_name;
}
I'm used to writing something like this:
$DB->query("SELECT book_id, title, author_name
FROM book
LEFT JOIN author
ON book_author_id = author_id
");
Let's assume, that I'm not interested in having separate queries for this association. How do I proceed? Here are some things I've heard:
create a MySQL VIEW of the JOIN
create a model class of the VIEW
The application I'm working on involves dozens of tables and was highly optimized in procedural code (almost no SELECT * anywhere, for instance). I'm refactoring to make it more maintainable (I'm the original creator, too), but I would like to have the flexibility of using joins when I need to without compromising the structure of my files and DB calls.
A possibly related question I have is related to including other models:
class Author
{
public $author_id;
public $author_name;
/* #var Book */ //<--don't really fully understand this but I've seen something like it somewhere
public (array) $authors_books;
}
I'm still searching for answers, but if you could send a link my way, that would be appreciated.

What you are calling "models" are actually domain objects. They should be responsible for dealing with domain business logic, and have nothing to do with storage.
The storage-related logic and interaction should be handled by separate group of objects. One of most sensible solution is using data mappers. Each mapper can deal with multiple tables and complicated SQL.
As for your query, the result of such query would contain information, appropriate for passing to a collection of domain objects.
BTW, that query is quite useless. You forget that each book can have multiple authors. Take for an example this book - it has 4 different authors. To make this query useful, you should have to do GROUP_CONCAT() based on either author_id or book_id.
When implementing such JOIN statements, the database response most likely will be a collection:
$mapper = $factory->buildMapper('BookCollection');
$collection = $factory->buildCollection('Book');
$collection->setSomeCondition('foobar');
$mapper->fetch( $collection );
foreach ( $collection as $item )
{
$item->setSomething('marker');
}
$mapper->store( $collection );
P.S. Your code example seem to be leaking abstraction. It is a bad practice to let other structures to access object's variables directly.
P.P.S. It seems that your understanding of model part of MVC is quite different from how i see it.

Database joins are an artefact of relational databases, you don't need to model them. You need to model what your data is and how it behaves, e.g. you might have a getBooks() method in your Author instances, or a static getByAuthor() method in your Book class (generally, $author->getBooks() should be implemented as Book::getByAuthor($this), so your Author class shouldn't be concerned with Book's implementation details). It's not always a good idea to automatically instantiate all related data (e.g. instantiate Book instances for all books by a given Author instance, as you seem to be considering with your $author_books property), since this might easily degrade into a "load the entire database to memory for each request" scenario.

If you're trying to model your DB in classes, this is a problem that's already been solved.
I suggest you try out the Doctrine framework, which is a full ORM framework for PHP.
Hope that helps.

Related

How to use a user on different parts of an MVC?

OK, I am building an MVC framework. Let's say for example, I have a SongsController. In a database, for each song I have the song's owner id (a user). What if I want to access the users information by getting the user id and selecting from the users table from that id and getting things such as name, email etc. I understand that there are joins, but for this example lets pretend there isn't any. What could I do? Could I create a UsersRepository class? Also, would I want to call it statically or create a new instance of it.
There a multiple ways to structure this.
For instance, you could use a UserModel, which is an object representing the user table.
This object does not provide any functions to launch queries with joins.
Then you could add a repository class, which provides additional functions related to queries, spanning over multiple tables (with joins).
UserModel
getUserName($userId)
UsersRepository
getSongsOfUser($userId)
You can think of this as:
the UserModel being "object 2 table" and
the UserRepository being "object 2 tables".
--
How to work with Models in the Controller? Should i call them statically or dynamically?
The general rule applies: avoid static functions in OOP. So: instantiate your models.
$userRepo = new UserRepository();
$result = $userRepo->getSongsOfUser($userId);
This is mainly because static stuff is really hard to test.
A static function is isolated and you have to pull all the depenencies in, for example the database instance. This leads to other static functions calls, like Database::getInstance() or to static properties access, which has to be populated (somehow, somewhere, before). You see, this gets messy really fast. This often leads to poorly designed spaghetti code applications, where procedural code sauce is mixed with object oriented noodles. Such an architecture is hard to maintain and it's hard to implement new features.
If this is just a hobby project, then $result = UserRepository::getSongsOfUser($userId); would suffice.

How can I render Master Detail data in MVC using PHP?

I can't find an answer to this anywhere. I've seen code examples in C# with ASP.NET MVC, but nothing in PHP outside of a CMS or framework.
If I have two tables, students and classes, how do I get that data rendered in the view?
If I query two different tables in one model (same function/method, however), does that somehow violate the principles of MVC? What about 20 different tables? That sounds like a lot of overhead for nothing a one off table you might only query once or twice. Do I really need 20 models?
Can someone please show me this in straight PHP with no frameworks and no CMS?
EDIT: This is for building my own MVC, so "straight" PHP means me building this component.
My approach would probably be to use a repository for classes and users in this case.
StudentRepository
Retrieves instances of students class based on some criteria. This might have a method called getStudentsByClass($classID) that would retrieve the students for a class by it's class id.
SchoolClassRepository
Retrieves instances of a school class based on some criteria. For instance, classes for a semester.
getClassesBySemester($semesterID)
Then in your regular "SchoolClass" class, I would have a function that uses the StudentRepository to retrieve classes for the current class. For instance:
<?php
class SchoolClass(){
private $id;
private $students;
public function getStudents(){
$repo = new StudentRepository();
return $repo->getStudentsByClass($this->id);
}
}
?>
This would mean that your queries to find students for a class would not be exposed in your SchoolClass model. The only thing that the SchoolClass knows about is that the StudentRepository returns the users that it needs.
You would then pass a SchoolClass model as your data model to grab information in your view.

PHP structuring arrays of objects

As a means to try and learn object oriented PHP scripting, I'm currently attempting to rewrite a database web application that I previously wrote in procedural PHP. The application is used to store car parts and information about car parts.
In my application there are car parts. They are identified by various reference numbers, which are assigned by different organisations (the part's manufacturer, re-manufacturers, vehicle manufacturers, etc.), and any particular car part could have zero, one or many reference numbers as assigned by these organisations (and, confusingly, each reference number may refer to more than one unique car part as defined in the database I'm working on).
As far as I understand things, I am dealing with three different classes of entities. There is that of the car part, the reference number, and that of the reference-assigner (in my internal nomenclature I call these 'referrers'). As I am just getting started with learning OOP, I have begun by creating some very basic classes for each:
class Part {
public $part_id;
public $part_type;
public $weight;
public $notes;
public $references;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
}
class Reference {
public $reference_id;
public $reference;
public $referrer;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
}
class Referrer {
public $referrer_id;
public $referrer_name;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
}
?>
What I've been struggling with is how to populate these and subsequently glue them together. The most basic function of my web application is to view a car part, including its metrics and its assigned reference numbers.
A part_id is included in a page request. Initially, I wrote a constructor method in my Part class which would look up that part in the database, and then another method which would look up reference numbers (which were JOINed with the referrer table) assigned to that Part ID. It would iterate through the results and create a new object for each reference, and hold the complete set in an array indexed by the reference_id datum.
After further reading, I began to understand that I should use a factory class to carry this out, however, as this kind of conjunction between my Part class and my Reference class is not the responsibility of any one of those discrete classes. This made conceptual sense, and so I have since devised a class that I've called PartReferenceFactory, which I understand should be responsible for assembling any kind of collation of part reference numbers:
class PartReferenceFactory {
public static function getReferences(Database $db, $part_id) {
$db_result = $db->query(
'SELECT *
FROM `' . REFERRER_TABLE . '`
LEFT JOIN `' . REFERENCE_TABLE . '` USING (`referrer_id`)
INNER JOIN `' . REFERENCE_REL . '` USING (`reference_id`)
WHERE `part_id` = :part_id
ORDER BY `order` ASC, `referrer_name` ASC, `reference` ASC',
array(':part_id' => $part_id);
);
if(empty($db_result)) {
return FALSE;
} else {
$references = array();
foreach($db_result as $reference_id => $reference_properties) {
$references[$reference_id] = new Reference($db);
$references[$reference_id]->reference = $reference_properties['reference'];
$references[$reference_id]->referrer = new Referrer($db);
$references[$reference_id]->referrer->referrer_id = $reference_properties['referrer_id'];
$references[$reference_id]->referrer->referrer_name = $reference_properties['referrer_id'];
}
return $references;
}
}
}
?>
The getReferences method of my factory class is then called inside my Part class, which I revised thusly:
class Part {
public $part_id;
public $part_type;
public $weight;
public $notes;
public $references;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
function getReferences() {
$this->references = PartReferenceFactory::getReferences($this->db, $this->part_id);
}
}
Really I'm looking for advice on whether my general approach is a good one or if, as I suspect, I've misunderstood something, am overlooking other things, and am tying myself in knots. I will try to distill this into some underlying, directly-answerable questions:
Does my understanding of the purpose of classes and of factory classes seem erroneous?
Is it a bad idea for me to store arrays of objects? I ask from a viewpoint more of design than performance, insofar as they are not intertwined.
Is this even an appropriate way to structure relationships/inter-dependencies between classes in PHP?
Is it correct to call my PartReferenceFactory inside the getReferences method of the (instantiated) Part class? And is storing the returned reference objects within the part objects appropriate?
As a part of the application's GUI, I'll need to provide lists of referrers, requiring me to create another array of ALL referrers independently of any part object. Yet some of these referrers will exist within the $references array inside the part object. It has occurred to me that in order to avoid duplicate referrer objects, I could SELECT a list of all referrers at the beginning of each page request, formulate these into a global array of referrers, and simply reference these from within my Part and Reference classes as needed. However, I have read that it is not good to rely on the global scope within classes. Is there an elegant/best-practice solution to this?
Thank you very much for the time of whomever happens to read this, and I apologise for the extremely long question. I often worry that I mis-explain matters, and so wanted to be as precise as possible. Please let me know if it would be beneficial for any parts of my post to be deleted.
Hmmm, I think Jon is right, this question has taken real commitment to get my head round and I'm still not sure I know everything you're asking, but I'll give it a go.
1) Is your understanding of classes/factory classes right?
Well yes and no. Yes you do understand it, but you're taking a very classroom type approach to the problem, rather than the sort of pragmatism that comes with experience. OOP is a way of modelling real things, but it's still fundamentally a programming tool, so don't over complicate your structure, just to keep it real. The main think OOP gives you over structured programming is inheritance, which means you can code things which are kind of like other things, so reuse code better by only coding the stuff that's actually different. If 2 things would share code, make them a shared parent and put the code in there. Envisaging how the hierarchy might work efficiently is 80% of the task of designing an OOP application, and you're bound to get it wrong first time and have to restructure.
For example. I've coded a number of classes which represent entities in a database: ie Users, Realthings, Collectibles. Each has fundamentally different set of attributes and relations, but also has a core set of things that are similar: the way they're interrogated, the way the data is presented, the fact that they have attributes, fields and relations. So I coded a parent class which everything inherits, and it contains most of the code, then the specific children just define the stuff which is different for each class, and the hard work was deciding how much could go in Indexed to avoid repeating code in the child classes. Initially I had a lot of code in the children, but as it evolved I moved more and more code into the parent class, and thinned out the children. Like I say, don't assume you'll get it right first time.
2) Is it a bad idea to store objects in arrays? Well no, but why would you want to? In your example you have an array of references in the database, where the relationship is a many to many relation (ie you have 3 tables with a joining table in the middle). Then when you get the data you create each object and store it in an array. Sure you can do that, but remember each object has an overhead. Loading everything into memory is fine, but don't do it unless you need to. Also be sure you need a many<=>many relationship. I may have mis-read your explanation, but I thought you'd only need a one<=>many relationship, which could be done by storing a reference to the 'one' in the record of each of the 'many' (thus loosing the middle table and simplifying the join).
5) I'm going to jump to the last one at this point because it feeds into #2. You need to think of your application from different perspectives (a) when you have data and are trying to present it (read) (b) when you have some data and are trying to add new data, with links to existing data (adding a relation) and (c) when you have no data, and are adding a fresh record. How might the user get to each of those perspectives and what would happen. It's often easy to get (a) and (c) to work, but making (b) intuitive is often the hard part, and if you over complicate it, then users simply won't get it. When building up the inner data structures in #2 only do what you need, for the perspective a user is in. Unless you're writing an app, you don't need to load everything, only the stuff for the task at hand.
3) Not sure what you mean by 'is this appropriate'. OOP allows you to tie yourself up in knots, or create wonderful works of art. In theory you should just try to keep it simple. There are great books which give examples of why you might want to make things more complicated, but most of the reasons aren't obvious, so you'll need experience to decide if what you're doing is needlessly over complicating things or if it actually avoids a pitfall. From personal experience if you think it's overcomplicating, it probably is.
4) Not sure if this is what you meant, but I've taken this question to be asking if you've used Factory classes correctly. My understanding of the theory is that what you should end up with, is next to no references to doing things statically, beyond the initial creation of a FactoryClass object, stored statically in the child class being used, then you have to code an abstract method in parent class, implemented in each child class, which gets you that object, so you can call on the object of that FactoryClass, using a method call. I normally only call FactoryClass stuff directly when a non-factory class is initialised (ie you need to populate the static in a new object, incase the class hasn't been init'd yet). I don't see any problem calling it directly as you have, but I'd avoid that as the Factory is IMHO an implementation detail of the class, and so shouldn't be exposed outside that.
In my experience you're always learning new things and discovering pitfalls in OOP, so even thought I've been coding professionally for nearly 20 years, I'd not claim to be an expert on this, so I'm sure there will be totally opposing views to what I've said. I think you learn most by doing what your gut says is right, then not being too stubborn to start over again, if you gut changes it's mind :-)

database connections in PHP classes

I need some advice\suggestions on how to create\handle database connections for a project I'm working on. I'm creating a simple work order system for my company using PHP 5.4.3, right now there isn't any type of authentication as I'm not ready for that complexity. So far I'm planning on the following structure
<? php
class Db {
private static $dbh = null;
static function open_connection() {
self::$dbh = new PDO(... }
static function query($sql) {
$result = self::$dbh->... }
static function fetch_array($result){
...}
...
}
class Workorder extends Db {
protected static $table_name = ...
...
public $wonum;
...
function instantiate {
//return workorder objects
...}
function findallwos {
//find all work orders...
...}
...}
I think this will work fine for pages that I need to display all of the work orders or put in new work orders. But I have a few pages that require very simple queries, for example one of the reporting pages will just have a drop down list of the 3 technicians we have working for us, if I was using a global $dbh variable I could just do
function create_dropdown () {
GLOBAL $dbh;
$sql = "select...";
$sth = $dbh->prepare($sql);
$sth->execute();
$arry = $sth->fetchAll(PDO::FETCH_ASSOC);
.....
But I'd rather stay away from global variables as eventually I would like to add future complexity to this site which might not work with globals. (Including multiple users with authentication etc). So my questions are:
Should I not use the Db class as I have it designed, and instead use some sort of connection_factory class instead that passes out connections? (and not have my workorder class be an extension of anything)
Should I just use static calls to the Db class to pull in simple queries? db::fetch_array...
Or do you guys have any other suggestions? I've come across a lot of different ways to go about this, but ideally I'd like to design this so that I don't have to completely recode everything when I get to the point where I'm adding multiple users with different permissions etc.
What I personally would criticise on the code design you provided is that you don't separate concerns and that there is no abstraction. Don't make the huge mistake so many did before to mix SQL statements, the type of presentation and your business logic all over your code. At some point you might want to switch the database product, create a mobile version, add functionality ... and then you need to change dozens of files.
To prevent these things in general, I would suggest an approach like this:
Create a clean and lightweight model of the entities and their relationships and don't care about persistence (i.e. database), access control, etc. at this point
(e.g. a simple class Workorder that contains classes of Employee, ...)
Write interfaces that define the necessary persistence operations on your model (i.e. saveWorkorder(Workorder $workorder), getAllWorkorders(), loadWorkorder(), ...). In your code, refer only to these interfaces and the methods they provide and never to a concrete implementation
Now, implement the classes of the persistence interfaces with a certain DB. Don't forget to encapsulate the fundamental DB actions in a class as well as you will use them in many persistence classes.
I hope my answer is not too vague, but software design is a very wide field and it's hard to cover all aspects in one single answer. And as with all questions concerning software design, there's no correct or wrong solution as it depends a lot on the concrete project, the requirements, on personal coding style, etc...
On a side note, if you plan to do more projects of this kind, it probably would pay off to invest the time to get known with a framework (like Zend Framework, Symphony, CakePHP and many more) as they provide you with a lot of existing functionality that you can use out of the box, like database connectors, separation of views and business logic, ...

How to Optimize Models in Zend Framework?

I need to figure out a best practice for utilizing models efficiently in Zend Framework.
Currently, I have classes extending Zend_Db_Table_Abstract which handle my queries to each class' respective table.
When I need to access say 5 of those tables from a controller, I find myself creating 5 new instances of each specific Zend_Db_Table object. This is really ineffective.
I've thought about implementing a Factory pattern to create new instances (or provide existing static copy) but am not sure. Is this the best way to go about it?
What is the correct way to handle models ensuring speed without consuming excessive resources? Should lazy loading come into play here?
[EDIT]
As an example, I have a class I use to handle getting details about a location from a raw search query and need these objects in order to parse the query:
// Initialize database object
$this->dbLocations = new Model_Locations;
$this->dbStates = new Model_States;
$this->dbZipcodes = new Model_Zipcodes;
$this->dbLookup = new Model_Lookup;
In another class, I may need to access those models again so I repeat the above code. Essentially reinitializing objects that could be static/singleton.
I tend to work at the DbTable like you do. I've found it effective when I need to query multiple tables in a single action to create another layer of model above the dbTable. Similar to a service or domain layer. This way I only have to call a single model but I still have the functionality I need.
Here is a simple example that may eventually interact with 5 DbTable classes and most likely a couple of Row classes as well:
<?php
class Application_Model_TrackInfo
{
protected $_track;
protected $_bidLocation;
protected $_weekend;
protected $_shift;
protected $_station;
public function __construct() {
//assign DbTable models to properties for convience
$this->_track = new Application_Model_DbTable_Track();
}
/**
*
* #param type $trackId
* #return type object
*/
public function getByTrackId($trackId) {
$trackData = $this->_track->fetchRow($trackId);
//getAllInfo() Application_Model_Row_TRack
$result = $trackData->getAllInfo();
//returns std object reflecting data from 3 DbTable classes
return $result;
}
/**
*Get Station from trackid through bidlocationid
*
* #param type $trackId
* #return type object
*/
public function getStation($trackId){
$data = $this->_track->fetchRow($trackId);
//This a Application_Model_Row_Track method
$result= $data->getStationFromBidLocation();
return $result;
}
}
I hope this helps.
[EDIT]
Since I wrote this answer I have learned the benefits of Domain Models and Data Mappers. Wow what a difference in my app. Not a magic bullet, but a huge improvement.
Thanks to
Alejandro Gervasio over at PHPMaster.com
Rob Allen at Akrabat.com
and
Pádraic Brady at Surviving The Deepend
for all their help in understanding this pattern.
You seem to be in a possition where you require efficient data management with features that the current Zend framework does not come with. Zend does not have a built in engine for working with databases of any sort, it simply has a wrapper classes which help you write your queries.
What you need is an object relational model (ORM) which is a must-have in a professional framework. As I understand it, ORM is a framework by itself, it has patterns and strongly defined ways of "doing things", supports lazy loading (it takes the most of it) and optimizes your queries to the fullest. When you use ORM you don't even write SQL, instead you need to change your interpretation of data storage, you need to forget about tables and focus on Objects. In Doctrine for example each type (table) is specified by a Class and each record (row) as a class instance where you have access to different methods and properties. It supports event listeners and crazy cascading rellations.
No more need to extract rows from related tables when you delete records (it is automatic), no more need to write complex and chaotic scripts to ensure filesystem synchronisation, you can migrate to almost any db engine at any time (mysql, postgresql, simplesql..) and more..
I've been using Doctrine 2 in conjunction with Symfony 2 framework and I have to say I wouldn't go back to Zend for anything. Yes, it is complex and heavy, but really the ultimate solution. When you come to a moment when you need to manage hundreds of tables with millions of records total - then you will see the difference.
So, final summation:
ORM is what you need, there are many solutions, I know of two really good: Doctrine 1 or 2 and Propel.
P.S.: ORM is an independant part of your system, so you don't really need to use a specific framework, Zend can be configured to work with Doctrine wonderfully :)

Categories