Re: revised Zend Db Table and JOINs

12 messages Options
Embed this post
Permalink
Simon Mundy

Re: revised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)
Yep, it's the join() method being overly-helpful - if you don't specify an empty array then it assumes '*' (or all fields).

Try:-

$select->join('phones', 'phones.user_id = users.user_id', array())
         ->group('user_id');

Hi Simon,

after I already posted in the nabble.com forum and thread isn't any more visible and lost, I will ask you directlty. When I try to fetch something with a JOIN, I get an exception:

exception 'Zend_Db_Table_Exception' with message 'Select query cannot join with another table'
Don't know why, I tried your code on nabble.

---- Users.php -------
class Users extends Zend_Db_Table_Abstract {
protected $_primary = 'user_id';
protected $_name = 'users';

protected $_dependentTables = array('Phones');

}

----- Phones.php -----
class Phones extends Zend_Db_Table_Abstract {
protected $_primary = 'phone_id';
protected $_name = 'phones';

protected $_referenceMap = array(
'Users' => array(
           'columns'           => 'user_id',
           'refTableClass'     => 'Users',
           'refColumns'        => 'user_id'
)
);
}

----- IndexController.php -------
$this->_helper->modelLoader('Users');
$this->_helper->modelLoader('Phones');
$userTable = new Users();

$select = $userTable->select();
$select->join('phones', 'phones.user_id = users.user_id')
         ->group('user_id');

$partial = $userTable->fetchAll($select);
Zend_Debug::dump($partial);

Any Ideas?

Best regards!




--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654 4124

Simon Mundy

Re: revised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
Hi Dino

That's the constraint of using Zend_Db_Table - you can only access the  
primary table columns, not joined tables. You're better off using the  
regular DB methods if that's what you're after.

Cheers

> Thank you for the fast answer.
> No Exception anymore, but how can I access to the values?
> If I dump the $rowset I get:
>    [6] => array(4) {
>      ["user_id"] => string(1) "9"
>      ["user_name"] => string(6) "sascha"
>      ["user_password"] => string(7) "foopass"
>      ["user_email"] => string(13) "[hidden email]"
>
> No Joined Data :(
>
> Best regards
>
> -------- Original-Nachricht --------
>> Datum: Fri, 2 Nov 2007 23:46:10 +1100
>> Von: Simon Mundy <[hidden email]>
>> An: [hidden email]
>> CC: [hidden email]
>> Betreff: Re: revised Zend Db Table and JOINs
>
>> Yep, it's the join() method being overly-helpful - if you don't
>> specify an empty array then it assumes '*' (or all fields).
>>
>> Try:-
>>
>> $select->join('phones', 'phones.user_id = users.user_id', array())
>>          ->group('user_id');
>>
>>> Hi Simon,
>>>
>>> after I already posted in the nabble.com forum and thread isn't any
>>> more visible and lost, I will ask you directlty. When I try to fetch
>>> something with a JOIN, I get an exception:
>>>
>>> exception 'Zend_Db_Table_Exception' with message 'Select query
>>> cannot join with another table'
>>> Don't know why, I tried your code on nabble.
>>>
>>> ---- Users.php -------
>>> class Users extends Zend_Db_Table_Abstract {
>>> protected $_primary = 'user_id';
>>> protected $_name = 'users';
>>>
>>> protected $_dependentTables = array('Phones');
>>>
>>> }
>>>
>>> ----- Phones.php -----
>>> class Phones extends Zend_Db_Table_Abstract {
>>> protected $_primary = 'phone_id';
>>> protected $_name = 'phones';
>>>
>>> protected $_referenceMap = array(
>>> 'Users' => array(
>>>           'columns'           => 'user_id',
>>>           'refTableClass'     => 'Users',
>>>           'refColumns'        => 'user_id'
>>> )
>>> );
>>> }
>>>
>>> ----- IndexController.php -------
>>> $this->_helper->modelLoader('Users');
>>> $this->_helper->modelLoader('Phones');
>>> $userTable = new Users();
>>>
>>> $select = $userTable->select();
>>> $select->join('phones', 'phones.user_id = users.user_id')
>>>         ->group('user_id');
>>>
>>> $partial = $userTable->fetchAll($select);
>>> Zend_Debug::dump($partial);
>>>
>>> Any Ideas?
>>>
>>> Best regards!
>>>
>>
>>
>>
>> --
>>
>> Simon Mundy | Director | PEPTOLAB
>>
>> """ " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
>> 202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
>> Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654
>> 4124
>> http://www.peptolab.com
>>
>
> --
> GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS.
> Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail



--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654  
4124
http://www.peptolab.com

dinok

Re: revised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
In reply to this post by Simon Mundy
For me, it doesn't work as expected.
When I set an empty array (as you described it), I don't get an exception but the $_data array holds just data of the "base table" (users in my case).
If I assign some cols, I get the same exception as I if i don't add any parameter (= '*').
Any help?
Daniel Freudenberger

RE: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
If you need read access only you could create view in your database with all
necessary columns and create a zend_db_table class from this view.

Best regards,
Daniel

-----Original Message-----
From: dinok [mailto:[hidden email]]
Sent: Friday, November 02, 2007 2:22 PM
To: [hidden email]
Subject: [fw-db] Re: re[fw-db] vised Zend Db Table and JOINs


For me, it doesn't work as expected.
When I set an empty array (as you described it), I don't get an exception
but the $_data array holds just data of the "base table" (users in my case).
If I assign some cols, I get the same exception as I if i don't add any
parameter (= '*').
Any help?
--
View this message in context:
http://www.nabble.com/Re%3A-revised-Zend-Db-Table-and-JOINs-tf4737221s16154.
html#a13547523
Sent from the Zend DB mailing list archive at Nabble.com.


dinok

Re: revised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
In reply to this post by dinok
But there is the problem, that you don't get the relationships exactly.
To understand the problem (and a solution):
http://doctrine.pengus.net/index.php/documentation/manual?one-page#working-with-objects:fetching-objects
But I don't want to use doctrine because it's to big and has some unnecessary features / features that already the zend framework provides.
Simon Mundy

Re: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
That will be more than likely the next step in the evolution of this  
component but for now you'll need to use the relationship capabilities  
of Zend_Db_Table.

> But there is the problem, that you don't get the relationships  
> exactly.
> To understand the problem (and a solution):
> http://doctrine.pengus.net/index.php/documentation/manual?one-page#working-with-objects 
> :fetching-objects
> But I don't want to use doctrine because it's to big and has some
> unnecessary features / features that already the zend framework  
> provides.
> --
> View this message in context: http://www.nabble.com/Re%3A-revised-Zend-Db-Table-and-JOINs-tf4737221s16154.html#a13550822
> Sent from the Zend DB mailing list archive at Nabble.com.

--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654  
4124
http://www.peptolab.com

dinok

Re: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
I'm glad to hear that it will be done in future.
But the problem is the way the table classes act at the moment.
They only represent the real columns and no possibilities to add some readOnly columns (like joined columns). Because that isn't just a small feature which can be easily made.
Is there already a proposal oder possibilty that it might be added to the current proposal?

Concerning the current funktions. What's the best way, to cache such related objects?
Because the relationships are currently realtime queries. So I can't cache 20 queries if I want to get the phonenumbers of 20 users. The best way I'm currently thinking of is to put each PhoneRowset in the related UserRow (example protected $_relatedData = array(...);) and add all UserRows in a new UserRowset.
After this object is completly built, I put it into the cache...
Am I right or is something to complicated and there is an easier way.
Simon Mundy

Re: Re: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
Hi Dinok

Perhaps there's a little too much emphasis on the mechanics here - can  
you provide some more context around your problem? Are you displaying  
a 'menu' or 'directory' of users/phones to browse? Do you need to have  
all these rows represented as individual Zend_Db_Table_Rows or could  
you not simply output the contents of a single SQL query instead?

I agree that having 20 users and then 20 separate queries for each  
user->phone is not optimal performance. It makes more sense to do that  
if you're operating on a per-record basis, not for a longer list.

I'm not sure if this helps you or not, but in my own apps I have a  
separate 'Directory' model that I use for displaying long, sortable  
and pageable lists. It executes a single SQL query, and then I simply  
create a new Zend_Db_Table_Rowset with the array of results. It means  
I don't have a parent table to refer back to, but I still have a very  
usable 'row' object I can use for display.

If this sounds like more your answer and you'd like some more info I  
can post the code for this component.

Cheers

> I'm glad to hear that it will be done in future.
> But the problem is the way the table classes act at the moment.
> They only represent the real columns and no possibilities to add some
> readOnly columns (like joined columns). Because that isn't just a  
> small
> feature which can be easily made.
> Is there already a proposal oder possibilty that it might be added  
> to the
> current proposal?
>
> Concerning the current funktions. What's the best way, to cache such  
> related
> objects?
> Because the relationships are currently realtime queries. So I can't  
> cache
> 20 queries if I want to get the phonenumbers of 20 users. The best  
> way I'm
> currently thinking of is to put each PhoneRowset in the related  
> UserRow
> (example protected $_relatedData = array(...);) and add all UserRows  
> in a
> new UserRowset.
> After this object is completly built, I put it into the cache...
> Am I right or is something to complicated and there is an easier way.
> --
> View this message in context: http://www.nabble.com/Re%3A-revised-Zend-Db-Table-and-JOINs-tf4737221s16154.html#a13562674
> Sent from the Zend DB mailing list archive at Nabble.com.

--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654  
4124
http://www.peptolab.com

dinok

Re: Re: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
It's just for displaying at the moment.
For example, I've got a list of customers. These customers can have some details, but they don't have to.
Some options like phonenumbers, adresses, emails and so on. And I need the list for
1. building an index with the data
2. getting the list as a hole one with the data (pagiging --> limit clause)
So there are just display cases at the moment.
So I think your solution might be interesting.

Best regards
Kamil N

Re: Re: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
Nice proposal.
I have a request , you are editing zend tabe class , could you also fix this issue http://framework.zend.com/issues/browse/ZF-1870 
with default values

Thanks
Simon Mundy

Re: Re: Re: Re: re[fw-db] vised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
Hi Tomek

It wasn't on the radar but I can't see why it wouldn't be considered.  
I think it may also be prudent to see if default values can be  
supplied via the model as well rather than just the metadata.

Thanks for the headsup.

>
> Nice proposal.
> I have a request , you are editing zend tabe class , could you also  
> fix this
> issue http://framework.zend.com/issues/browse/ZF-1870
> with default values
>
> Thanks
> --
> View this message in context: http://www.nabble.com/Re%3A-revised-Zend-Db-Table-and-JOINs-tf4737221s16154.html#a13577256
> Sent from the Zend DB mailing list archive at Nabble.com.

--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654  
4124
http://www.peptolab.com

Simon Mundy

Re: revised Zend Db Table and JOINs

Reply Threaded More More options
Print post
Permalink
In reply to this post by Simon Mundy
Some javascript/style in this post has been disabled (why?)
Hi Dino

Here's my 'Directory' class for you to play with.

I've attached the required components as a zip file. Below is some sample code to get you started. It obviously deserves a little more documentation(!) but that's a to-do for me in the coming weeks... There's also improvements I'd like to make - being able to specify request fields, adding a $config option to configure the keyfields, etc - that would be nice but are not essential for me right now. There's also a hook for adding 'filters' (i.e. widgets that can affect the results set, like being able to add search keywords, etc...) but I won't go into that yet. If this suits your needs I can supplement this post.

Essentially you define 'keyfields' in your model definition for your directory to show. You then pass your model to a Directory object as well as a Request object - the reason for the request object is that it pulls the page number, per-page field, sort field and direction field from the current request. Then you simply fetch the results from the directory and iterate through the resultset.

The model definition below is taken from the Zend_Db documentation on the framework

Hope this helps!

<?php

class Bugs extends Zend_Db_Table_Abstract implements Directory_Interface
{
    protected $_name     = 'bugs';

    // Required to make/show directory
    protected $_keyfields = array(
        'bug_description' => array(
            'title' => 'Name',                                  // Display title
            'type' => 'text',                                   // Can be used to allocate column types for display
            'sort' => 'asc',                                    // Default sort direction if selected
        ),
        'bug_status' => array(
            'title' => 'Status',
            'type' => 'text',
        ),
        'reported_by' => array(
            'title' => 'Reporter',
            'refTable' => array('r' => 'accounts'),              // Lookup table for JOIN
            'refCond' => 'r.account_name = bugs.reported_by',    // Lookup condition for JOIN
            'refCol' => 'r.account_name',                        // Evaluated column name
            'type' => 'text',
        ),
        'assigned_to' => array(
            'title' => 'Assignee',
            'refTable' => array('a' => 'accounts'),              // Lookup table for JOIN
            'refCond' => 'a.account_name = bugs.reported_by',    // Lookup condition for JOIN
            'refCol' => 'a.account_name',                        // Evaluated column name
            'type' => 'text',
        ),
        'verified_by' => array(
            'title' => 'Verifier',
            'refTable' => array('v' => 'accounts'),              // Lookup table for JOIN
            'refCond' => 'v.account_name = bugs.reported_by',    // Lookup condition for JOIN
            'expr' => 'CONCAT(v.account_name)',                  // How an expression can also work
            'type' => 'text',
        ),
    );
    
    public function getKeyfields()
    {
        return $this->_keyfields;
    }

    public function selectDirectory()
    {
        $select = $this->getAdapter()->select();
    }
}

Controller
===========================================

$bugsModel = new Bugs();

$directory = new MyDirectory($bugsModel);
$director->setRequest($this->getRequest());                      // Uses request to determine page number, sort field, etc.

$this->view->directory = $directory;


View
===========================================

<? $key       = $this->directory->getKeyfields() ?>
<? $rows      = $this->directory->fetchDirectory() ?>
<? $sort      = $this->directory->getSort() ?>
<? $dir       = ($this->directory->getDir() == 'asc') ? 'desc' : 'asc' ?>
<? $cnt       = count($key) ?>
            <h1>List of bugs</h1>
            <table>
<? foreach ($key as $id => $field): ?>
                <col />
<? endforeach ?>
                <thead>
                    <tr>
<? foreach ($key as $id => $field): ?>
                        <th><a href="<?= $this->url(array('sort' => $id, 'dir' => ($sort == $id) ? $dir : 'asc')) ?>"><?= $this->escape($field['title']) ?></a></th>
<? endforeach ?>
                    </tr>
                </thead>
                <tbody>
<? if (count($rows)): ?>
<? foreach ($rows as $row): ?>
                    <tr>
<? foreach ($key as $id => $field): ?>
                        <td><?= $this->escape($row->$id) ?></td>
<? endforeach ?>
                    </tr>
<? endforeach ?>
<? else: ?>
                    <tr>
                        <td colspan="<?= $cnt ?>">No records found</td>
                    </tr>
<? endif ?>
                </tbody>
            </table>



--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" " """""" "" "
202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654 4124




Directory.zip (6K) Download Attachment