Posted: Fri Oct 05, 2007 12:09 pm
Alright... well that's good. I look forward to your critique. 
A community of PHP developers offering assistance, advice, discussion, and friendship.
http://forums.devnetwork.net/
Code: Select all
$cal = qCal::create();
// do stuff with calendar .. snip ..
$renderer = new qCal_Renderer_icalendar;
$renderer->render($cal)Code: Select all
$cal = qCal::create();
// since it hasn't been told any different, it just renders w/default renderer (to icalendar format)
$cal->render();Code: Select all
$cal = qCal::create();
$cal->setRenderer(new qCal_Renderer_hCal);
$cal->render();Code: Select all
$cal = qCal::create();
$cal->render(new qCal_Renderer_hCal);Code: Select all
$cal = qCal::create();
$cal->render(new qCal_Renderer_hCal);I would probably stick to this method, simply because it would be easier to test than having to test two seperate methods. They essentially are doing the exact same thing, but this does it in fewer steps, with a simpler interface to the object.The Ninja Space Goat wrote:Any advantage of setRenderer over simply:
Thanks Everah!Code: Select all
$cal = qCal::create(); $cal->render(new qCal_Renderer_hCal);
If this is the case, I would probably have a setRender(), but you could easily accomplish this anyways with just a render method anyways.Using something a la setRenderer would give you the ability to set a renderer without rendering. So you could feasibly change the rendering engine midstream, if you wanted to, with the need for actual output.
Code: Select all
abstract class qCal_Renderer
{
public function render(qCal_Component $component)
{
$ret = '';
foreach ($component->getChildren() as $child)
{
if ($child instanceof qCal_Component) $ret .= $this->renderComponent($child);
elseif ($child instanceof qCal_Property) $ret .= $this->renderProperty($child);
}
}
abstract protected function renderComponent(qCal_Component $component);
abstract protected function renderProperty(qCal_Property $component);
}
class qCal_Renderer_icalendar
{
protected function renderComponent(qCal_Component $component)
{
foreach ($component->getChildren() as $child)
{
// render each child
}
}
protected function renderProperty(qCal_Property $component)
{
// render property
}
}I haven't had a chance to look and think about your code (hopefully I will get some time), but the above sounds wrong to me because components should render and properties should be essentially models for the components/views. Maybe I am not understanding your terminology.The Ninja Space Goat wrote:Alright, I'm having some trouble here again. I'm hoping somebody can just give me a push in the right direction. I've tried several things, but none seem flexible enough. I've got qCal_Component and qCal_Property. Components can have other components, as well as properties as children. My renderer needs to be able to traverse this tree of qCal_Components / qCal_Properties and render them based on logic provided by subclasses of qCal_Renderer. Does that make sense?
I might be interested to use this in our current project on a later stageThe Ninja Space Goat wrote:Is there any interest in a library such as this?
I believe component tree traversal should be embedded into the components themselves - that's what the composite pattern is about. And you could implement renderer as a visitor: something like this:This just doesn't feel like it will provide that kind of flexibility, and also I end up looping through component's children twice here... which feels wrong. DRY?
Code: Select all
<?php
interface qCal_Component_Visitor_Interface
{
public function visitComponent(qCal_Component $component);
public function visitProperty(qCal_Property $component);
}
class qCal_Renderer_icalendar implements qCal_Component_Visitor_Interface
{
protected function visitComponent(qCal_Component $component)
{
// render only that pertaining to component itself
}
protected function visitProperty(qCal_Property $component)
{
// render property
}
}
interface qCal_Component_Interface
{
public function traverse(qCal_Component_Visitor_Interface $visitor);
}
class qCal_Component implements qCal_Component_Interface
{
public function traverse(qCal_Component_Visitor_Interface $visitor)
{
$visitor->visitComponent($this);
foreach ($this->getChildren() as $child) {
$child->traverse($visitor);
}
}
}
class qCal_Property implements qCal_Component_Interface
{
public function traverse(qCal_Component_Visitor_Interface $visitor)
{
$visitor->visitProperty($this);
}
}
?>