Jump to content

Recommended Posts

::Destroying related objects doubt

 

One thing that is confusing me is regarding the lifecycle of the associated objects and the related data in the database. Suppose we have an example of object composition and in this case if I destroy de parent object then the children objects will be destroyed too.

 

Well, the confusion I'm doing is related to the semantics of the word 'destroy'. In my understanding when I say 'destroy' an object, it means I will unset it, but I will not 'delete' the related data in the database.

 

ex.: let's say we have objects House and Rooms, the relationship between them is composition, so House is responsible for creating new Rooms. If I destroy the instance of House, all instances of Rooms will be destroyed as well, but it doesn't mean I have to 'delete' them from the database, right? ... sounds like a silly question, but ...

 

thanks in advance, sohdubom

Link to comment
https://forums.phpfreaks.com/topic/169644-destroying-related-objects-doubt/
Share on other sites

Imagine a database like this:

 

CREATE TABLE `houses` (
  `house_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `price` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`house_id`)
) ENGINE=InnoDB;

INSERT INTO `houses` (`house_id`, `name`, `price`) VALUES
(1, 'My House', 5000000);

CREATE TABLE `rooms` (
  `room_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `house_id` int(10) unsigned NOT NULL,
  `name` varchar(100) NOT NULL,
  `size` int(10) unsigned NOT NULL,
  PRIMARY KEY (`room_id`),
  KEY `house_id` (`house_id`)
) ENGINE=InnoDB;

INSERT INTO `rooms` (`room_id`, `house_id`, `name`, `size`) VALUES
(1, 1, 'My Kitchen', 20),
(2, 1, 'My Bathroom', 5);

ALTER TABLE `rooms`
  ADD CONSTRAINT `rooms_ibfk_1` FOREIGN KEY (`house_id`) REFERENCES `houses` (`house_id`) ON DELETE CASCADE ON UPDATE CASCADE;

 

Each house has a composition of rooms. Without the house it doesn't make sense to talk about its rooms, so when the house ceases to exist, so does its rooms. I hope that makes sense.

Hi Daniel0,

 

I understanding your example with the cascade deletion, but this scenario happens if I call a delete (house) method. But my doubt is: when we read in the books and tutorials about Composition ... something like: 'destroying the parent, children will be destroyed too' ... are the authors talking about destroying only the instantiated objects (freeing up them from memory) or also 'deleting' them from a database ... that's my confusion

 

Also thinking in that way: when I decide that a relationship between 2 objects is a Composition, should I think about what happens with the database records or just with the objects in memory?

Try to forget the technical implementation. If you demolish a house, does its rooms persist to exist? No.

 

It kind of depends on what you're doing. The object instance is always destroyed when the script execution ends, so in that sense, neither the house nor its rooms should be removed from the database (unless you only want them to persist for the duration of the script's runtime of course). If you are actually deleting the house, the rooms should be deleted as well.

Try to forget the technical implementation. If you demolish a house, does its rooms persist to exist? No.

It kind of depends on what you're doing. The object instance is always destroyed when the script execution ends, so in that sense, neither the house nor its rooms should be removed from the database (unless you only want them to persist for the duration of the script's runtime of course). If you are actually deleting the house, the rooms should be deleted as well.

 

yes ... but sometimes it's a bit harder, like: Person and BankAccount ... in normal circunstances a BankAccount exists if there is a Person related to this account, so if I delete the Person I could think that there no sense to have a record of this Person's account, but sometimes we need a history and we can keep that account ... so as you said, it depends on what I'm doing ...

 

What I learn from this is that there is no absolute true, but we decide if some relation is a composition or aggregation or etc based on the scope/rules that are set for that particular situation  :-)

 

but of course, in the House/Rooms sample it doesn't make sense to keep its rooms after demolishing the House ... if I keep a single room it will be a House with a single Room, that's nonsense ...

I think (and correct me if I'm wrong here), sohdubom is asking if, when you unset() a class, the database records that that class created, are automatically deleted.

 

And the answer is no. Using the room / house analogy:

 

I have a house with three rooms. House is the parent, room is the child. I also have a friend nicknamed "Database". I tell Database I have a house with three rooms. They remember that (ie. Add a row to the specified table). Then one day I demolish a room (ie. Unset a room). It ceases to exist when I knock down the walls but Database doesn't know I've demolished a room unless I call them up and tell them.

 

So nothing gets deleted from the database unless I write a function that does that. PHP and MySQL (for example) don't know about each other until you tell them about each other.

 

You can, however, get PHP to automatically do some database stuff when you unset() an object. See this semi-psuedo-class:

 

<?php

class room extends house {

    public $roomID;

    function __construct($newRoomID) {
        // ... set up MySQL stuff here
        mysql_query("INSERT INTO `house` ('" . $newRoomID . "')");
        $this->roomID = $newRoomID;
    }

    function __destruct() {
         // .. set up your MySQL information here
        mysql_query("DELETE FROM `house` WHERE room = '" . $this->roomID . "'");
    }

    // .. More functions here (eg. furnish(), lightsOn() etc.)

}

 

So when you create a new room, you call $bathroom = new room("bathroom"); and a new room is created in the database. When you unset($bathroom); , your room is destroyed.

 

So in short, no, if you unset a room, you have to manually delete it from the database. You can sort of automate this by creating a class function called __destruct(), which is a function called by PHP when an object is destroyed, so you can do cleanup work and write stuff to disk etc.

 

Hope this helps?

Well, obviously you have to manually delete it from the database somehow. There is no inherent relationship between PHP's object model and database entries. You'll have to establish that relationship yourself.

 

However, do note that using the code you did it is impossible to store anything permanently in the database; each object is destructed during garbage collection at the end of the script execution.

1) You can't unset() a class (objects people, objects)

 

2) It makes no sense to delete the data in storage when the object is destroyed. Put differently, there's no point to persistence if you don't let it persist.

 

@OP: Unfortunately there is no one easy answer to your question: you have entered the realm of OO persistence and ORM. Here are most commonly used "solutions" for you to explore (simplified, in order of popularity, and by chance -- or perhaps not --, also in the reverse order of my recommendation):

 

Table Data Gateway

Object that handles persistence of data to a table.

 

Row Data Gateway

Objects map 1:1 to entries in the database. These objects "just" map data to the DB, nothing else.The logic for persisting them is usually found in a Table Data Gateway. This doesn't provide the best solution for mapping to the DB, as 1) it closely couples your object model to your DB, and 2) it usually doesn't support building or saving resultsets composed of entries from multiple tables.

 

Active Record

Very much like Row Data Gateway, only the business logic is also contained in the object. Also close mapping to the DB schema.

 

Data Access Object (DAO)

Object that does the mapping. Like Data Mapper it encapsulates the mapping logic, but clients are often the Domain Objects themselves, as the object does not return domain objects, but Transfer Objects (records, simply put).

 

Data Mapper

The only common solution that provides decoupling between DB schema and domain model. This allows you to map those "real" objects to the database. A Data Mapper is an object solely responsible for mapping, storing and retrieving objects from and to the DB. It is the boundrary, an intermediator, between your model and the DB. While it gives you by far the most flexibility and lets your DB and domain model evolve separately (to a degree), it is also the hardest/the most work to write because  of it. The mapping can differ in so many different ways, it almost impossible to write something uniform that is decoupled from the database to a decent degree. Put differently, while it is possible to write "common mappings", because the domain model and db can evolve separately, you will end up writing a lot of custom mapping for different parts of domain model.

 

Perhaps some quick and dirty examples:

 

/**
* Table Data Gateway: domain logic in client (controller-whatever)
*/
$record = $userTable->find('username', $post['username']);

if($record['password'] == md5($post['password']))
{
   $record['logintime'] = time();
   //Continue doing interesting stuff
}

$userTable->update($record);
/**
*/

/**
* Row Data Gateway named "User": domain logic in client
* 
* often used in combo with Table Data Gateway which then fetches 
* Row Data Gateway objects instead of records -- or with Data Access Object
*/ 
$userFinder = new UserFinder();

$userRow = $userFinder->findByUserName($post['username']);

if($userRow->getPassword() == md5($post['password']))
{
   $userRow->setLoginTime(time());
   //Continue doing interesting stuff
}

$userRow->save();
/**
*/

/**
* Data Access Object: client is Domain Object
* 
* (looks indentical to Active Record, but internally it delegates to DAO
*/
$user = $userDao->findByUsername($post['username']);

if($user->tryLogin($post['password'])) //Password hashing and login time setting is done internally
{
    //Continue doing interesting stuff
}

$user->save();


/**
* Active Record named "User": domain logic and mapping 
* logic in object (data mapping possibly/probably delegated)
* 
* Also often used in combo with Table Data Gateway or Data Access Object
*/
$userFinder = new UserFinder();

$user = $userFinder->findByUsername($post['username']);

if($user->tryLogin($post['password'])) //Password hashing and login time setting is done internally
{
    //Continue doing interesting stuff
}

$user->save();

/*
* Data Mapper: domain object named "User" 
* 
* So many scenarios are possible here, a simple one:
*/
$mapper = new UserMapper();

$user = $mapper->findByUsername($post['username']);

if($user->tryLogin($post['password']))
{
    //Continue doing interesting stuff
}

$mapper->save($user);
/**
*/

/*
* Data Mapper: domain object named "User" 
* 
* So many scenarios are possible here, another one using 
* Unit of Work Controller (keeps track of what objects where modified):
*/
$mapper = new UserMapper();

$user = $mapper->findByUsername($post['username']);

if($user->tryLogin($post['password']))
{
    //Continue doing interesting stuff
}

$mapper->saveAll(); //Persist all objects created/fetched trhough this mapper
/**
*/

 

This is of course a very simple example, the real value of Data Mapper over the others only really become obvious with a more complex example, but that's more than I have time for.

Sorry for the format error, edit time limit had passed and forgot about DAO.. Personally I think a DAO is already so close to a Data Mapper, that you might as well go that little step further. It is also worth noting that a Transfer Object is little more than an object holding a particular state. While the most common approach is is having the business/domain object populate itself from the TO, a better solution IMO is to use a separate entity to do so, e.g. a factory. Between all the implementation variations, the difference between a DAO and a Data Mapper can become marginal.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.