Creating nested relationships with an ORM and minimizing queries - php

Edit 3
After reading a boat load I really don't think with any ORM or system in general it is possible to build the relationships of organized objects like I want in fewer queries that I am using. If any can provide an example of it being possible I would kiss you.
In Edit 2 The nested for loops I think is the best solution running
Total_queries = 1 + 2(Slides_in_project) + Shapes_in_project
| | \
Query to get project | \
| \
Query to get slides and double because of points \
\
Get all the shapes in the project
I would love a better example because to populate simple projects I would probably be running 200-500 queries. This is bad.
Edit 2
Well I have been playing with this for a while now and I have some results but I do not think they are the "RIGHT" way and that matters to me a lot. What I do is I use the where_related method to get the right objects but I think my query count is still pretty high and I know an ORM can do better. When I use the where related to create the proper hierarchy I have to use nested foreach loops and I don't like that. That means useless querying.
Here is the solution I came up with
function get_project_points($link_id)
{
echo "<pre>";
foreach($this->where('link_id', $link_id)->get()->slide->where_related('project', 'id', $this)->get() as $slide){
echo $slide->id."<br>";
foreach($slide->shape->where_related('slide', 'id', $slide->id)->get() as $shape){
echo "\t".$shape->id."<br>";
foreach ($shape->point->where_related('shape', 'id', $shape->id)->get() as $point) {
echo "\t\t".$point->id."<br>";
}
}
}
}
This outputs a nice tiered structure and as you can see it would be easy to replace the echos with object/array population.
What I would rather have though is one chained command that did the same thing if possible that way scoping isn't an issue either.
Some chain more resembling
$this->where('link_id', $link_id)->get()
->slide->where_related('project', 'id', $this)->get()
->shape->where_related('slide', 'id', $slide->id)->get()
->point->where_related('shape', 'id', $shape->id)->get()
That of course does not achieve anywhere near the same results as the nested foreach loops but what I would like to know is it possible to chain relationships and populate objects without nested foreach
So I just did some profiling and the nested foreach loops generate 63 queries on a small project, and take almost half a second to generate results. This is really too slow. There must be a better query.
__________Edit 1
All the below information is great but I have been playing with it and I cannot seem to get any relationship to work let alone a 3 tiered one. I have tried just about everything I can think of and read the doc's but for somereason my brain doesn't like the ORM.
I would like to just echo the id's of all slides in a project. I will give a list of what I have tried with no avail. My model structure is the same as below I am just adding methodes.
class Project extends DataMapper {
var $has_many = array("slide");
function get_project_slides($link_id)
{
$this->where('link_id', $link_id)
->where_related('slides', 'project_id'
$this->where('link_id', $link_id)->get()->id
)
->get();
}
}
And I have tried what I would think is the logical opposite in the Slide Method.
What am I doing wrong... How do you structure ORM relationships?
Original Question
I am using an ORM for the first time and I am having huge problems visualizing how to structure the code to pull data from the relationships.
I am using DataMapper as my ORM with CodeIgniter. I have the installation working just fine and I read all the docs, I just cannot get my head around how to get information in controllers
+-----------+ +------------+ +---------+ +----------+
| projects | | slides | | shapes | | points |
+-----------+ +------------+ +---------+ +----------+
| id | | id | | id | | id |
+-----------+ | project_id | |slide_id | | shape_id |
+------------+ +---------+ | x |
| y |
+----------+
Models -
project.php
class Project extends DataMapper {
var $has_many = array("slide");
}
// End of project.php
// Location: ./application/models/project.php
slide.php
<?php
class Slide extends DataMapper {
var $has_many = array("shape");
var $has_one = array("project");
}
// End of slide.php
// Location: ./application/models/slide.php
shape.php
<?php
class Shape extends DataMapper {
var $has_many = array("point");
var $has_one = array("slide");
}
// End of shape.php
// Location: ./application/models/shape.php
point.php
<?php
class Point extends DataMapper {
var $has_one = array("shape");
}
// End of point.php
// Location: ./application/models/point.php
The above should create a decending one->many relationship between projects->slides->shapes->points
How do you start to deal with information? When I was not using an ORM I handled all data processing in the Model is this incorrect for the ORM Models? Say you wanted to get all the points in all the shapes in project 1 how would you go about structuring such a call?
I don't really need specific code if you want that would be helpful. What I really need is some ideas on how to visualize how to tier the objects so you can deal with each at any tier.

First of all, I'm sorry to break this to you , but CodeIgniter's DataMapper is actually a variation of ActiveRecord pattern.
If you care, you compare the real DataMapper pattern with its counterpart - ActiveRecord. In short - difference is in fact that in DM pattern you Domain Object is unaware of type ( and even the existence ) of storage. It is used in manner like $mapper->store( $user );.
"Favor object composition over class
inheritance." © GoF
That said..
If i read the examples right then it should work like this:
( i am assuming that relationships between 'entities' are already established )
class Project extends DataMapper
{
// --- the rest of your stuff
public function get_all_points()
{
$points = array();
$slides = $this->slide->get()->all;
foreach ( $slides as $slide )
{
$shapes = $slide->shape->get()->all;
foreach ( $shapes as $shape )
{
$points = array_merge( $point = $shape->point->get();
}
}
return $points;
}
}
Then you can use something like
$project = new Project;
$all_points = $project->where( 'id' , 1 )->get_all_points();
foreach ( $all_points as $point )
{
$point->x = 0;
$point->save();
}
This should gather all th points that are related to project with ID 1, and set the X value to 0 and store each in the database .. not that any sane person would do it.
I am not using any sort of ORM, that's why i really hope i got this wrong, because this looks to me like an abomination.

I'm not sure how Datamapper does it but I have a custom GenericObject model for Codeigniter that does ORM like this:
class Article extends GenericObject
{
public $relationships = array ( "has_many" => array ("comments"), "has_one" => array ("users") );
}
class Comments extends GenericObject
{
public $relationships = array ( "belongs_to" => array ("articles", "users"), "has_one" => array ("users") );
}
class Users extends GenericObject
{
public $relationships = array ( "has_many" => array ("comments", "articles") );
}
If I want to get everything from a User then I can just do something like:
$User = new User( $some_user_id );
$User->boot_relations("all");
foreach ($User->Comments as $Comment)
{
echo $Comment->title."<br />";
echo $Comment->body."<br />";
echo "written by ".$User->username;
}
So it can be fairly elegant (or at least I like to think so).

With most relational data, I typically lazy-load objects at they are needed. I'm not a PHP developer, but here's what I would do in pseudo-code.
class Projects {
var slides = null;
function getSlides() {
if(slides == null) {
slides = getSlidesForProject(this.id);
}
return slides;
}
}
class Slides {
var shapes = null;
function getShapes() {
if(shapes == null) {
shapes = getShapesForSlide(this.id);
}
return slides;
}
}
class Shapes {
//... same as Projects.getSlides and Slides.getShapes
}
Unfortunately, this causes multiple calls to the database if you needed to get all Points for a Project.
With any MVC solution, I recommend going with a light Controller and a heavy Model to make code reuse and testing easier.

First off : I don't know anything about CI's own ORM implementation, but when I see what you are doing, either it's missing some functionality or you're using it in the wrong way (from your edit #2).
In Propel however (just mentioning this because that's what I use most if the time, Doctrine is another good alternative) these things are easily done, especially in the new 1.6 branch, using fluent interfaces. Just check out the docs on Relationships. Doesn't that look like something you'd want to use? :p

From what I understand, you want to retrieve one project with all the associated points, given the constraints between each table.
Check this sqlFiddle: http://sqlfiddle.com/#!2/9ed46/2
Schema cration:
CREATE TABLE project
(
id int auto_increment primary key,
name varchar(20)
);
CREATE TABLE slide
(
id int auto_increment primary key,
name varchar(20),
project_id int
);
CREATE TABLE shape
(
id int auto_increment primary key,
name varchar(20),
slide_id int
);
CREATE TABLE point
(
id int auto_increment primary key,
name varchar(20),
shape_id int
);
Request:
select project.id as project_id, project.name as project_name,
slide.id as slide_id, slide.name as slide_name,
shape.id as shape_id, shape.name as shape_name,
point.id as point_id, point.name as point_name
from project
left join slide on slide.project_id = project.id
left join shape on shape.slide_id = slide.id
left join point on point.shape_id = shape.id
where project.id = 1
It returns something like this:
PROJECT_ID PROJECT_NAME SLIDE_ID SLIDE_NAME SHAPE_ID SHAPE_NAME POINT_ID POINT_NAME
1 fst_project 1 fst_slide 1 fst_shape 1 first_pt
1 fst_project 1 fst_slide 1 fst_shape 2 2nd_pt
...
By processing this output, you could construct an object tree that is like you want, everything in 1 query. But this post-processing may take some time. You would have to loop through each point.

Have a look at Granada.
From the readme:
class User extends Model {
public static $_table = 'user';
public function post(){
return $this->has_many('Post');
}
public function avatar(){
return $this->has_one('Avatar');
}
}
You can include relationships inside your relationships !
$user_list = Model::factory('User')->with(array('post'=>array('with'=>'comments')),'avatar')->find_many();
It will make 3 querys:
SELECT * FROM user
SELECT * FROM avatar WHERE user.id IN (......)
SELECT * FROM post WHERE user.id IN (.....)

Related

Can I have a field that combines multiple MySQL columns into one array in a Laravel Model

I am currently trying to construct a Laravel model based on a list of courses and course sections. For each record in the Course Sections database table, there are 7 columns for each day of the week that it might be on.
CourseID|SectionNumber|...|Mon|Tue|Wed|Thu|Fri|Sat|Sun|
-------------------------------------------------------
1001 | 01 |...|Mon| 0 |Wed| 0 | 0 | 0 | 0 |
Admittedly, it's not the best designed database (it should probably be booleans, and would also probably make sense as a relations table rather than in the same large table) but I don't have direct control over that part.
But what I would like to do is have all of those days stored in an array under one value $days in the Course model, however I'm not quite sure where to go about it. My end goal is to be able to Serialize a CourseSection Model into a JSON feed.
$course->days;
//should return [Mon, Wed]
Right now, in my CourseController, I have the following code that constructs that array as it feeds it to the View based off of a raw query
$days = array_where([$result->isMon, $result->isTue, $result->isWed, $result->isThu, $result->isFri, $result->isSat, $result->isSun],
function ($key, $value)
{
return $value != "0";
});
$courses[$course_key]['sections'][$result->section_number]->days = $days;
I suppose my question is can I do this all in one model? Is it possible to have variables equal an array? Or should this stay in the Controller and have the Model as a direct representation of the structure in the database?
You can use Accessors and Mutators to append extra data to your Eloquent models.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Course extends Eloquent
{
protected $appends = ['days'];
public function getDaysAttribute()
{
$values = [];
// Build your array of data from your existing database structure here...
return $values;
}
}
You can then refer to this new item without additional work in your controllers:
$course = Course::find(1);
$array = $course->days; // This value will come from the getDaysAttribute() value in the Eloquent model
Note: I haven't tested this code, but I've taken it from one of my projects built in Laravel 5.1 which utilises these methods. I haven't written the code for generating the $values array, but you should be able to put that together based on your existing code.
Alternatively, if you wanted to modify your database structure, you could look at using Array Casting which would automatically serialise/deserialise an array for storing as text in the database.
class Course extends Model {
public $appends = ['days'];
public function getDaysAttribute(){
$days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
$course = this;
return array_where($days,function($key, $val) use ($course)){
return $course[$value] != 0;
}
}
}
Then you can use $course->days, and when you serialize to JSON the days attribute will be included courtesy of the appends attribute.

Best way to get readable data from id

i was getting in a question when i got this scenario:
I have to make a history log about what the user does and of course the user can do a lots different action.
i thought two different 2 way for make it i just need someone that can help me to follow the right way.
First way:
Create 2 different tables
History_user
History_type
History_user table
id | user_id | history_type (int)
1 1 1
1 3 2
History_type
id | name_action (string)
1 The user has posted on the wall
2 The user has change his profile picture
and then just join on the query with History_user.history_type = History_type.id
Second way:
is create the History_user table and an helper example called Converter.
<?php
class Converter {
function history($type_history) {
switch($type_history) {
case 1:
$human_history = "The user has posted on the wall";
break;
case 2:
$human_history = "The user has change his profile picture";
break;
}
return $human_history;
}
}
$converter = new Converter();
$converter->history(1);
I was looking for the better way for do that, in terms of performance and maintainability. Thank you.
Both helper and History_type table are necessary for information representation. In terms of performance it doesn't really matter, because you will insert only in one table on user action. If you need to represent data, you will need just one more query to get descriptions of actions (without joins, ofc, if you want some performance). So 2 tables way is more flexible and extendable.
You still could do that helper function which lets say will have static cache variable - array of id => name of actions, which will be lazy loaded on history() function like this:
class Converter {
protected static $_cache;
protected static function _loadCache() {
if (null !== self::$_cache) {
return;
}
self::$_cache = array();
$query = "SELECT * FROM `History_type`";
$res = mysql_query($query);
while ($row = mysql_fetch_assoc($res)) {
self::$_cache[(int) $row['id']] = $row['action'];
}
}
public static function history($id) {
self::_loadCache();
return isset(self::$_cache[$id]) ? self::$_cache[$id] : 'Undefined action';
}
}
Converter::history(1);

2-table interaction: insert, get result, insert

I need to make a fundamental decision of my database/web interaction and I am missing the knowledge to even find proper search terms.
Background:
I am building a family website which supports a forum, family tree, pvp games with rankings and more details, all from a datamodel. Technologies right now: Php, MySQL, javascript in object oriented fashion.
Requirement:
In a forum datamodel, process a written post as addition of a new forum topic (thread).
Current approach:
In my current datamodel this would imply and update on two tables: Post and Topic.
I would need to insert a row in the topic table, then get the newly generated topicId(sequence), and then use that in an insert to the post table.
Problem:
I feel this is too much work for what needs to happen, too much interaction.
But it will become a typical requirement if I stick with the current approach.
Question:
am I on the right track anyway or should I
restructure the datamodel or
pick another way of database interaction (e.g. stored procedures)
am I facing a typical example where you would use methodology/framework xyz.
Currently tables have following structure (loosely based on this one from erdiagrams.com)
TOPIC: ('thread')
id
Forum_ID (FK)
Person_ID (FK)(threadcreator)
IsLocked
IsSticky
Subject
ViewCount
DateCreated
Tc_post_id - trigger to last post_id in this thread
POST
id
topic_id(FK)
person_id(FK)
subject
message
timestamp
replyto
Then I have a view that collects the last post for each topic and displays some info on that as well (e.g. last poster image) over the trigger Tc_post_id.
Ad 1 and 2: Your data model is fine. Using foreign keys is crucial here. One more thing that you need to take care of is that the database should ensure there is a TOPIC record for each POST. This is done by setting POST.topic_id NOT NULL attribute. This is sufficient safety mechanism on the DB side, as it ensures that no POST will be left without TOPIC. No matter what you do now with your POST you are obligated to provide a TOPIC.
Ad 3: A trigger with stored procedure is not recommended here as you have additional data in your TOPIC table (IsSticky, IsLocked, etc), which you might want to provide upon TOPIC record creation. Also, if such a trigger would be applicable, the database design would be a subject to denormalization.
Ad 4: On the business logic side you can now aid yourself by writing a automated mechanism to create the TOPIC record every time a new POST record is created without specified topic_id. I recommend using some ORM for this or take advantage of the data models available in any MVC framework. The blueprint for such models would look like this:
abstract class AModel // this class should be provided by ORM or framework
{
/**
* #var PDO
*/
protected $_db_driver;
public function getLastInsertId()
{
$stmt = $this->_db_driver->prepare('SELECT LAST_INSERT_ID() AS id');
$stmt->execute();
return $stmt->fetch(PDO::FETCH_OBJ)->id;
}
public abstract function getFieldList();
}
class ForumTopicModel extends AModel
{
public function insert(array $data)
{
$sql = 'INSERT INTO topic VALUES (:id, :forum_id, :person_id, :is_locked, ...)';
$stmt = $this->_db_driver->prepare($sql);
return $stmt->execute($data);
}
public function getFieldList()
{
return array('id', 'forum_id', 'person_id', 'is_locked', /*...*/);
}
// ...
}
class ForumPostModel extends AModel
{
public function insert(array $data)
{
$sql = 'INSERT INTO post VALUES (:id, :topic_id, :person_id, :subject, ...)';
$stmt = $this->_db_driver->prepare($sql);
return $stmt->execute($data);
}
public function getFieldList()
{
return array('id', 'topic_id', 'person_id', 'subject', /*...*/);
}
public function insertInitialTopicPost(array $form_data)
{
$this->_db_driver->beginTransaction();
$result = true;
if ( empty($form_data['topic_id']) ) {
// no topic_id provided, so create new one:
$topic = new ForumTopicModel();
$topic_data = array_intersect_key(
$form_data, array_flip($topic->getFieldList())
);
$result = $topic->insert($topic_data);
$form_data['topic_id'] = $topic->getLastInsertId();
}
if ( $result ) {
$forum_post_data = array_intersect_key(
$form_data, array_flip($this->getFieldList())
);
$result = $this->insert($forum_post_data);
}
if ( $result ) {
$this->_db_driver->commit();
}
else {
$this->_db_driver->rollBack();
}
return $result;
}
// ...
}
Note: as a good MVC practice those models should be the only place to directly operate on the table rows. Otherwise you'll end up getting SQL errors (but the data model will remain coherent, so you don't have to worry that something will break).
Finally take advantage of your models in the controller layer:
class ForumPostController extends AController
{
public function createInitialTopicPostAction()
{
$form_data = $this->getRequest()->getPost(); /* wrapper for getting
the $_POST array */
// (...) validate and filter $form_data here
$forumPost = new ForumPostModel();
$result = $forumPost->insertInitialTopicPost($form_data);
if ( $result ) {
// display success message
}
else {
// display failure message
}
}
}
The way I understand it: topics are containers of posts.
Topics table would be rather minimal, and would perhaps only contain a topic id (PK) and topic title.
The posts themselves will contain post id (PK), topic id (FK), timestamps, author id, text.
I would utilize InnoDB and foreign keys, so a topic that is deleted could delete all of its child posts.
(edit:)
In this answer I posted a way to do it using mysql_insert_id(), which would be still a technically correct solution (correct me if wrong).
However instead I will now go for the PDO wrapper I guess. And also, this is not an answer to the general modeling/approach question.
Still, following would be a way to do it:
$sql = "INSERT INTO topic VALUES (NULL,'$forumId',<more parameters>)";
$result = mysql_query($sql);
# get the generated id
$topicId = mysql_insert_id();
# and insert into the post table
$sql = "INSERT INTO post VALUES (NULL,'$topicId',<more parameters>)";
$result = mysql_query($sql);
mysql_free_result($result);
Source: http://www.desilva.biz/mysql/insertid.html

Is there a way to search all the tables in a mySQL database?

Basically I have a database full of tables and I want to go through them all until I find a result that matches my search query. Is there a way to do this? Or at least a command to return all of the table names so that I could loop through them until I find the right value?
thanks!
Aaah, search engines. Exciting subject, but I would rather build something with internal intelligence rather than using brute force solution. Yes - checking every table/column in database is brute force and may result in sluggishness and false positives.
Let me present you with something I would use instead. With below solution each table/column worth scanning needs to be added manually, but everything else is automatic. Here's the usage:
$e = new SearchEngine();
$e->addTable('users', 'id', 'login'); // table, primary key name, column to be searched in
$e->addTable('users', 'id', 'last_name');
$e->addTable('towns', 'id', 'name');
print_r($e->search('austin')); // we search for exact match for word "austin"
And here's how it was implemented:
class SearchEngine {
protected $tables = array();
public function addTable($table, $key, $column) {
$this->tables[] = array(
'table' => $table,
'key' => $key,
'column' => $column
);
}
public function search($term) {
$q = array();
foreach ($this->tables as $t) {
list($table, $key, $column) = $t;
$q[] = "
SELECT
$key AS searched_key,
'$key' AS searched_key_name,
'$table' AS searched_table,
'$column' AS searched_column,
$column AS searched_value
FROM $table
WHERE $column = $term
";
}
$sql = implode(' UNION ', $q);
// query the database
// return results
}
} // class SearchEngine
Let's analyse example output:
searched_key | searched_key_name | searched_table | searched_column | searched_value
-------------+-------------------+----------------+-----------------+---------------
276 | id | users | login | austin
1782 | id | users | last_name | austin
71 | id | towns | name | austin
From the table above you can figure out that phrase "austin" was found in table users, column login (primary key 276) and column last_name (primary key 1782). It was also found in table towns in column name (primary key 71);
Such search result may be sufficient for you. Or else, you can further process the list to select full row from each table:
$out = array();
foreach ($rows as $row) {
$sql = "
SELECT * FROM {$row['searched_table']}
WHERE {$row['searched_key_name']} = {$row['searched_key']}
LIMIT 1
";
// query the database
// append result to $out array
}
return $out;
This way you will end up with full search result (as opposed to intermediate results from previous table):
id: 276, login: austin, last_name: Powers, email: austin.powers#gmail.com
id: 1782, login: michael, last_name: austin, email: michael.e#gmail.com
id: 71, name: austin, state: texas, country: usa
Because current implementation is restricted to fixed comparison operator (WHERE field = value), you may want to introduce some flexibility here. If so, search operator needs to be delegated to external class and injected into search() function:
public function search(SearchOperator $operator, $term) {
...
Then SearchOperator needs to be taken into account by replacing WHERE condition with the below:
WHERE {$operator->toSQL($column, $term)}
Now let's focus on SearchOperator implementation. Since operator implementation provides only one method, namely toSQL, we don't need full class, or even abstract class. Interface will suffice in this case:
interface SearchOperator {
public function toSQL($column, $term);
} // interface SearchOperator
And let's define couple of implementations representing = (equals) and LIKE operators:
class Equals implements SearchOperator {
public function toSQL($column, $term) {
return "$column = '$term'";
}
} // class Equals
class Like implements SearchOperator {
public function toSQL($column, $term) {
return "$column LIKE '$term'";
}
} // class Like
Naturally, any other implementation is possible - think about classes called StartsWith, EndsWith, or DoesNotContain.
See updated solution usage:
$e = new SearchEngine();
$e->addTable('users', 'id', 'login');
$e->addTable('users', 'id', 'last_name');
$e->addTable('towns', 'id', 'name');
print_r($e->search(new Like(), 'austin%')); // here we search for columns being LIKE 'austin%'
Time to leave some final remarks:
Above examples are incomplete. Database querying code was omitted for clarity.
SQL used in examples does not sanitize input data. I strongly urge you to use prepared statements with bound parameters to avoid huge security risk.
Search algorithm presented above is a naive one. Some optimisation can be done (i.e. grouping queries referring to the same table). But don't optimise prematurely - wait until it becomes a real issue.
Hoping this was helpful.
Very bad idea. However, should you need to search all tables (and you are using MySQL) you can get a list with:
SHOW TABLES;
And then loop through each and (assuming you know the columns) query them.
I guess you could use Mysql's full-text search for this?
As others have said, it's possible to extract all the tables names and their column names from meta data dictionary. Take a look at the "information_schema" database. You can get a list of tables which you can then iterate over.
But chances are you are using the database wrong. We don't query the database, we query the data model. The data model is implemented as a set of tables/views etc.
Can you provide us with some background as to why you need to do this? Maybe there are better alternatives?
You can get all the tables in your database with
SHOW TABLES;
Then you can loop through the tables and find out the structure for each table with
DISPLAY table_name;
But you still would need to have a vague idea about how to query to columns of each table in order to find anything. So unless you have a more specialized problem, e.g. al tables have the same known structure, I would agree with the sentiment that you might be using the database wrong and there might be a better way.
There is a nice library for reading all tables, ridona

How to code in OO PHP?

How can I do this in OO PHP:
A form ('in newstudent.php') asks the user to enter his name, course and year.
After selecting 'Submit' button, the page will go to 'records.php'
records.php - contains a table that displays all the records (columns: name, course, year)
when the user selects 'Submit', the new record will be added to the database which has a table named STUDENTS
SQL code
CREATE TABLE STUDENTS(
NAME VARCHAR(25) NOT NULL,
COURSE VARCHAR(25) NOT NULL,
YEAR INT NOT NULL,
CONSTRAINT STUDENTS_PK PRIMARY KEY(NAME));
*please don't mind about the primary key coz i know it's not accurate to use name as the primary key. this is just for exmple purposes.
and also...How can i manipulate data in DB using OO PHP?
Thanks
Read a book
Search Google
Create Student Object
Create Database Object
Query Database Object to insert Student Object
Well, if you want to switch to a OO method of representing students in a database, how about a 'Student' class that looks something like the definition below (although this is very basic, and not a full ORM in any way). It takes you halfway to an ActiveRecord style approach.
Note that I have assumed you will use an integer id column, not doing so makes the whole class annoying.
class Student {
var $id = -1;
var $name;
var $course;
var $year;
public static function newFromID ($id)
{
//fetch a row ($row) from the students table matching the given id
//perhaps returning false if the student doesn't exist?
return self::newFromRow($row);
}
// this method should return a new student object given a specific db row
// and should be called from newFromID. This function means that if the table
// changes, modifications only have to be made in one place
public static function newFromRow($row)
{
$obj = new Student();
//fill in the fields of the object based on the content of the row
return $obj;
}
public static function getAllStudents()
{
//perhaps return an array of student objects, by doing a broad select,
//and passing each row to newFromRow?
}
//this should save the object to the database, either inserting or updating as appropriate
public function save()
{
if($this->id == -1)
{
//insert, store the auto_increment id in $this->id
} else {
//update
}
}
}
So, to create a new student, and save it to the database:
$student = new Student();
$student->name = "John Smith";
$student->course = "French";
$student->year = 2;
$student->save();
In reality, it is often more sensible to use an existing ORM system, but if that isn't an option, you can consider writing your own.
Maybe you talk about ORM - Object Relation Mapping patterns? There are many different approaches to get mapped SQL data objects to PHP classes: Propel, Doctrine (both can be used with Symfony framework), ActiveRecord.
Of course, you can try to implement your own ORM system. You need to write data access layer for this ORM, classes which describes SQL tables and many other things. It is very interesting (for educational purposes).

Categories