missing FROM-clause entry for table "Grupo" cakephp - postgresql

hi i have aproblem in my code, I want generate a list of user but this have a group and need just a group of user.
the error say:
Error: SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "Grupo"
this is my code:
public function add()
{
$this->loadModel('SoyaProveedor');
$this->loadModel('Soya');
$this->set('oleaginosas', $this->Soya->find('list', array(
'fields'=> array('id','username'),
'conditions' => array('Grupo.categoria' => 'Soya' , 'Grupo.subcategoria' => 'Productor de Oleaginosas')
)));
if ($this->request->is('post')) {
$this->request->data['SoyaProveedor']['nombre'] = strtoupper($this->request->data['SoyaProveedor']['nombre']);
$this->request->data['SoyaProveedor']['codigo'] = strtoupper($this->request->data['SoyaProveedor']['codigo']);
if ($this->SoyaProveedor->save($this->request->data)) {
$this->Session->setFlash(__('La InformaciĆ³n fue Guardada.'));
return $this->redirect(array('action' => 'index'));
}
}
}
the sql query of the cake generate it:
SQL Query: SELECT "Soya"."id" AS "Soya__id", "Soya"."username" AS
"Soya__username" FROM "public"."users" AS "Soya" WHERE
"Grupo"."categoria" = 'Soya' AND "Grupo"."subcategoria" = 'Productor
de Oleaginosas'

You need the grupos table to be joined in the query, your query in the question has no joins. There are a number of simple solutions.
Define recursive.
Recursive is a very coarse control of what joins and queries are executed, by default find('list') has a recursive value of -1.
-1 means no joins, which is why there is no join in the resultant query. Setting it to a value of 0 adds a join to the main query for all hasOne and belongsTo associations.
Be wary of using/relying on recursive as it's very easy to generate queries with joins you don't need - and/or triggering many subsequent queries for related data (if set to a value larger than 0).
However this find call:
$data = $this->Soya->find('list', array(
'fields'=> array('Soya.id','Soya.username'),
'recursive' => 0, // added
'conditions' => array(
'Grupo.categoria' => 'Soya' ,
'Grupo.subcategoria' => 'Productor de Oleaginosas'
)
));
Should result in this query (If the Soya model has a belongsTo association to Grupo):
SELECT
"Soya"."id" AS "Soya__id",
"Soya"."username" AS "Soya__username"
FROM
"public"."users" as "Soya"
LEFT JOIN
"public"."Grupos" as "Grupo" on ("Soya"."grupo_id" = "Grupo"."id")
...
Possibly more joins
...
WHERE
"Grupo"."categoria" = 'Soya'
AND
"Grupo"."subcategoria" = 'Productor de Oleaginosas'
Or Use containable
The containable behavior allows better control of what queries are executed. Given the info in the question to use it that means:
<?php
class Soya extends AppModel {
// Assumed from information in the question
public $useTable = 'users';
public $belongsTo = array('Grupo');
// added
public $actsAs = array('Containable');
}
Will permit you to do the following in your controller:
$data = $this->Soya->find('list', array(
'fields'=> array('Soya.id','Soya.username'),
'contain' => array('Grupo'), // added
'conditions' => array(
'Grupo.categoria' => 'Soya' ,
'Grupo.subcategoria' => 'Productor de Oleaginosas'
)
));
Which will generate the following query (exactly one join):
SELECT
"Soya"."id" AS "Soya__id",
"Soya"."username" AS "Soya__username"
FROM
"public"."users" as "Soya"
LEFT JOIN
"public"."Grupos" as "Grupo" on ("Soya"."grupo_id" = "Grupo"."id")
WHERE
"Grupo"."categoria" = 'Soya'
AND
"Grupo"."subcategoria" = 'Productor de Oleaginosas'

Link your models together using associations: CakePHP Associations
Alternatively you can use custom sql-statemens using join e.g.:
$db = $this->getDataSource();
$result = $db->fetchAll(
"SELECT Soya.id AS Soya__id, Soya.username AS Soya__username FROM public.users AS Soya
join Grupo on Grupo.id = Soya.groupo_id
WHERE Grupo.categoria = ? AND Grupo.subcategoria = ?",
array('Soya', 'Productor de Oleaginosas')
);
$this->set('oleaginosas', $result);

Related

Security Group subpanel doesn't exist for quotes, contrats, invoices, and events modules

I am using suiteCRM 7.7.4 (Sugar Version 6.5.24) and I need to use Security group subpanel in quotes, contracts, invoices and events modules, but for some reasons I can't find it ! I did some researches and I found that this subpanel doesn't appear by default for custom modules.. some developers recommand to do not use the studio to build this kind of relationship, because simply it will not work ! for paid version of sugarCRM they say that there was a tool called "hookup tool" that creates the relationship for you... but As I am using a free version I can't use it !
Do you have any idea ?
Thank you very much !
I finaly find a solution :
Adding this few lines to "modules/AOS_Contracts/metadata/subpaneldefs.php" :
'securitygroups' => array(
'top_buttons' => array(array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'SecurityGroups', 'mode' => 'MultiSelect'),),
'order' => 900,
'sort_by' => 'name',
'sort_order' => 'asc',
'module' => 'SecurityGroups',
'refresh_page' => 1,
'subpanel_name' => 'default',
'get_subpanel_data' => 'SecurityGroups',
'add_subpanel_data' => 'securitygroup_id',
'title_key' => 'LBL_SECURITYGROUPS_SUBPANEL_TITLE',
),
QRR
Verifying permissions.
follow this following steps:
1. Go to Admin
2. Go to studio
3. Select your module where you want subpanel like "invoices"
4. Go to relationship
5. Add 1 to many relationship with Security group module.
6. Now repair rebuild you will find the subapnel in invoice module.
When you create 1 to many relationship with any module it will create the subpanel.
IF its not working then go for custom subpanel.
Refer this linnk I put code from same link it worked for me
This tutorial should hopefully help you to create a new subpanel under the Contacts module in Sugar using a custom link class and driven by SugarCRM 7's new SugarQuery API.
Create a new link class
This should go into custom/modules/<YourModule>/YourNewLink.php and this class will act as the custom functionality that will build your link between the two records.
<?php
/**
* Custom filtered link
*/
class YourNewLink extends Link2
{
/**
* DB
*
* #var DBManager
*/
protected $db;
public function __construct($linkName, $bean, $linkDef = false)
{
$this->focus = $bean;
$this->name = $linkName;
$this->db = DBManagerFactory::getInstance();
if (empty($linkDef)) {
$this->def = $bean->field_defs[$linkName];
} else {
$this->def = $linkDef;
}
}
/**
* Returns false if no relationship was found for this link
*
* #return bool
*/
public function loadedSuccesfully()
{
// this link always loads successfully
return true;
}
/**
* #see Link2::getRelatedModuleName()
*/
public function getRelatedModuleName()
{
return '<Your_Module>';
}
/**
*
* #see Link2::buildJoinSugarQuery()
*/
public function buildJoinSugarQuery($sugar_query, $options = array())
{
$joinParams = array('joinType' => isset($options['joinType']) ? $options['joinType'] : 'INNER');
$jta = 'active_other_invites';
if (!empty($options['joinTableAlias'])) {
$jta = $joinParams['alias'] = $options['joinTableAlias'];
}
$sugar_query->joinRaw($this->getCustomJoin($options), $joinParams);
return $sugar_query->join[$jta];
}
/**
* Builds main join subpanel
* #param string $params
* #return string JOIN clause
*/
protected function getCustomJoin($params = array())
{
$bean_id = $this->db->quoted($this->focus->id);
$sql = " INNER JOIN(";
$sql .= "SELECT id FROM accounts WHERE id={$bean_id}"; // This is essentially a select statement that will return a set of ids that you can match with the existing sugar_query
$sql .= ") accounts_result ON accounts_result.id = sugar_query_table.id";
return $sql;
}
}
The argument $sugar_query is a new SugarQuery object, the details of which are documented here. What you essentially need to do is extend this query with whatever join/filters you wish to add. This is done in the inner join I've specified.
Note: The inner join can get really complicated, so if you want a real working example, checkout modules/Emails/ArchivedEmailsLink.php and how the core sugar team use this. I can confirm however that this does work with custom joins.
Here is the getEmailsJoin to help you understand what you can actually produce via this custom join.
/**
* Builds main join for archived emails
* #param string $params
* #return string JOIN clause
*/
protected function getEmailsJoin($params = array())
{
$bean_id = $this->db->quoted($this->focus->id);
if (!empty($params['join_table_alias'])) {
$table_name = $params['join_table_alias'];
} else {
$table_name = 'emails';
}
return "INNER JOIN (\n".
// directly assigned emails
"select eb.email_id, 'direct' source FROM emails_beans eb where eb.bean_module = '{$this->focus->module_dir}'
AND eb.bean_id = $bean_id AND eb.deleted=0\n" .
" UNION ".
// Related by directly by email
"select DISTINCT eear.email_id, 'relate' source from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
ON eabr.bean_id = $bean_id AND eabr.bean_module = '{$this->focus->module_dir}' AND
eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0\n" .
") email_ids ON $table_name.id=email_ids.email_id ";
}
Add a new vardef entry for the link field.
For this example, I'm going to create the custom link on the contacts module. So this code goes in custom/Extension/modules/Contacts/Ext/Vardefs/your_field_name.php
<?php
$dictionary["Contact"]["fields"]["your_field_name"] = array(
'name' => 'active_other_invites',
'type' => 'link',
'link_file' => 'custom/modules/<YourModule>/YourNewLink.php',
'link_class' => 'YourNewLink',
'source' => 'non-db',
'vname' => 'LBL_NEW_LINK',
'module' => '<YourModule>',
'link_type' => 'many',
'relationship' => '',
);
Add the new link as a subpanel
This goes under custom/Extension/modules/Contacts/Ext/clients/base/layouts/subpanels/your_subpanel_name.php
<?php
$viewdefs['Contacts']['base']['layout']['subpanels']['components'][] = array (
'layout' => 'subpanel',
'label' => 'LBL_NEW_LINK',
'context' =>
array (
'link' => 'your_field_name',
),
);
Add the label
Under
custom/Extension/modules/Contacts/Ext/Language/en_us.new_link.php
<?php
$mod_strings['LBL_ACTIVE_OTHER_INVITES'] = 'Your New Link';
Quick Repair and Rebuild
That should hopefully get you started. Keep an eye on the sugarlogs while you're debugging your queries. I also found using xdebug and SugarQueries compileSql function invaluable in figuring out what I needed to do to get a working INNER JOIN statement.
I've found this to be a surprisingly powerful solution, it means that if you need to show information related to a module that might be a few joins away, this allows you to create the links manually without having to create pointless related fields in-between the two.

zf1: chained joins

I'm getting an error with a query, my question is: can i chain joins?
My first join is to the primary table, but my second join is to the table joined to the primary table. This is the query:
$query = $this->getDbTable()->select()
->from(array('ca' => 'contracts_allotment'),
array('id',
'contracts_rooms_id' => new Zend_Db_Expr("CONCAT(room_type_desc, '-', room_characteristics_desc)")
))
->join(array('cr' => 'contracts_rooms'),
'ca.contract_rooms_id = cr.id',
array())
->join(array('rt' => 'room_types'),
'cr.room_id = rt.id',
array('room_type_desc'))
->join(array('rc' => 'room_characteristics'),
'cr.char_id = rc.id',
array('room_characteristics_desc'))
->where('contract_id = ?', $contractId);
var_dump($this->getDbTable()->fetchAll($query));die;
I'm getting:
Select query cannot join with another table"
The error comes from Zend/Db/Table/Select::assemble()
Here you have some inside assemble():
// Check each column to ensure it only references the primary table
if ($column) {
if (!isset($from[$table]) || $from[$table]['tableName'] != $primary) {
var_dump($from[$table]['tableName'], $primary);die;
require_once 'Zend/Db/Table/Select/Exception.php';
throw new Zend_Db_Table_Select_Exception('Select query cannot join with another table');
}
}
The var_dump() prints:
string(10) "room_types" string(19) "contracts_allotment"
Any idea?
Don't forget to lock the tables when doing joins:
$query = $this->getDbTable()->select()
->setIntegrityCheck(false)
->from(array('ca' => 'contracts_allotment'),
array('id',
'contracts_rooms_id' => new Zend_Db_Expr("CONCAT(room_type_desc, '-', room_characteristics_desc)")
))
->join(array('cr' => 'contracts_rooms'),
'ca.contract_rooms_id = cr.id',
array())
->join(array('rt' => 'room_types'),
'cr.room_id = rt.id',
array('room_type_desc'))
->join(array('rc' => 'room_characteristics'),
'cr.char_id = rc.id',
array('room_characteristics_desc'))
->where('contract_id = ?', $contractId);
->setIntegrityCheck(false) should at least get you a new error.

Zend Framework Query with Joins

I am trying to replicate this query using zend framework:
SELECT
activitytype.description,
activity.datecompleted
FROM
clientactivity
INNER JOIN activity
ON activity.activityID = clientactivity.activityid
INNER JOIN activitytype
ON activitytype.activitytypeid = activity.activitytypeid
WHERE
clientactivity.clientid = 100
This is what I have so far:
$select = $dbTable->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false);
$select->where('clientactivity.clientid = ?', $clientID);
$select->join('activity', 'activity.activityid = clientactivity.activityid');
$select->join('activitytype', 'activitytype.activitytypeid = activity.activitytypeid');
$select->columns(array('activitytype.description', 'activity.datecompleted'));
I seem to be having problems with the columns option, it doens't seem to be limiting the columns and I am ending up with
clientactivity.* etc in the column list in the query.
What am I doing wrong?
Thanks,
Martin
Try instead of the $select->columns();
$select->from('activitytype.description', 'activity.datecompleted');
Reference - http://framework.zend.com/manual/en/zend.db.select.html
UPDATE:
This example makes us of a generic database handler:
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'yourusername',
'password' => 'somepassword',
'dbname' => 'yourdbname'
));
$select = $db->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->from('tableName','fieldName')
->join('joinTable', 'joinTable.keyId = tableName.keyId',array())
->where('tableName.userId = ?', $userId);
$resultSet = $db->fetchAll($select);
The key piece is the blank array at the end of the join statements that specifies no records to be returned from the joined table.

$_referenceMap Relationships with Zend_Db_Table_Abstract creates too many queries

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);
}
}

Zend_Db_Table fetchAll and column names

I'm testing Zen_DB and Zend_DB_Table and I'm facing a problem:
Let's say I've got two tables
table A(id, title)
table B(id, title)
If I write something like
$db = $this->getDbTable()->getAdapter();
$query = "SELECT A.*, B.* FROM A INNER JOIN B on A.id = B.id"
$stmt = $db->query($query);
$rows = $stmt->fetchAll();
each resulting row is like ['id' => value, 'title' => value]
Question: How can the fetched rows be like ['A.id' => value, 'A.title' => value', 'B.id' => value, 'B.title' => value'] ?
Important: I don't want to modify the database schema
Your question was answered by this question