Object Oriented PHP: Loading data from DB to create objects? - php

I am new to OOP in PHP so here goes this "basic" question:
I have a table of customers:
Table 'customers'
id PRIMARY KEY
name VARCHAR 250
email VARCHAR 1000
is_active ENUM 'n','y'
In a script I need to select all the customers which are active (is_active == 'y') and send them a thank you email. There is a business class associated with the above table called class Customers.
I can write something very simple without using OOP:
$result = mysql_query("SELECT * FROM customers WHERE is_active = 'y'");
while($arr = mysql_fetch_assoc($result))
send this customer a thank you email...
If I were to use OOP, how do I do something as simple as the above? If there are thousands of customers, do I write OO code that loads thousands of customer objects to send each one an email as below?
$result = mysql_query("SELECT * FROM customers WHERE is_active = 'y');
while($arr = mysql_fetch_assoc($result))
$objCustomer = new Customer($arr['id']); //reload what has already been read from the db??
$objCustomer->sendThankYouEmail();
Am I doing something wrong (or silly) above?

I wouldn't reload it from the DB but rather from the array:
$objCustomer = new Customer($arr);
$objCustomer->sendThankYouEmail();
In your Customer object you load the data from the array.
Another way to do it is to do the following (object properties should match the field names):
while($objCustomer = mysql_fetch_object($result, 'Customer')) {
$objCustomer->sendThankYouEmail();
}
Note: If this is something new you are developing you should be using parametrized queries using MySQLI or PDO.

If you really like to work OOP try using Doctrine.
Doctrine 2 maps relational databases to objects.
You could say.
// obtaining the entity manager
$entityManager = EntityManager::create($conn, $config);
$customerRepository = $entityManager->getRepository('Customer');
$customers = $customerRepository->findAll();
forLoop(){
$customers[index]->email // To get the email and do whatever you want with the customer object.
}
With things like this you just have to try and see if it works for you.

Related

easiest way to fetch query to array of object in symfony

View in database I mean :
create view `vMaketType` as select * from MaketType
I have a view in database, but because of doctrine cant support it now, i using query, and fetch it one by one :
$em = $this->getDoctrine()->getManager();
$con = $this->getDoctrine()->getEntityManager()->getConnection();
$stmt = $con->executeQuery('SELECT * FROM vMaketType');
$domain = [];
//I must fetch it and set it one by one
foreach ($stmt->fetchAll() as $row){
$obj = new vMaketType();
$obj->setId($row["Id"]);
$obj->setName($row["Name"]);
$obj->setAmount($row["Amount"]);
array_push($domain, $obj);
}
for me this is really takes too much time to code one by one.
vMaketType is a custom entity I created to send data from controller to [Twig]view.
is there any easier way to fetch to array of object vMaketType?
because I have a view with 24 fields, I wish there is easier way for it.
Perhaps you can try with the serializer:
$obj = $this->get('serializer')->deserialize($row, 'Namespace\MaketType', 'array');
Code not tested, tweaks may be done, see the related doc.

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

how to create a dynamic update function for a mvc crud website

A User clicks on 'View Users' and the php logic fetches the data using MySQL SELECT, passes the data to the table_view, then displays all the 'Users' on the system.
Each table row has a 'edit' hyperlink which fetches an array or form elements, this array of form elements is passed to a 'Form_Generator' which generates the html for the form array, the values for the form are also added in.
So the User is faced with a form ( sometimes 20 elements large ) with the form element values matching the values in the database.
MY QUESTION IS...
How can I make the update dynamic? If not dynamic, how can I make it better?
My current Method is so...
When the user has eddited the values they submit the form, then validation.
might i add that one form may consist of 3 or more tables in the relational database
I could write an update statement for EACH element like:
if ( isset ( $user_input["firstname"] ) )
{
$this -> _database -> update( "UPDATE users SET firstname = '{$user_input["firstname"]}' WHERE user_id = $user_id" );
$this -> _database -> execute();
}
etc etc for ALL fields
or I could use an UPDATE statement with JOINS to update multiple fields at once. like so:
$this-> _database -> custom("UPDATE fitters AS f INNER JOIN user_types AS ut ON f.fitter_id = ut.type_id INNER JOIN users AS u ON u.user_id = ut.user_id SET f.title = '{$user_input["title"]}', f.firstname = '{$user_input["firstname"]}', f.surname = '{$user_input["surname"]}', u.email_address = '{$user_input["email_address"]}' WHERE u.user_id = {$user_input["user_id"]}");
Does anybody know of a better way to do this?
How have you tackled updating database information in your projects?
Using a framework for applications makes life alot easier. I personally like to work with CodeIgniter.
When using a framework like CodeIgniter database operations become a lot easier. Here is an example of how it could be:
public static function editProfile($data)
{
$user = User::find_by_pk($data['id']);
if (isset($data['username'])) {
$user->username = $data['username'];
}
if (isset($data['password'])) {
$user->hashed_password = User::hash_password($data['password']);
}
$user->save();
}
http://codeigniter.com/
This is great website with tutorials to get you started on the subject!
http://heybigname.com/2009/09/04/developing-a-website-with-code-igniter-part-1-configuration/

How to make a "find and update" query in Paris

I am using Paris with Idiorm and I am having problems finding in the documentation a clear instruction on how to find and update a table.
I don't want to insert a sql query into the script. Is there any other way?
Paris is an Active Record implementation based on Idiorm.
Idiorm is an object-relational mapper and fluent query builder.
I am interested in doing something like count = count + 1 all in one go
I found this on their github site:
Updating records
To update the database, change one or more of the properties of the object, then call the save method to commit the changes to the database. Again, you can change the values of the object's properties either by using the set method or by setting the value of the property directly:
$person = ORM::for_table('person')->find_one(5);
// The following two forms are equivalent
$person->set('name', 'Bob Smith');
$person->age = 20;
// Syncronise the object with the database
$person->save();
Creating new records
To add a new record, you need to first create an "empty" object instance. You then set values on the object as normal, and save it.
$person = ORM::for_table('person')->create();
$person->name = 'Joe Bloggs';
$person->age = 40;
$person->save();
After the object has been saved, you can call its id() method to find the autogenerated primary key value that the database assigned to it.
Checking whether a property has been modified
To check whether a property has been changed since the object was created (or last saved), call the is_dirty method:
$name_has_changed = $person->is_dirty('name'); // Returns true or false
According to the documentation on the github page, in idiorm you can update a record by doing the following:
$person = ORM::for_table('person')->find_one(5);
// The following two forms are equivalent
$person->set('name', 'Bob Smith');
$person->age = 20;
// Syncronise the object with the database
$person->save();
Or to do it in 'paris' you do:
$user = Model::factory('User')->find_one($id);
$user->name = 'Paris';
$user->save();

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