Cakephp v3.2.10 - error using virtual fields in other entities - cakephp-3.0

I am trying to use "virtual fields" across 3 tables and I just can't get it to work across more than 2.
I have 3 tables
item_type
project_items
projects
with suitable relationships
$this->table('project_items');
$this->displayField('id');
$this->primaryKey('id');
$this->belongsTo('ProjectTemplates', [
'foreignKey' => 'project_template_id',
'joinType' => 'INNER'
]);
$this->belongsTo('ItemTypes', [
'foreignKey' => 'item_type_id',
'joinType' => 'INNER'
]);
I have a virtual field on the project_items entity to calculate the sum of a float from the associated item_type table and a float from the project_items table:
protected function _getTotalItemEffort()
{
$adjustment = $this->_properties['item_effort_adjustment'];
$baseline = $this->_properties['item_type']->item_effort_baseline; //this works fine when used in project_items view, but causes error when referenced in project view
return $adjustment + $baseline;
}
I can use this virtual field in the 'projects' view and it works fine
<tr>
<th><?= __('Total Item Effort') ?></th>
<td><?= $this->Number->format($projectTemplate->total__item_effort) ?></td>
</tr>
HOWEVER - if I try and use this in another virtual function on the project entity, I get the errors below BUT the errors are reported on the virtual function above that works fine.
protected function _getTotalBuildEffort()
{
$effort = 0;
foreach ($this->project_items as $item) {
$effort = $effort + $item->total_build_effort; //this causes errors
}
return $effort;;
}
then I get errors
Notice (8): Undefined index: item_type [APP/Model/Entity/ProjectTemplateItem.php, line 49]
Notice (8): Trying to get property of non-object [APP/Model/Entity/ProjectTemplateItem.php, line 49]
Notice (8): Undefined index: item_type [APP/Model/Entity/ProjectTemplateItem.php, line 49]
Notice (8): Trying to get property of non-object [APP/Model/Entity/ProjectTemplateItem.php, line 49]
I am at a loss

Related

Yii 2 Gridview - Search Query generates ambiguous fields

I am generating related records search query for Gridview use
I get this error :
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'dbowner' in where clause is ambiguous
The SQL being executed was: SELECT COUNT(*) FROM tbl_iolcalculation LEFT JOIN tbl_iolcalculation patient ON tbl_iolcalculation.patient_id = patient.id WHERE (dbowner=1) AND (dbowner=1)
I have two related models 1) iolcalculation and patient - each iolcalculation has one patient (iolcalculation.patient_id -> patient.id)
The relevant code in my model IolCalculationSearch is :
public function search($params)
{
$query = IolCalculation::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['patient.lastname'] = [
'asc' => ['patient.lastname' => SORT_ASC],
'desc' => ['patient.lastname' => SORT_DESC],
];
$query->joinWith(['patient'=> function($query) { $query->from(['patient'=>'tbl_iolcalculation']); } ]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'patient_id' => $this->patient_id,
'preop_id' => $this->preop_id,
'calculation_date' => $this->calculation_date,
'iol_calculated' => $this->iol_calculated,
The reason this error is generated is that each model has an override to the default Where clause as follows, the reason being that multiple users data needs to be segregated from other users, by the field dbowner:
public static function defaultWhere($query) {
parent::init();
$session = new Session();
$session->open();
$query->andWhere(['t.dbowner' => $session['dbowner']]);
}
this is defined in a base model extending ActiveRecord, and then all working models extend this base model
How Can I resolve this ambiguous reference in the MySQL code?
Thanks in advance
$query->andFilterWhere([
// previous filters
self::tableName() . '.structure_id' => $this->structure_id,
// next filters
]);
I think, that you are searching for table aliases.
(https://github.com/yiisoft/yii2/issues/2377)
Like this, of course you have to change the rest of your code:
$query->joinWith(['patient'=> function($query) { $query->from(['patient p2'=>'tbl_iolcalculation']); } ]);
The only way I can get this to work is to override the default scope find I had set up for most models, so that it includes the actual table name as follows - in my model definition:
public static function find() {
$session = new Session();
$session->open();
return parent::find()->where(['tbl_iolcalculation.dbowner'=> $session['dbowner']]);
}
There may be a more elegant way using aliases, so any advice would be appreciated - would be nice to add aliases to where clauses, and I saw that they are working on this....

empty response on model using union

I have the following code
public function findAccessible(Query $query, array $options){
return $this->findPublic($query, $options)
->union($this->findMyAdmin($query, $options));
}
public function findPublic(Query $query, array $options){
return $query
->where(['public' => true]);
}
public function findMyAdmin(Query $query, array $options){
return $query
->where(['admin_user_id' => $options['User.id']]);
}
The findAccessible call gives me this error message in Chrome: ERR_EMPTY_RESPONSE
No other error message, no entry in error log. I am sure that is because of the union call. How to do it?
What I want to achieve:
groups hasAndBelongsTo users
groups: id, name, admin_user_id, public
I would like to get groups
1) what are public groups (This is ok, findPublic method)
2) where admin_user is the given user (This is ok, findMyAdmin method)
3) in where the given user is a member (This is ok, I could do it with an other find()->matching call)
4) which are accessible for the user, eg. public OR the given user is admin OR a member - meaning the union of 1), 2) and 3) - that is with what I am struggling. If I put all these to one find method I can not define OR relationship for the membership, as that is done by matching what is translated into an inner join.
I found a really ugly but working solution.
public function findAccessible(Query $query, array $options){
$qq = $this->query($query);
$memberships = $qq->matching('Users', function($q) use ($options){
return $q->where(['Users.id' => $options['User.id']]);
});
foreach($memberships as $m){
$memberInGroup[] = $m->id;
}
return $query
->where(['public' => true])
->orWhere(['admin_user_id' => $options['User.id']])
->orWhere(['Groups.id IN' => $memberInGroup]);
}
I hope somebody will find a better solution and post here.

Eloquent where clause to use related model's column when using with() -laravel 4

I have 2 models
Truck
class Truck extends \Eloquent {
// Add your validation rules here
public static $rules = [
'trucktype_id' => 'required',
'weight'=> 'required',
'truck_no'=> 'required'
];
// Don't forget to fill this array
protected $fillable = ['trucktype_id','weight','picture_path','remarks','truck_no'];
public function TruckType(){
return $this->belongsTo('TruckType','trucktype_id');
}
}
TruckType
class Trucktype extends \Eloquent {
// Add your validation rules here
public static $rules = array(
'type' => 'required|unique:trucktypes,type',
'max_weight' => 'required'
);
// Don't forget to fill this array
protected $fillable = ['type','max_weight'];
}
I need to lookup related table records i.e TruckType
$trucksobj = Truck::with('TruckType');
if($truck_no!="")
$trucksobj->where("truck_no",'=',$truck_no);
if($start_date!="" && $end_date!="")
$trucksobj->whereBetween('created_at', array($start_date, $end_date));
if($truck_type!="")
$trucksobj->where("trucktype_id",'=',$truck_type);
if($overweight=="on")
$trucksobj->where('TruckType.max_weight', '>=', 0);
But the above query didnt resolve TruckType.max_weight and throws following error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'TruckType.max_weight' in 'where clause' (SQL: select count(*) as aggregate from trucks where TruckType.max_weight >= 0)
I think you misunderstand how with() actually works. It is only used to alleviate the N+1 query problem, and does not make the contents of the table available for querying. After your first query has ran to select all of the trucks, the with() simply causes the following query to be automatically ran:
select * from TruckType where TruckType.id in (...)
Here the list at the end will contain all of the different truck.trucktype_id values that were found in your first query, and then they'll automatically be available for you to use via $truck->TruckType->{property} etc.
Now, if you actually have a look at the query that's being generated for you, you can clearly see that there is no TruckType table referenced anywhere:
select count(*) as aggregate from trucks where TruckType.max_weight >= 0
This is why the error is being thrown.
You have two options:
(1) Use a join
$trucksobj = Truck::with('TruckType')->join('TruckType', 'truck.trucktype_id', '=', 'TruckType.id')->where('TruckType.max_weight', '>=', 0);
(2) Use whereHas() to place a constraint on your relationship
$trucksobj = Truck::with('TruckType')->whereHas('TruckType', function($q) {
$q->where('max_weight', '>=', 0);
});
If you don't actually need to know anything about the truck type, and you only want to use it to sieve through the trucks, then you can get rid of with('TruckType') and just keep the rest of the query.

PHQL DELETE Not Working?

I am trying to use phalcons query language(PHQL) to remove items from a database, i have used the GET method obtain the id of the item clicked on.. The id is embedded
Controller:
public function deleteSkillsAction(){
$id=$_GET["id"]
$phql = "DELETE FROM Skills WHERE id =:id:";
$manager->executeQuery(
$phql,
array(
'id' => $id
)
);
}
Getting the following error message, and query is not going through:
Notice: Undefined variable: manager in C:\xampp\htdocs\Blueware\app\controller\skillsController.php on line 15
Fatal error: Call to a member function executeQuery() on a non-object in C:\xampp\htdocs\Blueware\app\controller\skillsController.php on line 15
Try
first initialize the $manager variable, as per documentation,
$manager = $this->modelsManager;
$manager->executeQuery(
$phql,
array(
'id' => $id
)
);
or
call is as
$this->modelsManager->executeQuery(
$phql,
array(
'id' => $id
)
);

UPDATED: Magento add customer attribute filter to order grid

I have extended the Mage_Adminhtml_Block_Sales_Order_Grid class with a custom module to add several customer attributes (Magento EE 1.10) to the grid.
Two of the attributes I added are text fields (i.e. they live in the customer_entity_varchar table, and I was able to add them to the collection and display them in the grid. So far so good.
A third attribute is a select, so the values live in the customer_entity_int, the eav_attribute_option and the eav_attribute_option_value tables. I added the necessary values to the collection (using $collection->getSelect()->joinLeft(.....). Again, so far so good.
My problem is being able to display and filter the attribute at the same time.
Inside the _prepareColumns() function in my MyCompany_MyModule_Block_Adminhtml_Order_Grid class, if I add a column like this, - as expected - I can display the values of the attribute on each row, but I don't get a drop down filter in the header:
protected function _prepareColumns()
{
...
$this->addColumn('bureau', array(
'header' => Mage::helper('sales')->__('Bureau'),
'index' => 'bureau',
'type' => 'text'
));
...
}
Following the example of status, and adding the column like this, gives me the drop down filter in the header, but it no longer displays the values for the attribute in each row:
protected function _prepareColumns()
{
...
$this->addColumn('bureau', array(
'header' => Mage::helper('sales')->__('Bureau'),
'index' => 'bureau',
'type' => 'options',
'options' => $this->_getBureauOptions(),
'filter_index' => 'value_option_table.option_id'
));
...
}
protected function _getBureauOptions()
{
$bureau = Mage::getResourceModel('eav/entity_attribute_collection')
->setCodeFilter('bureau')
->getFirstItem();
$bureauOptions = $bureau->getSource()->getAllOptions(false);
$optionsArr = array();
foreach ($bureauOptions as $option) {
$optionsArr[$option['value']] = $option['label'];
}
return $optionsArr;
}
Any advice / explanation would be much appreciated.
UPDATE:
It turns out that my code also causes a SQL error in a multi-website environment when an admin user only has permissions for some websites:
"SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'store_id' in where clause is ambiguous"
#clockworkgeek had the answer to the first part of my question.
The problem was that my joinLeft() was retrieving text values from the attribute options, while I should have been retrieving integer values when using 'type => 'options'.
Once I changed my joinLeft() to only retrieve integer values from customer_entity_int (actually a simpler join), the filtering and display worked flawlessly - thank you sir.
I will re-post my second issue (about SQL errors caused by permissions) as a separate question.