I was trying an example of one to many relationship in zend framework, but I can't get results.
Here are the tables:
UsersTable:
<?php
class Application_Model_DbTable_UsersTable extends Zend_Db_Table_Abstract
{
protected $_name = 'users';
protected $_dependentTables = array('Application_Model_DbTable_BugsTable');
}
BugsTable:
class Application_Model_DbTable_BugsTable extends Zend_Db_Table_Abstract
{
protected $_name = 'bugs';
protected $_dependentTables = array('Application_Model_DbTable_BugsProductsTable');
protected $_referenceMap = array(
'Reporter' => array(
'columns' => 'reported_by',
'refTableClass' => 'Application_Model_DbTable_UsersTable',
'refColumns' => 'username'
),
'Engineer' => array(
'columns' => 'assigned_to',
'refTableClass' => 'Application_Model_DbTable_UsersTable',
'refColumns' => 'username'
),
'Verifier' => array(
'columns' => array('verified_by'),
'refTableClass' => 'Application_Model_DbTable_UsersTable',
'refColumns' => array('username')
)
);
}
As you can see, this is one to many relationship from db table 'users' to table 'bugs' , where we have three foreign reference keys in bugs talbe.
Now when I try to use Zend methods for one to many relationships I always get empty results:
$tableUser = new Application_Model_DbTable_UsersTable();
$tableBugs = new Application_Model_DbTable_BugsTable();
$result= $tableUser->find(1);
$user= $result->current();
$userBugs = $user->findDependentRowset('Application_Model_DbTable_BugsTable','Verifier');
echo count($userBugs); //returns 0
$bugresult = $tableBugs->find(1);
$thisbug= $bugresult->current();
$verifier= $thisbug->findParentRow('Application_Model_DbTable_UsersTable','Verifier');
return $verifier //returns nothing
The proper data is in the database, when I for example do a query:
select * from bugs b, users u where b.reported_by=u.id and u.id=1;
I get the expected results. But when I try in zend no results.
Do you have any suggestions? Thanks.
In your sql u get bugs by field
reported_id
but in this code:
$result= $tableUser->find(1);
$user= $result->current();
$userBugs = $user->findDependentRowset('Application_Model_DbTable_BugsTable','Verifier');
echo count($userBugs); //returns 0
$bugresult = $tableBugs->find(1);
$thisbug= $bugresult->current();
$verifier= $thisbug->findParentRow('Application_Model_DbTable_UsersTable','Verifier');
return $verifier //returns nothing
u try to get bug by
verified_by
field
try this:
$result= $tableUser->find(1);
$user= $result->current();
$userBugs = $user->findDependentRowset('Application_Model_DbTable_BugsTable','Reporter');
echo count($userBugs);
Related
I have a tables named:
client (id, alias)
post (id, subject)
post_client (id, post_id, client_id)
Many clients can be joined to a post.
Using Zend DB Table abstract I have started to build a model, here are the classes:
ORM_Post
class ORM_Post extends Zend_Db_Table_Abstract {
protected $_name = 'Post';
protected $_dependentTables = array('ORM_Post_Client');
}
ORM_Client
class ORM_Client extends Zend_Db_Table_Abstract {
protected $_name = 'Client';
protected $_dependentTables = array(
'ORM_Post_Client'
);
}
ORM_Post_Client
class ORM_Post_Client extends Zend_Db_Table_Abstract {
protected $_name = 'Post_Client';
protected $_referenceMap = array(
'post' => array(
'columns' => 'post_id',
'refTableClass' => 'ORM_Post',
'refColumns' => 'id'
),
'client' => array(
'columns' => 'client_id',
'refTableClass' => 'ORM_Post_Client',
'refColumns' => 'id'
)
);
}
What I was hoping todo is call an instance of the Post and then load the clients associated aswell as loading an instance of the client and load all posts associated.
So I did this:
$post = new ORM_Post();
$results = $post->fetchAll();
foreach ($results as $key => $result){
$row = $results->current();
$client = $row->findDependentRowset('ORM_Post_Client','client');
}
and I get
Reference rule "client" does not reference table ORM_Post
I have battled with this for hours and cannot see where I'm going wrong. Am I to declare the Post_Client joins inside the client and post model also?
EDIT
Here is what I was after:
$post = new ORM_Post();
$results = $post->fetchAll();
$return = array();
foreach ($results as $result){
$row = $post->find($result->id)->current();
$return[$result->id] = $row->toArray();
$return[$result->id]['clients'] = $row->findManyToManyRowset('ORM_Client', 'ORM_Post_Client')->toArray();
}
return $return;
Thanks for the advice guys, you put me on the right track
in your ORM_Post_Client it should be
'client' => array(
'columns' => 'client_id',
'refTableClass' => 'ORM_Client', //instead of ORM_Post_Client
'refColumns' => 'id'
)
refTableClass => The class name of the parent table. Use the class
name, not the physical name of the SQL table (documentation)
also i think your loop should be :
foreach ($results as $result){
$row = $results->current();
$clients = $row->findDependentRowset('ORM_Post_Client','post');
}
because you are looking for clients of a post which means that post is your rule
($row->findDependentRowset($table, [$rule]); )
This as presented won't work, honestly it makes no sense.
$post = new ORM_Post();
$results = $post->fetchAll();
foreach ($results as $key => $result){
//$row is assigned to the whole fetchall result!
$row = $results->current();
//in this context $client cannot call a dependent rowset.
$client = $row->findDependentRowset('ORM_Post_Client','client');
}
MMc is correct in that you reference table definition was incorrect however your code has some issues as well. Maybe try something like:
$post = new ORM_Post();
$results = $post->fetchAll();
//unless your are going to use the 'key' for something you don't need it
foreach ($results as $result){
//you need each row object in order to call findDependentRowset in a one to many relationship.
$row = $post->find($result->id)->current();
//unless you have multiple rules set up for each table class pair you don't need to specify the rule.
$client = $row->findDependentRowset('ORM_Post_Client');
}
I have an entity setup called Lead which contains a car make, model, etc and this Lead is mapped by a Many to One relationship to a Client entity, which has forname, surname, etc.
i.e. A client may have many leads
I have created a toArray function which gets the data from the Lead,
public function toArray()
{
$record_data = get_object_vars($this);
$formatted_record_data = array();
foreach($record_data as $name=>$value){
if (is_object($value)){
if (get_class($value) == 'DateTime') {
$value = $this->datetimeToString($value);
} else {
$value = $value->toArray();
}
}
$formatted_record_data[$this->from_camel_case($name)] = $value;
}
return $formatted_record_data;
}
which then populates a Zend Form using:
$record = $this->_em->getRepository($this->_entity)->find($this->_primaryId);
$form->setDefaults($record->toArray());
This works fine for the fields for the Lead entity which are populated, but it does not populate the Client-based fields e.g. forname.
EDIT
I have fixed my problem by the following method:
1) Adding the following method to my Update Action.
$this->_record = $this->_em->getRepository($this->_entity)->find($this->_primaryId);
$this->_form->setRecord($this->_record);
$this->view->form = $this->_form;
2) Adding the following method to my Form Model
public function setRecord($record)
{
$data = array('registration' => $record->registration,
'make' => $record->make,
'model' => $record->model,
'pav' => $record->pav,
'salvage_value' => $record->salvageValue,
'forname' => $record->client->forname,
'surname' => $record->client->surname,
'vehicle_address1' => $record->vehicleAddress1,
'vehicle_address2' => $record->vehicleAddress2,
'vehicle_address3' => $record->vehicleAddress3,
'vehicle_address4' => $record->vehicleAddress4,
'vehicle_address5' => $record->vehicleAddress5,
'vehicle_postcode' => $record->vehiclePostcode,
'category' => $record->category,
'colour' => $record->colour
);
$this->setDefaults($data);
}
This way I can manually get the related data, in this case:
'forname' => $record->client->forname,
'surname' => $record->client->surname,
and add them to the form using:
$this->setDefaults($data);
try :
$leads = $record->toArray();
$client_info = array('name' => 'test', 'surname' => 'test 2'); // or if from db use what you did for the leads.
$defaults = array_merge($leads, $client_info);
$form->setDefaults($defaults);
I know there are some examples in the web, but doesn't work in my case.
I have a Category table with subcategories. One table 'category' that has id_father that's the id of the Parent Category.
My configuration is the following:
Application_Model_DbTable_Category:
protected $_referenceMap = array(
'Application_Model_DbTable_Category' => array(
'columns' => 'id_father',
'refColumns' => 'id',
'refTableClass' => 'Application_Model_DbTable_Category'
));
CategoryMapper (I don't write the top code, anyway I retrieve a Category that has a parent in the db)
$row = $result->current();
echo $row->name;
$father = 'Non trovato';
$father = $row->findParentRow('Application_Model_DbTable_Category');
print_r($father);
This doesn't print anything... Is something wrong on my code? Thank you
you need to create instance of class Application_Model_DbTable_Category
$row = $result->current();
echo $row->name;
$father = 'Non trovato';
$father = $row->findParentRow(new Application_Model_DbTable_Category());
print_r($father);
I have three two classess
class Application_Model_Accounts extends Zend_Db_Table_Abstract
{
protected $_name = 'accounts';
protected $_dependentTables = array('Application_Model_Bugs');
}
And
class Application_Model_Bugs extends Zend_Db_Table_Abstract
{
protected $_name = 'bugs';
protected $_dependentTables = array('Application_Model_BugsProducts');
protected $_referenceMap = array(
'Reporter' => array(
'columns' => 'reported_by',
'refTableClass' => 'Application_Model_Accounts',
'refColumns' => 'account_name'
),
'Engineer' => array(
'columns' => 'assigned_to',
'refTableClass' => 'Application_Model_Accounts',
'refColumns' => 'account_name'
),
'Verifier' => array(
'columns' => array('verified_by'),
'refTableClass' => 'Application_Model_Accounts',
'refColumns' => array('account_name')
)
);
}
in index controll i am trying to run this code.
public function indexAction()
{
$accountsTable = new Application_Model_Accounts();
$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();
$bugsReportedByUser = $user1234->findDependentRowset('Application_Model_Bugs');
}
and on line
$bugsReportedByUser = $user1234->findDependentRowset('Application_Model_Bugs');
I am getting this error
An error occurred
Application error
I am unable to findout the problem. How to fix this problem. and is there a way to get more developer friendly error in Zend rather then just getting this message "An error occured".
I figure out the solution for this problem.
in .Htaccess file
enable the development mode by adding this line on top
SetEnv APPLICATION_ENV "development"
This will show the complete error trace.
Sorted
full working example of bugs code including db available here
http://phphints.wordpress.com/2010/06/25/zend-framework-finddependentrowset-and-findparentrow-demo/
This is my first time using Zend Framework for an application and i don't know if I completely have by head around Models.
I have four tables: shopping_cart, product, product_unit, distributor.
shopping cart has an cart_id, product_id, unit_id and dist_id (shopping cart joins on the other tables with their corresponding id).
Before Zend I would create a class like this:
class ShoppingCart
{
function getItems()
{
$sql ="select * from shopping_cart, product, product_unit, distributor
where
shopping_cart.product_id = product.id AND
shopping_cart.unit_id = product_unit.id AND
shopping_cart.dist_id = distributor.id AND
cart_id = xxx";
$items = $this->db->getAll($sql);
}
One query to get all the information from the joined tables.
When I set up the relationship mapping in Zend_Db_Table_Abstract:
My Shopping Cart Model:
class Application_Model_ShoppingCart
{
function __construct()
{
$this->ShoppingCartTable = new Application_Model_DbTable_ShoppingCart();
}
function getItems()
{
$cart_items = $this->ShoppingCartTable->getItems($this->GetCartId());
return $cart_items;
}
}
class Application_Model_DbTable_ShoppingCart extends Zend_Db_Table_Abstract
{
protected $_name = 'shopping_cart';
protected $_rowClass = 'Application_Model_DbTable_ShoppingCart_Item';
protected $_referenceMap = array(
'Product' => array(
'columns' => 'product_id',
'refTableClass' => 'Application_Model_DbTable_Product',
'refColumns' => 'id'
),
'Distributor' => array(
'columns' => 'dist_id',
'refTableClass' => 'Application_Model_DbTable_Distributor',
'refColumns' => 'id'
),
'Unit' => array(
'columns' => 'unit_id',
'refTableClass' => 'Application_Model_DbTable_ProductUnit',
'refColumns' => 'id'
)
);
public function getItems($cart_id)
{
$where = $this->getAdapter()->quoteInto('cart_id = ?', $cart_id);
return $this->fetchAll($where);
}
}
In my controller:
$this->_shoppingCartModel = new Application_Model_ShoppingCart();
$items = $this->_shoppingCartModel->getItems();
IN my view :
foreach($this->items AS $item)
{
$item_product = $item->findParentRow('Application_Model_DbTable_Product');
$item_dist = $item->findParentRow('Application_Model_DbTable_Distributor');
$item_unit = $item->findParentRow('Application_Model_DbTable_ProductUnit');
}
when I have ten items in my cart the db profiler shows over sixty queries (WHOA) to view the cart items ( information across all four tables are displayed - product name, unit description, distributor name).
For each item it queries the shopping_cart, then querys the product table, then the product unit, then the distributor_table.
Is there a way to have this run as one query joining all the tables via Zend_Db_Table_Abstract relationships?
Will I have to go back to using db adapter in the my Application_Model_ShoppingCart class?
I want to abstract all data access to the table models (Application_Model_DbTable_ShoppingCart) and not have the Application_Model_ShoppingCart tied to a db handler.
Thanks in advance for advice, I love the Zend Framework but models are still hard for me to understand given the different conflicting ways people talk about using them.
In short, no, unfortunately it's not possible to get a set of table rows together with their relationships in a single query.
It's just that all methods dealing with relationships are defined for a row, not for a table.
But at least, you can form your sql with Zend_Db_Table_Select instead of writing it all manually.
Upd: Your code for fetching ShoppingCarts, in my opinion, should belong to the table (DbTable_ShoppingCart). So, the code you provided in the beginning could be transformed to the following:
class Application_Model_DbTable_ShoppingCart extends Zend_Db_Table_Abstract {
public function getItem($cart_id) {
$select = $this->select()
->from( array('sc' => 'shopping_cart'), array(Zend_Db_Select::SQL_WILDCARD) )
->join( array('p' => 'product'), 'sp.product_id = p.id', array(Zend_Db_Select::SQL_WILDCARD) )
->join( array('pu' => 'product_unit'), 'sp.unit_id = pu.id', array(Zend_Db_Select::SQL_WILDCARD) )
->join( array('d' => 'distributor'), 'sp.dist_id = d.id', array(Zend_Db_Select::SQL_WILDCARD) )
->where('sp.cart_id = ?', $cart_id)
->setIntegrityCheck(false);
return $this->fetchAll($select);
}
}