Digital magic. A small project for controlling smart light bulbs.
PHP Development with MongoDB (Fitz Agard)
1. MongoSF - PHP Development With MongoDB
Presented By: Fitz Agard - LightCube Solutions LLC
April 30, 2010
2. Introductions - Who is this guy?
{ “name”: “Fitz Agard”,
“description”: [“Developer”,”Consultant”,”Data Junkie”, “Educator”, “Engineer”],
“location”: “New York”,
“companies”:[
{“name”: “LightCube Solutions”, “url”: “www.lightcubesolutions.com”}
],
“urls”:[
{“name”: “LinkedIn”, “url”: “http://www.linkedin.com/in/fitzagard”},
{“name”: “Twitter”, “url”: “http://www.twitter.com/fitzhagard”}
],
“email”: “fhagard@lightcube.us”
}
(If the above formatting confused you please see - http://json.org/)
3. Why PHP Developers Should Use MongoDB?
PHP Reasons Database Reasons
• Enhanced Development Cycle - Itʼs no longer • Document-oriented storage - JSON-style documents with dynamic
necessary to go back and forth between the Database schemas offer simplicity and power.
Schema and Object. • Full Index Support - Index on any attribute.
• Easy Ramp-Up - Queries are just an array away. • Replication & High Availability - Mirror across LANs and WANs.
• No Need For ORM - No Schema! • Auto-Sharding - Scale horizontally without compromising functionality.
• DBA? What DBA? • Querying - Rich, document-based queries.
• Arrays, Array, Arrays! • Fast In-Place Updates - Atomic modifiers for contention-free
performance.
• Map/Reduce - Flexible aggregation and data processing.
• GridFS - Store files of any size.
5. Mongo and PHP in a Nutshell
(Connectivity)
http://us2.php.net/manual/en/mongo.connecting.php
function __construct()
{
global $dbname, $dbuser, $dbpass;
$this->dbname = $dbname;
$this->dbuser = $dbuser;
$this->dbpass = $dbpass;
// Make the initial connection
try {
$this->_link = new Mongo();
// Select the DB
$this->db = $this->_link->selectDB($this->dbname);
// Authenticate
$result = $this->db->authenticate($this->dbuser, $this->dbpass);
if ($result['ok'] == 0) {
// Authentication failed.
$this->error = ($result['errmsg'] == 'auth fails') ? 'Database Authentication Failure' : $result['errmsg'];
$this->_connected = false;
} else {
$this->_connected = true;
}
} catch (Exception $e) {
$this->error = (empty($this->error)) ? 'Database Connection Error' : $this->error;
}
}
6. Mongo and PHP in a Nutshell
(Simple Queries)
http://us2.php.net/manual/en/mongo.queries.php
/*
* SELECT * FROM students
* WHERE isSlacker = true
* AND postalCode IN (10466,10407,10704)
* AND gradYear BETWEEN (2010 AND 2014)
* ORDER BY lastName DESC
*/
$collection = $this->db->students;
$collection->ensureIndex(array('isSlacker'=>1, 'postalCode'=>1, 'lastName'=>1, 'gradYear'=>-1));
$conditions = array('postalCode'=>array('$in'=>array(10466,10407,10704)),
'isSlacker'=>true,
'gradYear'=>array('$gt'=>2010, '$lt'=>2014));
$results = $collection->find($conditions)->sort(array('lastName'=>1));
$collection = $this->db->grades;
//SELECT count(*) FROM grades
$total = $collection->count();
//SELECT count(*) FROM grades WHERE grade = 90
$smartyPants = $collection->find(array("grade"=>90))->count();
7. Mongo and PHP in a Nutshell
(Using GridFS)
http://us2.php.net/manual/en/class.mongogridfs.php
$m = new Mongo();
//select Mongo Database
$db = $m->selectDB("studentsystem");
//use GridFS class for handling files
$grid = $db->getGridFS();
//Optional - capture the name of the uploaded file
$name = $_FILES['Filedata']['name'];
//load file into MongoDB and get back _id
$id = $grid->storeUpload('Filedata',$name);
//set a mongodate
$date = new MongoDate();
//Use $set to add metadata to a file
$metaData = array('$set' => array("comment"=>"This looks like a MongoDB Student", "date"=>$date));
//Just setting up search criteria
$criteria = array('_id' => $id);
//Update the document with the new info
$db->grid->update($criteria, $metaData);
8. Mongo and PHP in a Nutshell
(Using GridFS)
public function remove($criteria)
{
//Get the GridFS Object
$grid = $this->db->getGridFS();
//Setup some criteria to search for file
$id = new MongoID($criteria['_id']);
//Remove file
$grid->remove(array('_id'=>$id), true);
//Get lastError array
$errorArray = $db->lastError();
if ($errorArray['ok'] == 1 ) {
$retval = true;
}else{
//Send back the error message
$retval = $errorArray['err'];
}
return $retval;
}
9. Let’s develop a simple student information capture
system with mongoDB and PHP!
12. Our Design
Design
(The Mongo Model)
Test Develop
db.students db.teachers
firstName: firstName:
lastName: lastName:
address: isCrazy:
address:
city:
state:
postalCode:
db.courses
grades:
name:
grade: isImpossible:
course: teacher:
createdDate:
modifiedDate:
comment:
schedule:
course:
sysInfo: Whiteboards aren’t this neat but they
are just as good!
username:
password:
isSlacker:
gradYear:
13. Some Wireframes
Design
(The View)
Test Develop
Select Course: - Select One - * Required
User Name: * Required Select Student: - Select One - * Required
Password: ***************** * Required
Grade:
First Name: * Required
Submit
Last Name: * Required
Address: * Required
City, State, Postal Code: City - State - Postal Code * Required
Click if this student is a slacker Imagine the code for this
Graduation Date: mm/dd/yyyy
Submit
14. Design
We’re Developing
Test Develop
public function studentUpdate()
{
$mongo_id = new MongoID($_POST['_id']);
$data = $this->cleanupData($_POST);
$this->col->update(array("_id" => $mongo_id), array('$push' => $data));
return;
}
$_POST = '4b7c29908ead0e2e1d000000';
$data = array('firstName'=>'Fitz',
'lastName'=>'Agard',
'address'=>array(
'address'=>'123 Data Lane',
'state'=>'New York',
Letʼs assume cleanupData only removes 'postalCode'=>10704
unnecessary POST elements like the _id ),
'sysInfo'=>array(
'username'=>'fhagard',
'password'=>sha1('MongoW00t')
),
'isSlacker'=>true,
'gradYear'=>2003
);
15. Design
We’re Developing
Test Develop
public function studentUpdate()
{
$mongo_id = new MongoID($_POST['_id']);
$data = $this->cleanupData($_POST);
$this->col->update(array("_id" => $mongo_id), array('$push' => $data));
return;
}
$_POST = '4b7c29908ead0e2e1d000000';
$data = array('grades'=>array(
'grade'=>'3.8',
'course'=>'4bd0dd44cc93740f3e00251c',
'createDate'=>new MongoDate()));
Donʼt forget that cleanupData only removes
unnecessary POST elements like the _id
16. Design
Test Develop
Problem: The client called and asked why we forgot
to collect “student infractions” in our design.
oops!
“oops” - used typically to express mild apology, surprise, or dismay.
17. Development back to Design
Design
(“oops” is easily fixed)
Test Develop
db.students
firstName:
lastName:
address:
address:
city:
state:
postalCode: infractions:
grades: desc:
grade: date:
course:
createdDate:
modifiedDate:
comment:
schedule:
course:
sysInfo:
username:
password:
Back to the whiteboard
(or - napkin, omnigraffle, visio, etc)
isSlacker:
gradYear:
18. Another Wireframe
Design
(The View - Again)
Test Develop
Infraction View
Search for Student Input Search
Last Name
First Name
Graduating Year
Course
Imagine the Editor Controls A ab
new code for
Format Font Size
B i u 1
2
this.
3
Textarea enter text
Date Selector __ / __ / ____
Select a date range
Submit
19. Design right back to Development
Design
(The Fix! Do you see it?)
Test Develop
public function studentUpdate()
{
$mongo_id = new MongoID($_POST['_id']);
$data = $this->cleanupData($_POST);
$this->col->update(array("_id" => $mongo_id), array('$push' => $data));
return;
}
$_POST['_id'] = '4b7c29908ead0e2e1d000000';
$data = array('infractions'=> array('desc'=>'Caught Sharding', 'date'=> new MongoDate()));
Answer: The only thing that changed was the view in the last slide.
This code is the same!
20. Design and Development In Summary
Our Classes/Methods/Views made the schema
NoSQL
NoORM
Arrays! Arrays! Arrays!
21. Design
Let’s Test
Test Develop
What does MongoDB have to do with testing?
22. Design
Let’s Test
Test Develop
Isn’t it a good idea to run unit tests often?
Where do you store the results?
23. Idea: PHPUnit to Mongo
Design
(Test Logging)
Test Develop
Test logs can
go in Mongo
Clipping from: http://www.phpunit.de/manual/current/en/logging.html#logging.json