Simple Question...

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Simple Question...

Post by Ambush Commander »

Since I'm stuck, I'm probably overengineering. Therefore, I would like to ask you a simple question.

You have a novel. Inside the novel are chapters.

Do the chapters know about the novel? (don't take it literally)

What about the chapter numbers (i.e. Chapter 2, Prologue, etc.)
Charles256
DevNet Resident
Posts: 1375
Joined: Fri Sep 16, 2005 9:06 pm

Post by Charles256 »

hum....being the non expert I am I think i'd let the chapters know about the novel though I'm too sure I'd let the novel know about the chapter numbers.....
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Seems like a very simple solution to me

You have your novel table, which includes novel_name and novel_id (auto_increment)
You have your chapter table, which includes chapter_id (auto_incremented) chapter_number, novel_id, chapter name
You have your page table, which includes page_id (auto_incremented), page_number, chapter_id
You have your content table, which includes content_id (auto_incremented), page_id, content_text

So yes, each step deep holds its parent_id
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

I would expand on what jcart said, by recommending not only does a page know its chapter, but which novel. That way you have a multi-part where clause to pull a page from a book, instead of multiple queries
User avatar
dbevfat
Forum Contributor
Posts: 126
Joined: Tue Jun 28, 2005 2:47 pm
Location: Ljubljana, Slovenia

Post by dbevfat »

Jcart wrote:So yes, each step deep holds its parent_id
I'm not sure if he's asking about a database design, but ...

If relational database structure is in question, I guess the answer is yes, because you'd want to know what to write in the parent column, for every single child. But in OO design (without db to cover it's back) this is not necessary.

It all depends - do the child classes need to know about their parents? The parent could just be a container to them, and they don't necessarily have to know if and who holds them.

Regards
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

I would expand on what jcart said, by recommending not only does a page know its chapter, but which novel. That way you have a multi-part where clause to pull a page from a book, instead of multiple queries
There isn't a point, since they are all linked one way or another

Lets say you wanted to pull up: page 4 of Chapter 3 of The Book

Code: Select all

$result = $db->query('
   SELECT * FROM `novels`
   INNER JOIN `chapters` USING (`novel_id`)
   INNER JOIN `pages` USING (`chapter_id`)
   INNER JOIN `content` USING (`page_id`)
   WHERE `novels`.`novel_name` = \'The Book\' and 
         `chapters`.`chapter_number` = \'3\' and
         `pages`.`page_number` = \'4\'
   ');
I'm not sure if he's asking about a database design
Good point. Lets find out. Are you asking about database design?
User avatar
pickle
Briney Mod
Posts: 6445
Joined: Mon Jan 19, 2004 6:11 pm
Location: 53.01N x 112.48W
Contact:

Post by pickle »

I'm gonna post contrary to most people ( :twisted: :twisted: :twisted: )

I would say the chapter would be a member of the novel, but wouldn't know what novel it was part of. It would be up to the novel to list what chapters it had.

As for chapter numbers I'm not too sure - that might be a good reason to go with the method everyone else is suggesting.
Real programmers don't comment their code. If it was hard to write, it should be hard to understand.
User avatar
patrikG
DevNet Master
Posts: 4235
Joined: Thu Aug 15, 2002 5:53 am
Location: Sussex, UK

Post by patrikG »

Chapters never know about the whole picture. Class methods shouldn't make use of globals or superglobals. Keep things local and let things work perfectly there. Only the class knows what it's been designed to do, not its methods, and only the application knows which classes to use when.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Ah, DB stuff will come later. Let's talk about the domain model.
hum....being the non expert I am I think i'd let the chapters know about the novel though I'm too sure I'd let the novel know about the chapter numbers.....
Being a nonexpert means you pick the most intuitive solution. Chapters know about the novel.
It all depends - do the child classes need to know about their parents? The parent could just be a container to them, and they don't necessarily have to know if and who holds them.
Important question.
I would say the chapter would be a member of the novel, but wouldn't know what novel it was part of. It would be up to the novel to list what chapters it had.

As for chapter numbers I'm not too sure - that might be a good reason to go with the method everyone else is suggesting.
Hit the head on the nail.

--

Physically speaking, the Novel to Chapter one is a simple one of composition. A chapter isn't in multiple novels, and the novel literally contains on the chapters. This manifests as a collection in the novel. It's a one to many association.

When we make the chapter know about the novel, we add a back pointer and make the association bidirectional. Chapters now know about and can manipulate their novel. Var_dump'ing what should be a noun is now a bit awkward (recursion... gasp)

--

So the dilemma is this: I'd rather not let the chapter know about the novel, as pickle and PatrickG state and dbevfat wonders.

But pickle picks up on an important point: it may not be possible to keep this sort of setup when it comes to chapter numbers. If you have a rapidly changing novel, with chapters changing and being added, you probably don't want to explicitly set the chapter number. The Prologue doesn't have a chapter number, and the second element has a chapter number of one, and if we keep on going, a chapter has to know about all other chapters (or, at least, the ones before it) in order to know its chapter number.

Chapter number is obviously(?) a chapter property. No sense in putting it in the Novel.

So, if we keep out the back pointer, we get...

1. No way for a call to getNumber() to figure itself out

which leads to

2. Some way for the mapper to tell the chapter what number it is.

If we put in the back pointer, we get...

1. Chapters talking to the novel in order to find out what chapter number it is.

Which seems a lot more natural, but has var'dumping problems.

Since there was a bit of discussion about the SQL, I make a few notes:

*I'm not paginating it.
*IDs should never be meaningful, right? So does that mean that I need a chapter_order to tell us how to sort the chapters?
*Supposedly, joins get slow if you do too many of them

--

I have this feeling that the discussion is reaching critical mass, with too many things to talk about.
User avatar
dbevfat
Forum Contributor
Posts: 126
Joined: Tue Jun 28, 2005 2:47 pm
Location: Ljubljana, Slovenia

Post by dbevfat »

Very nice analysis Ambush Commander :)

A good thought about chapter_order, it solves two problems at the same time:
- well ... chapter ordering, easy reordering later on,
- child doesn't have to know about the parent.

I would actually consider the child's awareness of the parent as a problem if it would only be used to retrieve the chapter number. After all, a chapter's number is it's own property, isn't it?

But! As I mentioned before - a mapper that would write the chapter domain model would have to get `novel_id` from it, right? Is it a mere scalar property of the chapter or does it hold a reference to a novel DM - both bring us back to the child's knowing about the parent in a way ...
:)

Best regards
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Not necessarily. A foreign key in the database does not necessarily entail a pointer from the object with the foreign key to the object. You could very well exclude the foreign key completely from the object (although it's not recommended since it complicates mapping). Foreign keys are the ONLY way to atomically handle compositional hierarchies. I have no doubt in my mind that the chapter table should have a novel_id. But it will also have a unique chapter_id totally independent of everything else.
I would actually consider the child's awareness of the parent as a problem if it would only be used to retrieve the chapter number. After all, a chapter's number is it's own property, isn't it?
Making things easier makes things more complex.

Consider FanFiction.Net: it blatantly disregards prologues and number 'em anyway. Quick and dirty fix. It always irked me, so in the first (extremely poorly written) iterations of my software, I offered ways to quickly generate labels on the fly. In the end, there were multiple options. Some were offsets: don't start numbering until a certain chapter. Others were special flags: if a chapter has a special flag, skip over it and continue numbering. And, of course, there was fine-grained, define all chapter labels yourself.

I now face the challenge of translating this into an OO system that doesn't have chapters that know about the novel.

I suppose it would be helpful to describe the hacks I started writing to get this to work. On my compositional hierarchies, I'd have this propagate() functions. Essentially, they would be called by the Mapper after everything was instatiated, and the novel would package up all the information the chapters needed to know about and sent it to them. Then, there was no need to call the Novel.

The problem, then, is editing the Novel/Chapter properties and then re-propagating them to everyone. To do anything useful with the Chapter object, you'll need the Novel object close at hand. This may not necessarily be a bad thing, but after adding about ten extra methods to make this work (and seeing the need for more as additional requirements arose), I balked, and stopped working on the program.
GRemm
Forum Newbie
Posts: 17
Joined: Fri Jul 08, 2005 3:37 pm
Location: California
Contact:

My approach.

Post by GRemm »

Or you could have a generic object for the content sections of a novel

Then extend that generic object for chapters / prologues / epilogues / bibliography etc giving them the ability to introduce specific private member variables they would need.

The novel itslef is simply a collection of element objects. Depending on the type of object the Novel itslef could handle the ordering of sections based on the sections extended type.

In this situation the Novel is aware of its collections, the types of data in each collection and the output ordering of the types. The novel itself doesn't even need to know the order or the objects in each collection ( assume each collection knows how to sort its objects and they are read into the Novel object for manipulation in the order they are stored. ) The objects themselves don't even need to know their chapter or ordering info. The collection that contains them handles this for them when they are added to the collection object. IE $chapterCollection->insertChapter(+chapter XML chunk / file+) would simply append an iterator based array / queue with a new chunk of chapter data. If it ends up in position 14 then it is chapter 14. If output was handled by a pagination class (decorator?) that split chapters into screen / print sized chunks then there might need to be some coupling either directly or through an intermediate object that communicates this to the page numberer / TOC etc.

The chapters themselves could be contained in an iterator object of their own and then be given as a collection to the Novel for composition purposes.

IE the prologue type is always first. Even if it is 10980182th in the collection of elements. Then the novel would look for the chapter collection and begin ordering them as nescessary. This would also allow chapter X to be on page Y and for a table of contents to know this on the fly.. saving you from creating a TOC object or even better allowing your TOC object to construct itself at initilization to account for the ordering and page numbering etc.

You could even 1->1 map a second collection ( or many collections to eachother ) to handle page specific footnotes / endnotes / bibliographies / sidebars / images + captions on pages etc.

As a related note http://alistapart.com/articles/boom has a book microformat in xhtml that uses css2/3 to handle outputting a book in printable format / export xhtml format to pdf for print. I disagree with their approach to the microformat - or rather wish they had shown some info on how to get from an xml novel format to the xhtml since it seems inneficient to use xhtml to mark up a novel from the start.

I hope I haven't been too abstract I am posting from work and can't come up with any concept code for you. If this has been helpful then let me know and I will throw something together that reads xml into a group of collection objects for you and a container / controller object to handle how they get turned from data into a novel.

GRemm
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Or you could have a generic object for the content sections of a novel

Then extend that generic object for chapters / prologues / epilogues / bibliography etc giving them the ability to introduce specific private member variables they would need.
Okay, I get the general jist of what you are saying, but I don't understand some things, which means that it may be a little too complicated. Simplify, simplify. Remember, we're not going for a perfect solution. Deal with our issues first.

You say the Novel is the collection, then you say the novel knows about the collection, and then you say it is it's own object (the iterator class). Which is it? You also propose that the novel does all the ordering. Or maybe the collection class.

What you're saying is that a novel contains lots of different types of things. Sometimes, these things contains more little things. 8O :P

And you also say that the collection should know about the ordering, not the pieces of the collection.
If it ends up in position 14 then it is chapter 14.
But how does the chapter know that it's been put into position 14 and thus it is chapter 14? Does it... ::gasp:: not need to know?

When you actually start talking about converting this into... say... HTML, we would always be talking to the novels to get information about the chapters. It seems like a novel is too closely tied to its chapters to be seperated: no free-agent chapters/content-sections floating around. They're probably value objects anyhow.

Very helpful, but too complex. You suggest that you just don't interact with chapters. You interact with novels. And the parent is responsible for ordering, and all ordering dependant attributes (whether they be chapter labels or something else).

A List Apart is a great website, I read that article when it came out. Pity they don't publish more often, but quality is good. Despite my main problem object being a novel, I actually don't plan on printing this. I'm trying to go for fiction web publishing, and most conventional styles that apply to paper and ink should apply to make things easier for users. Granted, not everything, but most. I don't see much use for CSS3... yet...
GRemm
Forum Newbie
Posts: 17
Joined: Fri Jul 08, 2005 3:37 pm
Location: California
Contact:

Post by GRemm »

I will try and explain this without resorting to UML or diagrams too much.

From the top of the design down. (Backwards approach I think but easier to elaborate on)

You have a novel object. This object contains Novel specific data - title / author / date published / genre / ISBN / etc.
This object also is composed of a set of smaller subclasses
The subclasses are for example ..

You also have a novelObject class which would likely be a very simple class containing a few universal pieces of data. - These are then extended to account for specific functionality.
These are then stored into the collection objects which could either implement a collection interface ala Java or extend a more general collection class.

Some specifc collections might need other pieces of data - the chapter collection would need to know when each chapter started and where each chapter stopped as well as the next and previous chapters.

By extending a collection class or implementing a well written interface the logic for the next / prev / first / last / jump to logic could be internalized and leave you more freedom to worry about the novelObjects data and structures.

$prologueCollection implements Collection / Iterator and collects $prologueObject(s) -> which extends novelObject
$chapterCollection implements Collection / Iterator and collects $chapterObject(s) -> which extends novelObject
$epilogueCollection implements Collection / Iterator and collects $epilogueObject(s) -> which extends novelObject
I also imagine some sort of name->value paired collection or collection of small objects to handle the Table Of Contents.

The Collection interface and the Iterator determine the order of each type of section. The collection for an object at the top of the stack would be assumed to be the first object to appear of it's type in the Novel output.

On the way to rendering your output you could pass each type of object through it's own specific Decorator helper class. This allows the main class to handle the data and structures and the decorator to deal with things like linkifying text headers and inserting the page numbers into the output. During this process the decorator could access a member variable(s) for each chapterObject processed thus storing it's starting and stopping page numbers ( This assumes your decorator takes the page and determines if it needs to be split into smaller portions for display ) as well as displaying the current page number for the chunk of data being rendered. Not all of the novelObjects would need to store the page number data of course and also not all of the Page Objects need to be passed through a decorator. This would easily allow you to begin page numbering at the beginning of chapter one and not number the prologue. Or to get fancy you could number prologue / epilogue novelObjects through a different decorator that uses roman numerals or alphabetic page ordering. (just ideas here)

Now the hierarchy is such that your novel contains a group of collection objects which have collected the various novelObjects they contain. All the main novel class has to do is determine the rendering order for sections and iterate through the collections as it sees fit passing certain data through specific decorators and displaying the output. This seems particularly vague as an implementation but think of the benefits.

You are leaving the page chunking for chapters to the decorator. This means if you decide to change the 'size' of a page from 25 lines to 10 lines that the page numbering and table of contents generation is handled by the decorator at runtime. A chapter that was once 2 pages long now is 6 pages long. The collection for the chapterObjects is told where the chapter starts and stops by the decorator and this information is accessible by the TOC class and nobody has to worry about it.

This also allows you to keep data specific to all novelObject types in their own super class while allowing certain extended novelObjects to keep their own private data. It also allows each collectionObject to determine how it orders / stores / manages it's members.

Also if you decide for one Novel that you need footnotes you can write a footNotes class that extended your novelObject class. This would be a million zillion times easier to work with than trying to make a huge super class for all types of novel data. If you wanted to you could also pass in a reference to specific render classes to handle the output of each collection as it gets handed to the decorator for that object type.

Being an XML man myself I would store the Novel data as an XML doc and run the xml through a parser yanking out the data required to instantiate each extended novelObject subclass and then hand each new object off to its respective collection. At the end pass the collections into the Novel object and allow it to handle the data as it sees fit for rendering. (? XML / XSLT / CSS ?)

I know this is a very complicated solution to what you were hoping was a simple problem but it is in my opinion the most extensible and forward thinking approach to a complex composited data type.

When I write code I try and think of the smallest data chunk I can work with that isn't subjective at all. A page is subjective (depends on the number of lines, width of display, font etc. ) while a Chapter or Epilogue section is not. It is simply a store for the relevent data.
Then, if you have any situation where you might have an indeterminate number of these chunks you should hand them off to a collection object that implements an interface most suited to its data. This might be an array / hash table / iterator / linked list / etc depening on what it is.
If there is a semantic separation between the raw data and it's presentation then a decorator is perfect. For example the href and target attributes for an html link are raw data. The brackets, quotes, css classing, etc are a decorated layer over that raw information.
As a final step the last class I write is the contol class (In this case the Novel class) which simply accepts the data and objects it gets instantiated with and deals with the logic of putting it together so it isn't just a pile of parts. In the theoretical case above the logic flow would be..

Read xml file -> hand each node to xml parser and determine it's type. Instantiate the appropriate extended novelObject subclass with the required data and then pass it through its decorator and then store it and it's meta data in its particular collection class. The meta data would include page numbering, linkifying text, whatever you need.

When the data is loaded and collected the novel class would then look at the table of contents object and read the meta data from each collection - printing the start page and chapter title for each entry in the collection for example - then it would point each collection back to it's beginning point.
Then the Novel Class would look in its first collection for the first prologue object. It would render the output and iterate to the next prologue object. When the collection was empty the novel would then go the Chapter collection and do the same thing for each chapter - at this point you could make things complicated and check for references to footnote objects or anything else you wanted on a per chapter basis - when the Chapter collection was finished iterating the Novel Class would move to the next collection and handle that one as nescessary.

With this setup you could create a paged / indexed / referenced novel for web output without the novel knowing anything more than the mechanisms for handling the data types. The data types don't need to know about each other or even that other data chunks exist. The collections don't care about the number of objects they contain. They only care that they can access them in order and know when they are at the beginning / at the end / that data exists at a particular index.

It also would allow you to store much less pure data. Using the previous link example. As raw data containing the markup a link is far larger than the sum of its parts. Take the following as an example. As a single piece of data

Code: Select all

string = '<a href="http://www.some.domain.ext/path/info/page.html" name="name" class="class" id="id" target="target">text</a>'
= 117 chars
versus :

Code: Select all

$urlData = array('http://www.some.domain.ext/path/info/page.html', 'name', 'class', 'id', 'target');
= 98 chars

While this doesn't seem like a lot of storage saving you will see a difference. 1000 of the first type would occupy 14k - the second type would occupy 12k. If you can keep your decorator class for links under 2k in this situation you just saved yourself a small amount of bandwidth bill.
If you do this for page rendering and allow the decorator to generate the tags and quotes and styling on your data for every type of data you will display.. you just saved youself a lot of bandwidth and you make it easier to insert new information into existing data types.
For example if you find you need an attribute for your links that you forgot all you would have to do is alter the extended novelObject that handles that data to include it in it's structure then add a line or two to your decorator and voilia - all your images have alt tags across the board in your output.

This post is distracting me from my work and seems to be straying from a specific idea into a discussion of object composition and application design so I will stop here.

Let me know if I am at all helpful or if I am just being a windbag.
GRemm

** To address specific issues for you **
But how does the chapter know that it's been put into position 14 and thus it is chapter 14? Does it... ::gasp:: not need to know?
This is an implementation detail. A few options - not all for sure but a few - would be to insert the instances of the chapterObject into their collection in order. The first chapter added to the collection would be the first chapter in the rendered output for the chapters of your novel.
A second option is to pass the chapter number to the collection either as the array key value (in the case of a hash table of chapters) the index position (for a basic array or stack/queue) or to use a list type of structure for the collection which allows insertion of data into specific nodes. The different extended novelObjects may very well be suited to a variety of collection implementations. The key to any of these collections is that no matter the data structure you use to store the info / meta-info for the objects they contain they ALL implement a consistent iterator for traversing the collection.

My preference since a novel is such a linear format would be to read the chapter data into the objects in the order they would appear in the novel and implement the collection as a queue where each new chapter gets added to the bottom of the pile. Then pop them off the top of the queue (or rather iterate from the top down - pop implies removal) as each chapter object gets decorated and rendered.
Very helpful, but too complex. You suggest that you just don't interact with chapters. You interact with novels. And the parent is responsible for ordering, and all ordering dependant attributes (whether they be chapter labels or something else).
An easy analogy to use for determining which object you interact with is to equate it to real life. You pick up a Novel to read it. You don't pull a specific page or chapter off of your bookshelf. You may then open the novel and jump to a chapter once you have the novel open. The world outside the novel doesn't know the number of chapters until the novel is opened and you look at the table of contents.
With the approach above the table of contents would be a storage object of some sort that got populated with the information it needed as the decorator classes for each content chunk processed it's information - all of which happens during the construction of collection objects. (I am assuming we are storing the 'pre-decorated' data. You could also do this at render time by passing undecorated info from the collection through the decorator and out to the rendering logic. This might be a better approach even if you planned on supporting a variety of renders (handheld device pages vs the web vs pdf output for example)
When you actually start talking about converting this into... say... HTML, we would always be talking to the novels to get information about the chapters. It seems like a novel is too closely tied to its chapters to be seperated: no free-agent chapters/content-sections floating around. They're probably value objects anyhow.
If you have a subclass of the generic novelObject for a type of content that would be considered free agent and accounted for this in the control class (Novel) you could easily have content between chapters with no page numbers for example. Is this is what you mean by 'floating around'?

This post is getting too long. In summary I feel that a novel is a collection of other collections where each sub-collection represents a different type of data related to the novel. The Novel class represents this data as a book. Another class could use the same data collections and represent the information in a different format if you wanted to handle a different format. Even better - multi cultural formatting. You could have a western novel format that reads front to back left to right and another Novel class that could render and manage the collections in such a way that the same exact novel could be read back to front left to right.
foobar
Forum Regular
Posts: 613
Joined: Wed Sep 28, 2005 10:08 am

Post by foobar »

^Wow, someone has their IT consultant hat on today! :)
Post Reply