RE: [fw-general] Data Mappers and Relational Modelling

2009-09-07 Thread Jared Williams
 
Hi,

Tried to post this as a comment on the wiki, but its slow/dying or dead.

One thing I think that could simplify some of this, is telling the back end
where to put values, rather than ask for them and having to juggle them
about. Especially when have to deal with joins and particularly self joins,
as each set of fields can be bound to their own scope.

The also an added advantage is that PDO  MySQLi backends can be told where
to put column values, so PDOStatement::fetch(PDO::FETCH_BOUND) or
MySQLI_STMT::fetch() respectively can do most of the actual mapping. 

A crude example (which is all kinds of wrong in other aspects... ) is
below..

Jared


?php

function query(PDO $pdo, $sql, array $refs = null, array $params = null)
{
$query = $pdo-prepare($sql);
if ($query-execute($params))
{
if ($refs)
{
$i = 1;
foreach($refs as $ref)
$query-bindColumn($i++, $ref);
}
return function() use ($query)
{
return $query-fetch(\PDO::FETCH_BOUND);
};
}
return false;
}

function findAllAndBoss(PDO $pdo)
{
$e = array();
$b = array();

$iterator = query($pdo, 'SELECT e.id, e.name, e.email, 
b.id, b.name, b.email FROM Employee e LEFT
JOIN Employee b ON e.boss = b.id')
array(
$e['id'], $e['name'], $e['email'],
$b['id'], $b['name'], $b['email']));
return function() use ($e, $b, $iterator)
{
if ($iterator())
{
// IdentityMap lookup omitted...
$employee = new Employee();
$employee-setState($e);

// IdentityMap lookup omitted...

if (isset($b['id']))
{
$boss = new Employee();
$boss-setState($b);
}
else
$boss = null;

return array($employee, $boss);
}
return false;
};
}



Re: [fw-general] Data Mappers and Relational Modelling

2009-09-04 Thread Benjamin Eberlei

Hello Chris,

there is an example/readme at www.beberlei.de/zendentity which is a
quickstart
rewrite of the bug model in the Zend_Db manual. It has some quirks, but
a working (though slightly different) demo is in the

http://framework.zend.com/svn/framework/standard/incubator/demos/Zend/Entity

repository.

Sadly ZendCon and the development of zend Entity are on a bad timeline,
i haven't tried to get any talk about it into, and since i am from
germany i won't be at ZendCon unless someone (Zend ;)) pays me to come ;)

greetings,
Benjamin 


On Thu, 3 Sep 2009 16:49:34 -0700 (PDT), Chris Murray cmur...@murtek.com
wrote:
 Yes, it is difficult, especially doing complex validation on nested
forms.
 I'm in the late stages of building an ORM/MDA framework on top of ZF.
It's
 quite functional, but I'd much prefer to work with others doing the same
 thing and use a common code base that is certainly going to be more
robust
 and sophisticated than what I've built.
 
 I've downloaded the latest Zend_Entity code. Is there an example or
readme
 somewhere so I can try to map my MDA definitions into Zend_Entity? BTW,
 I'll
 be attending ZendCon so hope to learn more about it there.


Re: [fw-general] Data Mappers and Relational Modelling

2009-09-03 Thread Chris Murray

Yes, it is difficult, especially doing complex validation on nested forms.
I'm in the late stages of building an ORM/MDA framework on top of ZF. It's
quite functional, but I'd much prefer to work with others doing the same
thing and use a common code base that is certainly going to be more robust
and sophisticated than what I've built.

I've downloaded the latest Zend_Entity code. Is there an example or readme
somewhere so I can try to map my MDA definitions into Zend_Entity? BTW, I'll
be attending ZendCon so hope to learn more about it there.
-- 
View this message in context: 
http://www.nabble.com/Data-Mappers-and-Relational-Modelling-tp25193848p25286031.html
Sent from the Zend Framework mailing list archive at Nabble.com.



Re: [fw-general] Data Mappers and Relational Modelling

2009-09-02 Thread keith Pope
2009/9/1 Matthew Weier O'Phinney matt...@zend.com:
 -- Hector Virgen djvir...@gmail.com wrote
 (on Tuesday, 01 September 2009, 12:02 PM -0700):
 I've updated my Collection object and it is working very nicely. I can now
 iterate through an entity's child entities very easily thanks to the lazy
 loading collection, and the entity has no idea that a mapper even exists:

 $quizMapper = new QuizMapper();
 $quiz = $quizMapper-find(123);
 foreach ($quiz-getQuestions() as $question) {
     assert($question instanceof Question); // true
 }

 But now I have a problem with relationships in the other direction --
 specifically, the belongs to relationship.

 Let's say I have a Question object and need to access the Quiz object that it
 belongs to. Since a Question can only belong to one Quiz, how could I achieve
 that without a mapper? For example I want to do this:

 $questionMapper = new QuestionMapper();
 $question = $questionMapper-find(456);
 $quiz = $question-getQuiz();

 How are these types of relationships normally handled? I was thinking of
 creating a new type of class that is similar to the Collection object, but 
 only
 deals with a single entity. For example (simplified for brevity):

 Before you get too carried away...

 ORM stuff is really, really difficult. DataMappers that deal with a
 single table are fairly easy (which is part of the reason we demonstrate
 the technique in the quick start), but once you start dealing with
 relations (the realm of ORMs -- Object Relational Mappers), it becomes
 quite complicated -- as you're starting to discover.

 Benjamin Eberlei is working on a general ORM solution for ZF currently,
 and it's in the incubator. Do yourself a favor and check out his work --
 it's under the Zend_Entity namespace. If you have ideas on how it might
 work, give him a helping hand. :)

 If you need stable code, and need it now, try out Doctrine.

Maybe it would be an idea to note this in the quickstart guide, I
think people are easily confused by the data mapper example.

In martin fowlers book it also mentions that data mappers are
difficult to implement, and indeed he says that its better to buy one
than create your own :)


 class My_Domain_Entity_Reference
 {
     protected $_id;
     protected $_mapper;

     public function __construct($id, My_Domain_Entity_Mapper_Interface 
 $mapper)
     {
         $this-_id = $id;
         $this-_mapper = $mapper;
     }

     public function getReference()
     {
         return $this-_mapper-find($this-_id);
     }
 }

 Then, I could add this reference to my Question object in the 
 QuestionMapper's
 find() method:

 class QuestionMapper
 implements My_Domain_Entity_Mapper_Interface
 {
     public function find($id)
     {
         $row = $this-_questionTable-find($id)-current();
         $question = new Question();
         /* ... */
         $quiz_id = $row-quiz_id;
         $quizMapper = new QuizMapper();
         $question-addReference('quiz', new My_Domain_Entity_Reference
 ($quiz_id, $quizMapper));
     }
 }

 I would then have to update the Question::getQuiz() method to pull the value
 from its references.

 Does this seem like a good way to approach the belongs-to relationship
 problem? Thanks again for all your help!

 --
 Hector


 On Sun, Aug 30, 2009 at 3:34 PM, Hector Virgen djvir...@gmail.com wrote:

     Thanks, Benjamin. I like your version of the Collection object better 
 that
     mine. It seems much more flexible and supports lazy loading without the
     need to provide my Quiz object with a mapper. I'm going to update my
     Collection class with your idea and post back here if I run into any
     problems. Thanks again!

     --
     Hector



     On Sat, Aug 29, 2009 at 12:00 AM, Benjamin Eberlei kont...@beberlei.de
     wrote:

         Hello,

         lazy loads are implemented by some underyling magic. Say you have a
         Quiz
         with questions and you load the quiz. Instead of adding an array of 
 all
         the
         questions right away, you build a collection class which implements
         ArrayAccess, Iterator and Countable and takes a PHP Callback which is
         fired
         upon the first acces of any of those functions. See here:

         
 http://framework.zend.com/svn/framework/standard/branches/user/beberlei
         /Zend_Entity/library/Zend/Entity/LazyLoad/Collection.php

         In your example it would look like:

         $quiz = $quizMapper-findById(1);

         // Inside QuizMapper building the quiz:
         $questionsMapper = new QuestionsMapper();
         $state['questions'] = new Zend_Entity_LazyLoad_Collection(
            array($questionsMapper, loadByQuizId), array($state['id'])
         );

         This way you have a collection inside your quiz, its just not loaded
         yet
         though. Only upon first access of this pseudo array all the data is
         loaded.

         Implementing LazyLoad for querying is easy, there are some tricks to 
 do
        

Re: [fw-general] Data Mappers and Relational Modelling

2009-09-01 Thread Matthew Weier O'Phinney
-- Hector Virgen djvir...@gmail.com wrote
(on Tuesday, 01 September 2009, 12:02 PM -0700):
 I've updated my Collection object and it is working very nicely. I can now
 iterate through an entity's child entities very easily thanks to the lazy
 loading collection, and the entity has no idea that a mapper even exists:
 
 $quizMapper = new QuizMapper();
 $quiz = $quizMapper-find(123);
 foreach ($quiz-getQuestions() as $question) {
 assert($question instanceof Question); // true
 }
 
 But now I have a problem with relationships in the other direction --
 specifically, the belongs to relationship.
 
 Let's say I have a Question object and need to access the Quiz object that it
 belongs to. Since a Question can only belong to one Quiz, how could I achieve
 that without a mapper? For example I want to do this:
 
 $questionMapper = new QuestionMapper();
 $question = $questionMapper-find(456);
 $quiz = $question-getQuiz();
 
 How are these types of relationships normally handled? I was thinking of
 creating a new type of class that is similar to the Collection object, but 
 only
 deals with a single entity. For example (simplified for brevity):

Before you get too carried away...

ORM stuff is really, really difficult. DataMappers that deal with a
single table are fairly easy (which is part of the reason we demonstrate
the technique in the quick start), but once you start dealing with
relations (the realm of ORMs -- Object Relational Mappers), it becomes
quite complicated -- as you're starting to discover.

Benjamin Eberlei is working on a general ORM solution for ZF currently,
and it's in the incubator. Do yourself a favor and check out his work --
it's under the Zend_Entity namespace. If you have ideas on how it might
work, give him a helping hand. :)

If you need stable code, and need it now, try out Doctrine.

 class My_Domain_Entity_Reference
 {
 protected $_id;
 protected $_mapper;
 
 public function __construct($id, My_Domain_Entity_Mapper_Interface 
 $mapper)
 {
 $this-_id = $id;
 $this-_mapper = $mapper;
 }
 
 public function getReference()
 {
 return $this-_mapper-find($this-_id);
 }
 }
 
 Then, I could add this reference to my Question object in the QuestionMapper's
 find() method:
 
 class QuestionMapper
 implements My_Domain_Entity_Mapper_Interface
 {
 public function find($id)
 {
 $row = $this-_questionTable-find($id)-current();
 $question = new Question();
 /* ... */
 $quiz_id = $row-quiz_id;
 $quizMapper = new QuizMapper();
 $question-addReference('quiz', new My_Domain_Entity_Reference
 ($quiz_id, $quizMapper));
 }
 }
 
 I would then have to update the Question::getQuiz() method to pull the value
 from its references.
 
 Does this seem like a good way to approach the belongs-to relationship
 problem? Thanks again for all your help!
 
 --
 Hector
 
 
 On Sun, Aug 30, 2009 at 3:34 PM, Hector Virgen djvir...@gmail.com wrote:
 
 Thanks, Benjamin. I like your version of the Collection object better that
 mine. It seems much more flexible and supports lazy loading without the
 need to provide my Quiz object with a mapper. I'm going to update my
 Collection class with your idea and post back here if I run into any
 problems. Thanks again!
 
 --
 Hector
 
 
 
 On Sat, Aug 29, 2009 at 12:00 AM, Benjamin Eberlei kont...@beberlei.de
 wrote:
 
 Hello,
 
 lazy loads are implemented by some underyling magic. Say you have a
 Quiz
 with questions and you load the quiz. Instead of adding an array of 
 all
 the
 questions right away, you build a collection class which implements
 ArrayAccess, Iterator and Countable and takes a PHP Callback which is
 fired
 upon the first acces of any of those functions. See here:
 
 
 http://framework.zend.com/svn/framework/standard/branches/user/beberlei
 /Zend_Entity/library/Zend/Entity/LazyLoad/Collection.php
 
 In your example it would look like:
 
 $quiz = $quizMapper-findById(1);
 
 // Inside QuizMapper building the quiz:
 $questionsMapper = new QuestionsMapper();
 $state['questions'] = new Zend_Entity_LazyLoad_Collection(
array($questionsMapper, loadByQuizId), array($state['id'])
 );
 
 This way you have a collection inside your quiz, its just not loaded
 yet
 though. Only upon first access of this pseudo array all the data is
 loaded.
 
 Implementing LazyLoad for querying is easy, there are some tricks to 
 do
 it
 right when saving the collection then if you dont want to completly
 load it.
 
 greetings,
 Benjamin
 
 On Saturday 29 August 2009 08:06:06 am Hector Virgen wrote:
  Thank you for the replies, Dmytro and Keith.
  I just finished reading over the Zend_Db_Mapper 

Re: [fw-general] Data Mappers and Relational Modelling

2009-09-01 Thread Hector Virgen
Thanks for the reply, Matthew. I have looked over his proposal but only
briefly. I'll have to examine it more closely to see how the relationships
are handled.
I've found (based on my limited experience) that the data mapper pattern is
more of an idea than a set of abstract classes. For example, my mapper
interface only requries a find() method, and my abstract entities are
nothing more than magic getters/setters for a protected $_data array.

This is why I have been interested lately in learning how everything works,
since the pattern must be re-implemented for each entity/mapper.

Thanks again for the tips. Looks like I have some more reading to do :)

--
Hector


On Tue, Sep 1, 2009 at 1:55 PM, Matthew Weier O'Phinney matt...@zend.comwrote:

 -- Hector Virgen djvir...@gmail.com wrote
 (on Tuesday, 01 September 2009, 12:02 PM -0700):
  I've updated my Collection object and it is working very nicely. I can
 now
  iterate through an entity's child entities very easily thanks to the
 lazy
  loading collection, and the entity has no idea that a mapper even exists:
 
  $quizMapper = new QuizMapper();
  $quiz = $quizMapper-find(123);
  foreach ($quiz-getQuestions() as $question) {
  assert($question instanceof Question); // true
  }
 
  But now I have a problem with relationships in the other direction --
  specifically, the belongs to relationship.
 
  Let's say I have a Question object and need to access the Quiz object
 that it
  belongs to. Since a Question can only belong to one Quiz, how could I
 achieve
  that without a mapper? For example I want to do this:
 
  $questionMapper = new QuestionMapper();
  $question = $questionMapper-find(456);
  $quiz = $question-getQuiz();
 
  How are these types of relationships normally handled? I was thinking of
  creating a new type of class that is similar to the Collection object,
 but only
  deals with a single entity. For example (simplified for brevity):

 Before you get too carried away...

 ORM stuff is really, really difficult. DataMappers that deal with a
 single table are fairly easy (which is part of the reason we demonstrate
 the technique in the quick start), but once you start dealing with
 relations (the realm of ORMs -- Object Relational Mappers), it becomes
 quite complicated -- as you're starting to discover.

 Benjamin Eberlei is working on a general ORM solution for ZF currently,
 and it's in the incubator. Do yourself a favor and check out his work --
 it's under the Zend_Entity namespace. If you have ideas on how it might
 work, give him a helping hand. :)

 If you need stable code, and need it now, try out Doctrine.

  class My_Domain_Entity_Reference
  {
  protected $_id;
  protected $_mapper;
 
  public function __construct($id, My_Domain_Entity_Mapper_Interface
 $mapper)
  {
  $this-_id = $id;
  $this-_mapper = $mapper;
  }
 
  public function getReference()
  {
  return $this-_mapper-find($this-_id);
  }
  }
 
  Then, I could add this reference to my Question object in the
 QuestionMapper's
  find() method:
 
  class QuestionMapper
  implements My_Domain_Entity_Mapper_Interface
  {
  public function find($id)
  {
  $row = $this-_questionTable-find($id)-current();
  $question = new Question();
  /* ... */
  $quiz_id = $row-quiz_id;
  $quizMapper = new QuizMapper();
  $question-addReference('quiz', new My_Domain_Entity_Reference
  ($quiz_id, $quizMapper));
  }
  }
 
  I would then have to update the Question::getQuiz() method to pull the
 value
  from its references.
 
  Does this seem like a good way to approach the belongs-to relationship
  problem? Thanks again for all your help!
 
  --
  Hector
 
 
  On Sun, Aug 30, 2009 at 3:34 PM, Hector Virgen djvir...@gmail.com
 wrote:
 
  Thanks, Benjamin. I like your version of the Collection object better
 that
  mine. It seems much more flexible and supports lazy loading without
 the
  need to provide my Quiz object with a mapper. I'm going to update my
  Collection class with your idea and post back here if I run into any
  problems. Thanks again!
 
  --
  Hector
 
 
 
  On Sat, Aug 29, 2009 at 12:00 AM, Benjamin Eberlei 
 kont...@beberlei.de
  wrote:
 
  Hello,
 
  lazy loads are implemented by some underyling magic. Say you have
 a
  Quiz
  with questions and you load the quiz. Instead of adding an array
 of all
  the
  questions right away, you build a collection class which
 implements
  ArrayAccess, Iterator and Countable and takes a PHP Callback
 which is
  fired
  upon the first acces of any of those functions. See here:
 
 
 http://framework.zend.com/svn/framework/standard/branches/user/beberlei
  /Zend_Entity/library/Zend/Entity/LazyLoad/Collection.php
 
  In your example it would look like:
 
  $quiz = $quizMapper-findById(1);
 
  

Re: [fw-general] Data Mappers and Relational Modelling

2009-08-30 Thread Hector Virgen
Thanks, Benjamin. I like your version of the Collection object better that
mine. It seems much more flexible and supports lazy loading without the need
to provide my Quiz object with a mapper. I'm going to update my Collection
class with your idea and post back here if I run into any problems. Thanks
again!

--
Hector


On Sat, Aug 29, 2009 at 12:00 AM, Benjamin Eberlei kont...@beberlei.dewrote:

 Hello,

 lazy loads are implemented by some underyling magic. Say you have a Quiz
 with questions and you load the quiz. Instead of adding an array of all the
 questions right away, you build a collection class which implements
 ArrayAccess, Iterator and Countable and takes a PHP Callback which is fired
 upon the first acces of any of those functions. See here:


 http://framework.zend.com/svn/framework/standard/branches/user/beberlei/Zend_Entity/library/Zend/Entity/LazyLoad/Collection.php

 In your example it would look like:

 $quiz = $quizMapper-findById(1);

 // Inside QuizMapper building the quiz:
 $questionsMapper = new QuestionsMapper();
 $state['questions'] = new Zend_Entity_LazyLoad_Collection(
array($questionsMapper, loadByQuizId), array($state['id'])
 );

 This way you have a collection inside your quiz, its just not loaded yet
 though. Only upon first access of this pseudo array all the data is loaded.

 Implementing LazyLoad for querying is easy, there are some tricks to do it
 right when saving the collection then if you dont want to completly load
 it.

 greetings,
 Benjamin

 On Saturday 29 August 2009 08:06:06 am Hector Virgen wrote:
  Thank you for the replies, Dmytro and Keith.
  I just finished reading over the Zend_Db_Mapper proposal, and it is
 looking
  really nice. It seems to be similar to what I've been putting together,
  which makes me feel confident that I'm at least somewhat on the right
  track.
 
  I can agree that the entity should not know about the mapper, but without
  it I wasn't able to figure out a way for the entity to support lazy
 loading
  (where would it load from?). This was the part I struggled with the most,
  because I wanted my entities to know about their relationships:
 
  $quiz-getOwner(); // lazy loads the owner as a User entity
 
  Unless I'm missing something, it seems important that a quiz knows about
  its owner if even just for saving purposes:
 
  class QuizMapper
  {
  /* ... */
  public function save(Quiz $quiz)
  {
  $data = array(
  'title' = $quiz-title,
  'owner_id' = $quiz-owner-id
  );
  // add code to save to persistent storage
  }
  }
 
  I suppose I could just test if the quiz has an owner object, and save its
  ID if it does, but then I have to account for a quiz that doesn't have an
  owner -- would its value be set to false?
 
  I think maybe shadow data can help in this case by resorting to the
 shadow
  value if owner object doesn't exist, allowing me to re-save an entity
  without ever having to load the owner object at all.
 
  Dmytro, regarding your question about where the collection gets its IDs,
 it
  is provided by the mapper. For example, my QuizMapper may have a method
  that returns all quizzes owned by a user. But instead of returning an
 array
  of instantiated Quiz objects, it returns a single Collection object that
  produces Quiz entities when iterated:
 
  class QuizMapper
  {
  /* ... */
  public function findByUser(User $user)
  {
  $db = $this-getDatabase()
  $select = $db-select()
  -from('quizzes', array('quiz_id'))
  -where('user_id = ?', $user-id)
  ;
  $ids = $db-fetchCol($select);
  $collection = new My_Entity_Collection();
  $collection-setMapper($this);
  $collection-setIds($ids);
  return $collection;
  }
  }
 
  This allows me to create specialty methods that return entities based on
  any criteria (like for searches, etc) and the collection can be paginated
  with Zend_Paginator. From what I understand, the Zend_Db_Mapper proposal
  also has a collection that is similar to this one.
 
  What I was also thinking of doing was expanding on the Collection idea
 and
  making a class that contains information on how to build a reference
 entity
  using an implementation of the Value Holder type of lazy loading. All
 this
  class would contain is a mapper, an ID, and a factory method to use the
  mapper to create the entity. Something like this:
 
  class My_Entity_Reference
  {
  protected $_id;
  protected $_mapperClass;
 
  public function __construct($id, $mapperClass)
  {
  $this-_id = $id;
  $this-_mapperClass = $mapperClass;
  $this-_method = $method;
  }
 
  public function getValue()
  {
  $mapper = new $this-_mapperClass();
  return $mapper-find($this-_id);
  }
  }
 
  I could then use this reference object to give the entity a way to
  lazy-load a single resource 

Re: [fw-general] Data Mappers and Relational Modelling

2009-08-29 Thread Hector Virgen
Thank you for the replies, Dmytro and Keith.
I just finished reading over the Zend_Db_Mapper proposal, and it is looking
really nice. It seems to be similar to what I've been putting together,
which makes me feel confident that I'm at least somewhat on the right track.

I can agree that the entity should not know about the mapper, but without it
I wasn't able to figure out a way for the entity to support lazy loading
(where would it load from?). This was the part I struggled with the most,
because I wanted my entities to know about their relationships:

$quiz-getOwner(); // lazy loads the owner as a User entity

Unless I'm missing something, it seems important that a quiz knows about its
owner if even just for saving purposes:

class QuizMapper
{
/* ... */
public function save(Quiz $quiz)
{
$data = array(
'title' = $quiz-title,
'owner_id' = $quiz-owner-id
);
// add code to save to persistent storage
}
}

I suppose I could just test if the quiz has an owner object, and save its ID
if it does, but then I have to account for a quiz that doesn't have an owner
-- would its value be set to false?

I think maybe shadow data can help in this case by resorting to the shadow
value if owner object doesn't exist, allowing me to re-save an entity
without ever having to load the owner object at all.

Dmytro, regarding your question about where the collection gets its IDs, it
is provided by the mapper. For example, my QuizMapper may have a method that
returns all quizzes owned by a user. But instead of returning an array of
instantiated Quiz objects, it returns a single Collection object that
produces Quiz entities when iterated:

class QuizMapper
{
/* ... */
public function findByUser(User $user)
{
$db = $this-getDatabase()
$select = $db-select()
-from('quizzes', array('quiz_id'))
-where('user_id = ?', $user-id)
;
$ids = $db-fetchCol($select);
$collection = new My_Entity_Collection();
$collection-setMapper($this);
$collection-setIds($ids);
return $collection;
}
}

This allows me to create specialty methods that return entities based on any
criteria (like for searches, etc) and the collection can be paginated with
Zend_Paginator. From what I understand, the Zend_Db_Mapper proposal also has
a collection that is similar to this one.

What I was also thinking of doing was expanding on the Collection idea and
making a class that contains information on how to build a reference entity
using an implementation of the Value Holder type of lazy loading. All this
class would contain is a mapper, an ID, and a factory method to use the
mapper to create the entity. Something like this:

class My_Entity_Reference
{
protected $_id;
protected $_mapperClass;

public function __construct($id, $mapperClass)
{
$this-_id = $id;
$this-_mapperClass = $mapperClass;
$this-_method = $method;
}

public function getValue()
{
$mapper = new $this-_mapperClass();
return $mapper-find($this-_id);
}
}

I could then use this reference object to give the entity a way to lazy-load
a single resource without giving the entity access to a mapper. Perhaps this
would be a good alternative to giving the entity a mapper to work with? Or
should I be relying on shadow data? Maybe I could use both ideas together
and use the Reference object as a shadow data by adding a getId() method. So
many ways to go! :)

--
Hector


On Fri, Aug 28, 2009 at 4:45 PM, keith Pope mute.p...@googlemail.comwrote:

 2009/8/28 Hector Virgen djvir...@gmail.com:
  Thanks for the reply, Tim. So you're saying I'll need one or more mappers
  for my Quiz entity depending on how much information I want to prefill
 the
  quiz with? For example I'll have classes like:
 
  QuizSimpleMapper
  QuizWithQuestionsMapper
 
  Let's say we allow the users to tag their quizzes from a set of global
 tags,
  and they can use as many tags as they want. Would I then need more
 mappers?
 
  QuizWithTagsMapper
  TagMapper
  TagWithQuizzesMapper
 
  Then, if I need a Quiz with its questions and its tags, do I need to
 create
  yet another mapper?
 
  QuizWithQuestionsAndTagMapper
 
  This is becoming overwhelming. I feel like this complexity could be
  simplified if the entity had access to the mapper that created it,
 allowing
  it to pull in more data in a lazy-loading fashion. But as you said, that
  goes against the design pattern.
  What I have been working on lately has been an entity collection object
  which contains a mapper instance and a list of IDs. It implements the
  SeekableIterator and Countable interfaces and uses lazy-loading to load
 the
  actual entity on demand when My_Model_Entity_Collection::current() is
  called. This seems to help so that objects aren't created until they're
  accessed, and they can be accessed without any additional work on the
  

Re: [fw-general] Data Mappers and Relational Modelling

2009-08-29 Thread Benjamin Eberlei
Hello,

lazy loads are implemented by some underyling magic. Say you have a Quiz
with questions and you load the quiz. Instead of adding an array of all the 
questions right away, you build a collection class which implements 
ArrayAccess, Iterator and Countable and takes a PHP Callback which is fired 
upon the first acces of any of those functions. See here:

http://framework.zend.com/svn/framework/standard/branches/user/beberlei/Zend_Entity/library/Zend/Entity/LazyLoad/Collection.php

In your example it would look like:

$quiz = $quizMapper-findById(1);

// Inside QuizMapper building the quiz:
$questionsMapper = new QuestionsMapper();
$state['questions'] = new Zend_Entity_LazyLoad_Collection(
array($questionsMapper, loadByQuizId), array($state['id'])
);

This way you have a collection inside your quiz, its just not loaded yet 
though. Only upon first access of this pseudo array all the data is loaded.

Implementing LazyLoad for querying is easy, there are some tricks to do it 
right when saving the collection then if you dont want to completly load it.

greetings,
Benjamin

On Saturday 29 August 2009 08:06:06 am Hector Virgen wrote:
 Thank you for the replies, Dmytro and Keith.
 I just finished reading over the Zend_Db_Mapper proposal, and it is looking
 really nice. It seems to be similar to what I've been putting together,
 which makes me feel confident that I'm at least somewhat on the right
 track.

 I can agree that the entity should not know about the mapper, but without
 it I wasn't able to figure out a way for the entity to support lazy loading
 (where would it load from?). This was the part I struggled with the most,
 because I wanted my entities to know about their relationships:

 $quiz-getOwner(); // lazy loads the owner as a User entity

 Unless I'm missing something, it seems important that a quiz knows about
 its owner if even just for saving purposes:

 class QuizMapper
 {
 /* ... */
 public function save(Quiz $quiz)
 {
 $data = array(
 'title' = $quiz-title,
 'owner_id' = $quiz-owner-id
 );
 // add code to save to persistent storage
 }
 }

 I suppose I could just test if the quiz has an owner object, and save its
 ID if it does, but then I have to account for a quiz that doesn't have an
 owner -- would its value be set to false?

 I think maybe shadow data can help in this case by resorting to the shadow
 value if owner object doesn't exist, allowing me to re-save an entity
 without ever having to load the owner object at all.

 Dmytro, regarding your question about where the collection gets its IDs, it
 is provided by the mapper. For example, my QuizMapper may have a method
 that returns all quizzes owned by a user. But instead of returning an array
 of instantiated Quiz objects, it returns a single Collection object that
 produces Quiz entities when iterated:

 class QuizMapper
 {
 /* ... */
 public function findByUser(User $user)
 {
 $db = $this-getDatabase()
 $select = $db-select()
 -from('quizzes', array('quiz_id'))
 -where('user_id = ?', $user-id)
 ;
 $ids = $db-fetchCol($select);
 $collection = new My_Entity_Collection();
 $collection-setMapper($this);
 $collection-setIds($ids);
 return $collection;
 }
 }

 This allows me to create specialty methods that return entities based on
 any criteria (like for searches, etc) and the collection can be paginated
 with Zend_Paginator. From what I understand, the Zend_Db_Mapper proposal
 also has a collection that is similar to this one.

 What I was also thinking of doing was expanding on the Collection idea and
 making a class that contains information on how to build a reference entity
 using an implementation of the Value Holder type of lazy loading. All this
 class would contain is a mapper, an ID, and a factory method to use the
 mapper to create the entity. Something like this:

 class My_Entity_Reference
 {
 protected $_id;
 protected $_mapperClass;

 public function __construct($id, $mapperClass)
 {
 $this-_id = $id;
 $this-_mapperClass = $mapperClass;
 $this-_method = $method;
 }

 public function getValue()
 {
 $mapper = new $this-_mapperClass();
 return $mapper-find($this-_id);
 }
 }

 I could then use this reference object to give the entity a way to
 lazy-load a single resource without giving the entity access to a mapper.
 Perhaps this would be a good alternative to giving the entity a mapper to
 work with? Or should I be relying on shadow data? Maybe I could use both
 ideas together and use the Reference object as a shadow data by adding a
 getId() method. So many ways to go! :)

 --
 Hector

 On Fri, Aug 28, 2009 at 4:45 PM, keith Pope mute.p...@googlemail.comwrote:
  2009/8/28 Hector Virgen djvir...@gmail.com:
   Thanks for the reply, Tim. So you're saying I'll need one or more
   

Re: [fw-general] Data Mappers and Relational Modelling

2009-08-28 Thread Tim Navrotskyy

Hi,


Hector Virgen wrote:
 
 The example in the Zend Framework Quick Start [1] involves only a single
 model and a single mapper, which is fine -- the pattern works beautifully
 in
 isolation. But in my application I have many models each with their own
 mappers, and the models are related to each in one-to-one, one-to-many,
 and
 many-to-many relationships.
 

I think the data mapper pattern is not implemented right in the QuickStart
guide which leads to series of questions like yours. Even on the 
http://martinfowler.com/eaaCatalog/dataMapper.html reference page  we see:


 A layer of Mappers (473) that moves data between objects and a database
 while keeping them independent of each other and the mapper itself.
 

According to this statement the class Quiz may not depend on any Data
Mapper, including the QuestionMapper.

The client code (e.g. action controller) using a Data Mapper may look like
this:

//fetching questions for some quiz
$questions = $questionMapper-findByQuiz($quiz);

$questions is now a collection of objects with complete question informaton
including the answer choices.

The client doesn't ask the Quiz Entity to get the questions, but the mapper.
The question mapper may communicate with the AnswerChoice mapper to fetch
the choices and populate the questions with them. 

Implementing it this way you make your Model independent of the Mapper and
therefore the storage type. 


Hector Virgen wrote:
 
 Also, since each question belongs to a quiz, should the Question object
 contain an instance of the Quiz object it belongs to?
 

I think it's acceptable if you use this backreference somewhere.


Hector Virgen wrote:
 
 If I follow this pattern, then when I find a single AnswerChoice object,
 the AnswerChoiceMapper would load the parent Question object, which loads
 the parent Quiz object, which loads the parent User object, etc. This
 seems
 to be inefficient, especially when iterating through multiple answer
 choices.
 

With the Data Mapper layer decoupled from your model you may now implement
another mapper for each use case which pulls exactly as many dependencies as
needed. You could still use techniques you mentioned like Identity Map or
Lazy Loading. Martin Fowler describes them very good in 
http://martinfowler.com/books.html#eaa PoEAA .

Tim.
-- 
View this message in context: 
http://www.nabble.com/Data-Mappers-and-Relational-Modelling-tp25193848p25198001.html
Sent from the Zend Framework mailing list archive at Nabble.com.



Re: [fw-general] Data Mappers and Relational Modelling

2009-08-28 Thread Hector Virgen
Thanks for the reply, Tim. So you're saying I'll need one or more mappers
for my Quiz entity depending on how much information I want to prefill the
quiz with? For example I'll have classes like:

   - QuizSimpleMapper
   - QuizWithQuestionsMapper

Let's say we allow the users to tag their quizzes from a set of global tags,
and they can use as many tags as they want. Would I then need more mappers?

   - QuizWithTagsMapper
   - TagMapper
   - TagWithQuizzesMapper

Then, if I need a Quiz with its questions and its tags, do I need to create
yet another mapper?

   - QuizWithQuestionsAndTagMapper

This is becoming overwhelming. I feel like this complexity could be
simplified if the entity had access to the mapper that created it, allowing
it to pull in more data in a lazy-loading fashion. But as you said, that
goes against the design pattern.

What I have been working on lately has been an entity collection object
which contains a mapper instance and a list of IDs. It implements the
SeekableIterator and Countable interfaces and uses lazy-loading to load the
actual entity on demand when My_Model_Entity_Collection::current() is
called. This seems to help so that objects aren't created until they're
accessed, and they can be accessed without any additional work on the
object. Any thoughts on this?

--
Hector


On Fri, Aug 28, 2009 at 3:32 PM, Tim Navrotskyy dmytro.navrots...@gmail.com
 wrote:


 Hi,


 Hector Virgen wrote:
 
  The example in the Zend Framework Quick Start [1] involves only a single
  model and a single mapper, which is fine -- the pattern works beautifully
  in
  isolation. But in my application I have many models each with their own
  mappers, and the models are related to each in one-to-one, one-to-many,
  and
  many-to-many relationships.
 

 I think the data mapper pattern is not implemented right in the QuickStart
 guide which leads to series of questions like yours. Even on the
 http://martinfowler.com/eaaCatalog/dataMapper.html reference page  we see:


  A layer of Mappers (473) that moves data between objects and a database
  while keeping them independent of each other and the mapper itself.
 

 According to this statement the class Quiz may not depend on any Data
 Mapper, including the QuestionMapper.

 The client code (e.g. action controller) using a Data Mapper may look like
 this:

 //fetching questions for some quiz
 $questions = $questionMapper-findByQuiz($quiz);

 $questions is now a collection of objects with complete question informaton
 including the answer choices.

 The client doesn't ask the Quiz Entity to get the questions, but the
 mapper.
 The question mapper may communicate with the AnswerChoice mapper to fetch
 the choices and populate the questions with them.

 Implementing it this way you make your Model independent of the Mapper and
 therefore the storage type.


 Hector Virgen wrote:
 
  Also, since each question belongs to a quiz, should the Question object
  contain an instance of the Quiz object it belongs to?
 

 I think it's acceptable if you use this backreference somewhere.


 Hector Virgen wrote:
 
  If I follow this pattern, then when I find a single AnswerChoice
 object,
  the AnswerChoiceMapper would load the parent Question object, which loads
  the parent Quiz object, which loads the parent User object, etc. This
  seems
  to be inefficient, especially when iterating through multiple answer
  choices.
 

 With the Data Mapper layer decoupled from your model you may now implement
 another mapper for each use case which pulls exactly as many dependencies
 as
 needed. You could still use techniques you mentioned like Identity Map or
 Lazy Loading. Martin Fowler describes them very good in
 http://martinfowler.com/books.html#eaa PoEAA .

 Tim.
 --
 View this message in context:
 http://www.nabble.com/Data-Mappers-and-Relational-Modelling-tp25193848p25198001.html
 Sent from the Zend Framework mailing list archive at Nabble.com.




Re: [fw-general] Data Mappers and Relational Modelling

2009-08-28 Thread keith Pope
2009/8/28 Hector Virgen djvir...@gmail.com:
 Thanks for the reply, Tim. So you're saying I'll need one or more mappers
 for my Quiz entity depending on how much information I want to prefill the
 quiz with? For example I'll have classes like:

 QuizSimpleMapper
 QuizWithQuestionsMapper

 Let's say we allow the users to tag their quizzes from a set of global tags,
 and they can use as many tags as they want. Would I then need more mappers?

 QuizWithTagsMapper
 TagMapper
 TagWithQuizzesMapper

 Then, if I need a Quiz with its questions and its tags, do I need to create
 yet another mapper?

 QuizWithQuestionsAndTagMapper

 This is becoming overwhelming. I feel like this complexity could be
 simplified if the entity had access to the mapper that created it, allowing
 it to pull in more data in a lazy-loading fashion. But as you said, that
 goes against the design pattern.
 What I have been working on lately has been an entity collection object
 which contains a mapper instance and a list of IDs. It implements the
 SeekableIterator and Countable interfaces and uses lazy-loading to load the
 actual entity on demand when My_Model_Entity_Collection::current() is
 called. This seems to help so that objects aren't created until they're
 accessed, and they can be accessed without any additional work on the
 object. Any thoughts on this?
 --
 Hector

I would say that the quickstart is only a pointer to how a mapper can
work, once you start looking at relationships that are not simple you
will need to create more and more infrastructure to handle them. The
idea of a data mapper is to help create a Domain Model, this also will
require components to manage object life cycle such as unit of work
and identity map patterns.

I would suggest reading up on domain model, Eric Evans Domain Driven
Design is probably the best book to read on this.

Also check out the Zend_Db_Mapper proposal, you will see from this how
involved creating a data mapper is :) The good news is this proposal
has been approved for development which is very good news for the
framework. There is code checked into the SVN for this component too,
which is worth a read through.



 On Fri, Aug 28, 2009 at 3:32 PM, Tim Navrotskyy
 dmytro.navrots...@gmail.com wrote:

 Hi,


 Hector Virgen wrote:
 
  The example in the Zend Framework Quick Start [1] involves only a single
  model and a single mapper, which is fine -- the pattern works
  beautifully
  in
  isolation. But in my application I have many models each with their own
  mappers, and the models are related to each in one-to-one, one-to-many,
  and
  many-to-many relationships.
 

 I think the data mapper pattern is not implemented right in the QuickStart
 guide which leads to series of questions like yours. Even on the
 http://martinfowler.com/eaaCatalog/dataMapper.html reference page  we see:


  A layer of Mappers (473) that moves data between objects and a database
  while keeping them independent of each other and the mapper itself.
 

 According to this statement the class Quiz may not depend on any Data
 Mapper, including the QuestionMapper.

 The client code (e.g. action controller) using a Data Mapper may look like
 this:

 //fetching questions for some quiz
 $questions = $questionMapper-findByQuiz($quiz);

 $questions is now a collection of objects with complete question
 informaton
 including the answer choices.

 The client doesn't ask the Quiz Entity to get the questions, but the
 mapper.
 The question mapper may communicate with the AnswerChoice mapper to fetch
 the choices and populate the questions with them.

 Implementing it this way you make your Model independent of the Mapper and
 therefore the storage type.


 Hector Virgen wrote:
 
  Also, since each question belongs to a quiz, should the Question object
  contain an instance of the Quiz object it belongs to?
 

 I think it's acceptable if you use this backreference somewhere.


 Hector Virgen wrote:
 
  If I follow this pattern, then when I find a single AnswerChoice
  object,
  the AnswerChoiceMapper would load the parent Question object, which
  loads
  the parent Quiz object, which loads the parent User object, etc. This
  seems
  to be inefficient, especially when iterating through multiple answer
  choices.
 

 With the Data Mapper layer decoupled from your model you may now implement
 another mapper for each use case which pulls exactly as many dependencies
 as
 needed. You could still use techniques you mentioned like Identity Map or
 Lazy Loading. Martin Fowler describes them very good in
 http://martinfowler.com/books.html#eaa PoEAA .

 Tim.
 --
 View this message in context:
 http://www.nabble.com/Data-Mappers-and-Relational-Modelling-tp25193848p25198001.html
 Sent from the Zend Framework mailing list archive at Nabble.com.






-- 
--
[MuTe]
--