I'm trying to add two fields (Shipping Postcode and Billing Postcod) to Magento 1.7CE's backend Sales grid.
I'm doing this by overriding Mage_Adminhtml_Block_Sales_Order_Grid::setCollection(...) to join the table with sales/order_address.
public function setCollection($collection){
parent::setCollection($collection);
$collection->getSelect()->join(
array('address_shipping' => $collection->getTable("sales/order_address")),
'main_table.entity_id = address_shipping.parent_id AND address_shipping.address_type = "shipping"',
array('postcode')
);
$collection->getSelect()->join(
array('address_billing' => $collection->getTable("sales/order_address")),
'main_table.entity_id = address_billing.parent_id AND address_billing.address_type = "billing"',
array('postcode')
);
}
And Mage_Adminhtml_Block_Sales_Order_Grid::_prepareColumns(...) to add the columns to Sales Grid.
protected function _prepareColumns(){
$this->addColumn('shipping_postcode', array(
'header' => Mage::helper('sales')->__('Shipping Postcode'),
'index' => 'postcode',
));
$this->addColumn('billing_postcode', array(
'header' => Mage::helper('sales')->__('Billing Postcode'),
'index' => 'postcode',
));
return parent::_prepareColumns();
}
The issue is that both times I need to select postcode field from sales/order_address table which results in SQL error
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'postcode' in order clause is ambiguous
I have tried to use MySQL's AS alias to differentiate between two postcodes, by modifying setCollection(...) to pass array('shipping_postcode'=>'postcode') and array('billing_postcode'=>'postcode') as well as changing _prepareColumns(...) to say 'index' => 'shipping_postcode' and 'index' => 'billing_postcode'. This resulted in another SQL error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'shipping_postcode' in 'where clause'
How can I achieve having both columns in the Sales Grid?
let try this first code
public function setCollection($collection){
parent::setCollection($collection);
$collection->getSelect()->join(
array('address_shipping' => $collection->getTable("sales/order_address")),
'main_table.entity_id = address_shipping.parent_id AND address_shipping.address_type = "shipping"',
array('address_shipping.postcode as shippingpostcode')
);
$collection->getSelect()->join(
array('address_billing' => $collection->getTable("sales/order_address")),
'main_table.entity_id = address_billing.parent_id AND address_billing.address_type = "billing"',
array('address_billing.postcode as billingpostcode')
);
}
Second _prepareColumns() is here,
protected function _prepareColumns(){
$this->addColumn('shippingpostcode', array(
'header' => Mage::helper('sales')->__('Shipping Postcode'),
'index' => 'shippingpostcode',
'filter_index' => 'address_shipping.postcode'
));
$this->addColumn('billingpostcode', array(
'header' => Mage::helper('sales')->__('Billing Postcode'),
'index' => 'billingpostcode',
'filter_index' => 'address_billing.postcode'
));
return parent::_prepareColumns();
}
if you want to know more about 'filter_index', comment in/out in this, then try sorting in your grid for post code column. You will see different result. If you remove filter_index, error in sorting.
Before return parent::_prepareCollection();
You should create a join:
$collection->getSelect()->joinLeft(array('billing'=>'sales_flat_order_address'),
'main_table.entity_id = billing.parent_id AND billing.address_type="billing"',array('billing.postcode AS bp'));
And in the method _prepareColumns paste:
$this->addColumn('bp', array(
'header' => Mage::helper('sales')->__('Billing Postcode'),
'index' => 'bp',
'width' => '60px',
'filter_index' => 'billing.postcode'
));
Related
I`ve been trying to setup my migrate module for a while without any success to associate taxonomy terms to node.
Lets first start by saying, its not D2D migration, source is old symfony database!
First I`ve exported taxonomy terms successfuly:
*-.migrate.inc:
...
'symfony_db_countries' => array(
'class_name' => 'MigrateSymfonyCountriesMigration',
'group_name' => 'symfony_db_loc',
),
'symfony_db_cities' => array(
'class_name' => 'MigrateSymfonyCitiesMigration',
'group_name' => 'symfony_db_loc',
'dependencies' => array('symfony_db_countries'),
),
'symfony_db_sights' => array(
'class_name' => 'MigrateSymfonySightsMigration',
'group_name' => 'symfony_db_loc',
),
...
Cities.inc:
class MigrateSymfonyCitiesMigration extends MigrateSymfonyCitiesMigrationBase {
const TABLE_NAME = 'ya_loc_city';
public function __construct($arguments = array()) {
parent::__construct($arguments);
$this->description = t('Migrate cities from Symfony DB.');
$query = Database::getConnection('symfony', 'default')->select('ya_loc_city', 'c');
$query->leftJoin('ya_loc_city_translation', 'ct', 'ct.id = c.id');
$query->fields('c', array());
$query->fields('ct', array());
$this->source = new MigrateSourceSQL($query, array(), NULL, array('map_joinable' => FALSE));
$this->destination = new MigrateDestinationTerm('cities');
$this->map = new MigrateSQLMap($this->machineName,
array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'City ID',
),
),
MigrateDestinationTerm::getKeySchema()
);
$this->addFieldMapping('name', 'name');
$this->addFieldMapping('parent', 'country_id')->sourceMigration('symfony_db_countries');
}
}
Then Im creating nodes from another table, which have a entityReference field (field_city) to the taxonomy term.
<?php
class MigrateSymfonySightsMigration extends Migration {
public function prepareRow($row) {
parent::prepareRow($row);
$row->point = 'point (' . $row->longitude . ' ' . $row->latitude. ')';
}
public function __construct($arguments = array()) {
//entry is the name of a group.
parent::__construct($arguments);
$this->description = 'Migration sights';
/*************SOURCE DATA*************/
...
$this->source = new MigrateSourceSQL($query, array(), NULL,
array('map_joinable' => FALSE));
$this->destination = new MigrateDestinationNode('sight');
/*************MAPPING*************/
$this->addFieldMapping('field_city', 'name')->sourceMigration('symfony_db_cities');
$this->map = new MigrateSQLMap($this->machineName,
array(
'id' => array('type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
)
),
MigrateDestinationNode::getKeySchema()
);
}
}
From symfony table there is a column "name", which contains the city name like "Paris".
How to associate this column ('name') value ('Paris') with taxonomy term? Following doesnt work:
$this->addFieldMapping('field_city', 'name')->sourceMigration('symfony_db_cities');
Firstly, make sure your "field_city" field accepts "cities" terms.
Then make sure MigrateSymfonyCitiesMigration is a dependency of MigrateSymfonySightsMigration.
According to the documentation, the term reference field migration has a "source_type" of term name by default. Make sure "ignore_case" is set appropriately.
If all else fails, then change the MigrateSymfonyCitiesMigration map sourceid1 to the "name" instead of "id" and try again (will have to reregister migration):
$this->map = new MigrateSQLMap($this->machineName,
array(
'name' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'City Name',
),
),
MigrateDestinationTerm::getKeySchema()
);
In my GridView I want to display all records of my table 'reply'. The table has relations to the tables 'author' and 'task' and not every reply has a task.
The table 'task' has a relation with another table called 'concern'.
Here ist the relations() of my model Reply:
public function relations() {
return array(
'trak' => array(self::HAS_MANY, 'Task', 'reply_id', 'condition' => 'task.deleted<>1'),
'author' => array(self::BELONGS_TO, 'Author', 'author_id'),
);
}
The search() method of my model Reply has the following code:
public function search() {
$criteria = new CDbCriteria;
$criteria->with = array(
'author' => array('select' => 'id, name, role, office_id, abk', 'together' => false),
'author.office' => array('select' => 'id, name'),
'task' => array('select' => 'id, concern_id', 'together' => true),
'task.concern' => array('select' => 'id, classification_id', 'alias' => 'concern'),
);
$criteria->compare('t.id', $this->id);
$criteria->compare('t.create_time', $this->create_time);
$criteria->compare('t.create_date', $this->create_date, true);
$criteria->compare('t.office.id', $this->search_office);
$criteria->compare('t.author_id', $this->author_id);
$criteria->compare('t.rel', $this->rel, true);
$criteria->compare('t.author_id', $this->author_id);
$criteria->compare('t.lektor_id', $this->lektor_id);
$criteria->compare('t.issue_id', $this->issue_id);
$criteria->compare('t.reply_text', $this->reply_text, true);
$criteria->compare('t.deleted', $this->deleted);
if (EWMParam::getValue(EWMParam::MODUL_SCHLAGWORTE))
$criteria->compare('t.tags', $this->tags, true);
$criteria->compare('t.text_name', $this->text_name, true);
$criteria->compare('t.use_count', $this->use_count);
$criteria->compare('concern.classification_id', $this->classification_id);
$criteria->compare('t.update_time', $this->update_time);
$criteria->compare('t.update_user', $this->update_user);
$criteria->compare('t.global', $this->global);
if (EWMParam::getValue(EWMParam::MODUL_confirmationN))
$criteria->compare('t.confirmation', $this->confirmation);
$criteria->compare('t.confirmation_text', $this->confirmation_text, true);
$criteria->compare('t.use', $this->use, true);
$pagination = EWMPageSortFilterHelper::getPagination($this);
$sort = new CSort();
$sort->defaultOrder = 't.id DESC';
$sort->attributes = array(
'global' => 't.global',
'search_office' => 'office.name',
'id' => 't.id',
'text_name' => 't.text_name',
'confirmation' => 't.confirmation',
'author_id' => 'author.name',
'create_date' => 't.create_date',
'tags' => 't.tags',
'use' => 't.use',
'classification_id' => 'classification_id',
);
$sort->applyOrder($criteria);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
'pagination' => $pagination,
'sort' => $sort
));
}
In my GridVew only replys with a task are displayed and all filters work fine. But I want to display all replys with a task and all replys without a task. If I
delete in the search() method in the array for $criteria->with the elements 'task' and 'task.concern' all replys are displyed. But the filter for the row
'Classifcation' which comes from the relation 'task.concern' doesn't work. Logically I get the error "Column not found: 1054 Unknown column 'concern.classification_id' in 'where clause'".
Is it possible to display all replys and to filter those replys by the classification? Do you have an idea?
You should look into how Yii relations work.
One thing that comes into my mind is that when adding the relations in the with() property the SQL generated might include INNER JOINs.
That's why when having the relations included you're not getting any reply without tasks.
In order to fix that you should make sure that the SQL generated is using LEFT JOINs.
You can do that by using joinType property of a relation:
http://www.yiiframework.com/doc/api/1.1/CActiveRelation#joinType-detail
And you could specify LEFT JOIN there.
'task' => array('select' => 'id, concern_id', 'together' => true, 'joinType'=>'LEFT JOIN'),
'task.concern' => array('select' => 'id, classification_id', 'alias' => 'concern', 'together' => true, 'joinType'=>'LEFT JOIN'),
That might do the trick. But maybe you need some more tweaking if it is not working just as expected.
If you want to debug what is actually happening, you could put a bad field/table name inside the criteria that would result in a database error and then you can look in the SQL code that was executed and see how tables are joined.
Suggested links:
http://www.yiiframework.com/doc/guide/1.1/en/database.arr
http://www.yiiframework.com/wiki/527/relational-query-lazy-loading-and-eager-loading-with-and-together/
http://www.yiiframework.com/wiki/428/drills-search-by-a-has_many-relation
I have simple CGridView, which is not showing me any data at all.
I've logged query built by CDbCriteria and there was some LIKE conditions which uses mysql default field values, so MySQL searches for entries with default values in required fields.
Since I have none entries matching this condidion it returns 0 rows. But the thing is, I don't need these LIKEs. Is there a way to disable it?
Here's the view:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
array(
'name' => 'name',
'type' => 'raw',
'value' => 'CHtml::encode($data->name)'
),
array(
'name' => 'email',
'type' => 'raw',
'value' => 'CHtml::link(CHtml::encode($data->email), "mailto:".CHtml::encode($data->email))',
),
),
));
Controller:
public function actionUsers() {
$model = new Users();
$this->renderPartial('users',array(
'model' => $model,
));
}
Function Search of model Users:
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
'sort'=>array(
'defaultOrder'=>'user ASC',
),
'pagination'=>array(
'pageSize'=>5
),
));
And Logged Query:
SELECT * FROM `users` `t` WHERE (((((email LIKE :ycp0) AND (`group` LIKE :ycp1)) AND (gender LIKE :ycp2)) AND (city LIKE :ycp3)) AND (name LIKE :ycp4)) AND (av_url LIKE :ycp5) ORDER BY `t`.`name` LIMIT 5. Bound with :ycp0='%NotSet%', :ycp1='%3%', :ycp2='%Secret%', :ycp3='%NotSet%', :ycp4='%NotSet%', :ycp5='%noav.jpg%'
I am new to Stackoverflow and don't have sufficient reputation to post a comment, otherwise I would have asked that you share more information on how you configure your CDbCriteria object in your $model->search() function.
But, I suspect that you are using partial matches in the compare method, which can be disabled by passing false in the $partialMatch parameter as follows:
$criteria = new CDbCriteria;
$criteria->compare('email', $someValue, false);
Or, since false is the default value, you can simple write:
$criteria->compare('email', $someValue);
I have this search using joins. The results are correct but yii grid does not show all of the results even if the pagesize selected is greater than number of result.
here's my code :
if($_GET['BaseIar']['description'] !='empty'){
$criteria->with = array('class','classSi',);
$this->description=$_GET['BaseIar']['description'];
$criteria->compare('class.description', $this->description, true);
$criteria->compare('classSi.description', $this->description, true, 'OR');
}
here are the relations:
public function relations() {
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'class' => array(self::HAS_ONE, 'BaseEiEquipItem', 'iar_no'),
'classSi' => array(self::HAS_ONE, 'BaseSiReceivedItem','iar_no'),
);
}
here's the grid:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'base-iar-grid',
'dataProvider'=>$searchModel->search(),
'columns'=>array(
array(
'class'=>'CCheckBoxColumn',
'id'=>'base-iar-id',
'selectableRows'=>2, // multiple rows can be selected
),
'iar_id',
'dateInspected',
array(
'name'=>'inspectedBy',
'value'=>'(!empty($data->inspectedBy))?$data->inspectedBy0->person->lastName.", ".$data->inspectedBy0->person->firstName." ".$data->inspectedBy0->person->middleName:"---"',
),
array(
'name'=>'endUser',
'value'=>'(!empty($data->endUser))?$data->endUser0->person->lastName.", ".$data->endUser0->person->firstName." ".$data->endUser0->person->middleName:"---"',
),
'dateReceived',
array(
'name'=>'receivedBy',
'value'=>'(!empty($data->receivedBy))?$data->receivedBy0->person->lastName.", ".$data->receivedBy0->person->firstName." ".$data->receivedBy0->person->middleName:"---"',
),
array(
'name'=>'requisitionOffice',
'value'=>'(!empty($data->requisitionOffice))?$data->requisitionOffice0->code:"---"',
'value'=>'$data->requisitionOffice0->code'
),
'prNo',
'poNo',
array(
'class'=>'InfosysButtonColumn',
'template'=>'{view}',
'afterDelete'=>'function(link,success,data){
if(success){
jSuccess("Delete completed successfully!");
}
}',
'buttons'=>array(
'view' => array(
'label' => 'View details',
'url' => 'Yii::app()->createUrl("pims/IAR/BaseIar/view", array("id"=>$data["id"]))'
),
),
'header'=>CHtml::activeDropDownList($model,'pageSize',array('10'=>'10','20'=>'20','30'=>'30','50'=>'50','100'=>'100','ALL'=>'All'),array('onchange'=>'$.fn.yiiGridView.update("base-iar-grid", {data:{pageSize:$(this).val()}});')),
),
)
));
What might be the correct way to declare multiple relations in $criteria->with?
Hey I found this piece of example code in the docs for with(), maybe it'll help you:
Post::model()->with(array(
'author'=>array('select'=>'id, name'),
'comments'=>array('condition'=>'approved=1', 'order'=>'create_time'),
))->findAll();
I have been fighting with this code:
function getNextActionFObyBalance($when) {
$theQuery = $this->find('first', array(
'fields' => array(
'Contract.id',
'Contract.start_balance'
),
'conditions' => array(
'AND' => array(
'Status.next_action_by' => 'frontoffice',
'Status.status_type' => 'active',
'Status.visibility' => 'frontoffice',
'OR' => array(
'Contract.next_action_on' => null,
'Contract.next_action_on <=' => $when
)
)),
'order' => 'Contract.start_balance DESC',
'recursive' => 0,
));
return $theQuery;
}
I have enabled logging on the MySQL server at this is what the server indicates that CakePHP is requesting:
SELECT `Contract`.`id`, `Contract`.`start_balance` FROM `contracts` AS `Contract` LEFT JOIN `statuses` AS `Status` ON (`Contract`.`status_id` = `Status`.`id`) LEFT JOIN `users` AS `User` ON (`Contract`.`user_id` = `User`.`id`) WHERE ((`Status`.`next_action_by` = 'frontoffice') AND (`Status`.`status_type` = 'active') AND (`Status`.`visibility` = 'frontoffice') AND (((`Contract`.`next_action_on` IS NULL) OR (`Contract`.`next_action_on` <= '2010-09-13 10:13:04')))) ORDER BY `Contract`.`start_balance` DESC LIMIT 1
if I use that in the phpmyadmin tool, I get exactly what I was expecting 1 record with two fields. BUT CakePHP just gives me an empty result set.
Can anyone enlighten me?
PS the code was working but I can figure out what changed!
The problem was with a stub to do some post processing afterFind. The problem is that I have completely forgotten to return $results;
I found the error by doing a step by step debugging down the find method in model.php. Found that the after find was called at some point and went to check my afterFind.
Took my about 4 hours for a simple error but I am learning!
Presumably this method is defined in models/contract.php?
The recursive = 0 statement looks a bit suspect to me. Are the models correctly related in their respective model files?
Have you tried loadModel in case the associations aren't working properly?
It would be useful to see the relationship definitions from the respective models.
--EDIT--
I've formatted the code from your comment here as I can't edit your OP
var $belongsTo = array(
'Status' => array(
'className' => 'Status',
'foreignKey' => 'status_id',
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
)
);
var $hasMany = array(
'Transaction' => array(
'className' => 'Transaction',
'foreignKey' => 'contract_id',
'dependent' => false,
)
);