Re: Listing objects
- From: Lüpher Cypher <lupher.cypher@xxxxxxxxxxx>
- Date: Fri, 30 Dec 2005 17:51:53 GMT
Dikkie Dik wrote:
Ok, let me try a clearer version :)
Object | +--- App | ::$page | +--- Control | ::$parent | ::$data | ::$object | +--- Data | ::$id | +--- Template | ::owner | ::control | +--- Page
This is the inheritance hiearchy, I assume that you also have an association hierachy. App will be the root, and then...
I would think that an App creates a page and creates a data channel, or asks a Control to do that. Within my perception, a page has a template and date (gets it from App). So App knows Control and Page, and also knows that Control has Data. All these objects do not have to know App as far as I can see.
Well, App only creates and knows Page (Template).
Template creates Controller, which creates Data. So, Template knows Control, and Control knows Data. However, depending on the Data, Control may instantiate another Template (at which point the process repeats). The original Template has access to Control's Template.
Right now it's like this:
$app = new App(
$page = new Page(
$ctl = new Control(
$data = new Data()
if (<another template>) {
$temp = new TemplateSubclass(
$ctl = new Control(
...
)
)
}
)
)
)
$app->render(
$page->render(
if ($ctl->temp exists) {
$out = $ctl->temp->render(
if ($ctl->temp exists) {
$out = $ctl->temp->render(
...
)
}
return $out.<custom output>;
)
}
return $out.<custom output>;
)
echo <results>;
)Some of these do call App's methods, though, for instance to get a global application parameter..
In the main script I have
$app = new App();
In constructors I have
function App() { ... $null = null; $this->page = new Page($null); }
function Page(&$owner) { parent::Template(&$owner); }
function Template(&$owner) { $this->owner = &$owner; ... $this->control = new Control(&$this); }
function Control(&$parent) { $this->parent = &$parent; ... $this->data = new Data(); ... if (already_exists($this->data->id)) { echo "Duplicate ID"; return; }
If the problem is here, let's keep it here. I have written my own DatabaseID class with its own IsEqualTo method (and an IsNew method). For the very simple reason: A data-object might be constructed with database data (known ID) or be a new record that was not yet stored in the database. With this DatabaseID class, I can give EVERY data-object an ID. If the DatabaseID instance is not contructed with a database ID, the IsEqualTo method will always return FALSE. Two new records are per definition different in my application. Only if both compared objects were constructed with an ID from the database, an actual by-value comparison if done.
Well, all I need is just checking whether an ID exists. In this case, Data loads an XML file and sets its ID value to a string. This ID should be unique. So, after Controller instantiates Data, it should check that the loaded ID wasn't already assigned in some other Controller. I figure the easiest way is to iterate an array of objects, see if an object has Control as its class, and compare the IDs in Datas. :)
... if ($some_condition) { $object = new $CustomSubclassOfTemplate($this->parent); } }
What is template doing in Control? If Control is responsible for both templates and data, it is a clear signal that this class wants to be split into two classes.
Well, Template is presentation class so, it's all about *how* the data should be displayed and has no other functionality. It knows its Control so that it can present dynamic data. Control relies on Data to choose *what* should be displayed.
Suppose Data consists of 3 classes. Control chooses one of them and instantiates it. Template simply outputs whatever it is, inserting the output of the class Control chose along way. This way Data is only about data, Control is about what should be output, and Template is only about how it should be output, no matter what the actual content is. I figure instantiating the chosen class in Template would mean that Template is also about data, and instantiating it in Data would mean that data is dynamic.. :)
function Data() { ... $this->id = $some_retrieved_id; }
Basically, the interesting part is:
When Template is instantiated (initially Page in App constructor), it instantiates Control, which, in turn, instantiates Data. At this point, $data->id will be set.
At the end of Control's constructor, if some condition is satisfied, a subclass of Template will be instantiated and stored in Control's $object.
Thus, we can have:
$app->$page->$control->$object->$control->$object->...->$control->null($object)
Is that bad? Frankly I don't care how deep a structure goes, as long as it makes sense and is finite.
Well, it's actually not all that bad, since there is no need to write such long references :) It is finite, otherwise the page will never load :)
We can also pretty much go bottom-up through Template objects via $owner and we can get the Template object from Control via $parent.
Now, in the middle of Control's constructor there is a check that $data-id does not already exist.
One way would be to go through Templates:
$temp = $this->parent; while (isset($temp)) { if ($this->data->id == $temp->control->data->id) { echo "error"; return; } }
Apparently this does not work, even though owner is passed by reference.
Found where the mistake is :) Apparently $a = new A() means that $a is a copy of the actually instantiated class A() ;-o All I had to do was to change all instantiations to form $a = &new A();
Another way would be to have a global array and save all objects there by reference. This is actually more appealing to me, since then I could access any object at any time from anywhere.
Yikes!
One of the main features of object-oriented programming is that you can nicely shield off what others should not access. The contents of a page should only be accessible by asking the $page object, which is only accessible by asking $app. Why? Because it allows $page to decide how and when to fill in the data, and to throw an exception if no data was passed. That is $page's reponsibility, not $app's, and not even yours. If you want to peek inside of $page's internals, write a temporary method or echo statement, during development only.
Not even your responsibility? No. You can program it, write a unit test for it, and when it is finished, it can live on its own. It is sad, but the only thing left for you to do is typing the URL...
Well, echo's are what I usually use to debug things :)
In this case, however, I could either traverse a tree, meaning that I would start in a leaf, and would have to traverse all nodes and leaves, bottom-up, check if a node/leaf is of appropriate class, and then check whether ID is the same or not.
With array, I can simply use foreach:
foreach($objects as $name=>$obj) {
if (!is_a($obj,"Control")) { continue; }
if ($name == $this->getName()) { continue; }
if ($this->getId() == $obj->getId()) { echo "error"; return; }
}Where each object has a unique name :) That's what I actually use, now that the references work in the global array.
It is pretty much a shortcut to doing some things :)
luph .
- References:
- Listing objects
- From: Lüpher Cypher
- Re: Listing objects
- From: Dikkie Dik
- Re: Listing objects
- From: Lüpher Cypher
- Re: Listing objects
- From: Dikkie Dik
- Listing objects
- Prev by Date: Re: Cannot get this one correct and working, though simple!
- Next by Date: Re: Newbie questions for the PHP5 experts in this ng
- Previous by thread: Re: Listing objects
- Next by thread: Re: Listing objects
- Index(es):