This practical looks at simple implementations of two ORM patterns, Active Record and Data Mapper. It's the same OO MVC example we looked at earlier but the model layer uses ORM.
- Open your existing codespace (you shouldn't create a new one) https://github.com/codespaces.
- In the terminal enter
git clone https://github.com/CHT2520-web-prog/object-relational-mapping
This will copy the contents of this repository into your codespace.
- Find the file Database/DbConnect.php and make changes to the connection settings so they match your database.
- Start Apache (
apache2ctl start
) - Test the website. You should be able to view and add new films, the edit and delete functionality won't work.
Now move onto Completing the practical work
- Download and unzip this repository.
- Move it into the htdocs folder in XAMPP.
- Find the file Database/DbConnect.php and make changes to the connection settings so they match your database.
- Test the website. You should be able to view and add new films, the edit and delete functionality won't work.
Now move onto Completing the practical work
The app uses an Active Record pattern that makes domain classes (in this example Film) responsible for working with the database.
- Open Models/ActiveRecord/Film.php Note the following:-
- The first few methods look very similar to the examples we looked at last week (
__construct()
,getAge()
). - The next block of methods all perform database operation (
all()
,save()
,find()
,delete()
).- The first two (
save()
anddelete()
) execute database operations using the object's properties. - The next two are static as we want them to be called without having to instantiate a Film object (
all()
,find()
).
- The first two (
- The final method maps a row from the database to a Film object (
makeFilmObject()
). Each field from the database becomes a property of the object.
Open Controllers/FilmController.php to see how the controller uses the Film class e.g.
function show()
{
//Get the id from the query string e.g. for show.php?id=2, $_GET['id'] has a value of 2
$id = $_GET['id'];
//Get the film from the model
$film = Film::find($id);
//load the view
$this->loadView("show.view", ["film" => $film]);
}
Now open show.view.php. See how we can use the Film class methods and properties e.g.
echo "<h1>{$film->title}</h1>";
echo "<p>Year:{$film->year} ({$film->getAge()} years old)</p>";
- Modify show.view.php so that it also displays the duration of the film.
- Can you get the edit, update and delete functions to work.
- You don't need to make any changes to Film.php, and the edit.view.php has already been created. You only need to make changes to the
FilmController
so that it uses theFilm
model to execute actions.- For the edit you will need to get the selected film's id value from the query string, call the static
find()
method of the Film class, and then load edit.view.php. This is going to be very similar to the FilmController'sshow()
method. - For update you will need to get the selected film's id value from the form, call the static
find()
method of the Film class. You then need set the properties of this object using values from the form e.g.$film->title = $_POST['title'];
and finally call thesave()
method on this object.
- For the edit you will need to get the selected film's id value from the query string, call the static
An alternative to Active Record is the Data Mapper pattern. The mapper class is responsible for working with the database - insert, delete etc. The advantage is that Domain objects (e.g. Film) don't need any knowledge of the database.
-
Open Models/DataMapper/Film.php
-
Note that it is much simpler than the active record example, there isn't any code in here for working with a database.
-
Now open models/DataMapper/FilmMapper.php. Note that it has methods for interacting with the database e.g.
persist()
,findAll()
,findById()
etc. -
Also note that it has the exact same
makeFilmObject()
method we saw previously -
Rename your FilmController.php file to FilmController_ActiveRecord.php so it doesn't get used.
-
Rename the FilmController_DataMapper.php to FilmController.php so it does get used.
You should find that you can still view and add films. However, now the app is using the Data Mapper pattern. Have a look in FilmController and see how this is working e.g.
function store()
{
//get the data from the form
$title = $_POST['title'];
$year = $_POST['year'];
$duration = $_POST['duration'];
//Create a new Film object
$film = new Film($title, $year, $duration);
//Ask the mapper to save the filmin the database
$this->filmMapper->persist($film);
//Redirect the user to the home page
header('Location: ./index.php');
}
or
function show()
{
//Get the id from the query string e.g. for index.php?action=show&id=2, $_GET['id'] has a value of 2
$id = $_GET['id'];
//Get the film from the model
$film = $this->filmMapper->findById($id);
$this->loadView("show.view", ["film" => $film]);
}
Note the difference between the Active Record pattern and Data Mapper.
Can you get the edit, update and delete functions to work.
You don't need to make any changes to Film.php, or FilmMapper.php. You only need to make changes to FilmController
so that it uses the FilmMapper
to execute database actions.