Cakephp 3.x join with OR condition always result as AND - cakephp-3.0

Code
$query = $this->Client->find()
->hydrate(false)
->limit($limit)
->page($page)
->select(['Client.id','Client.achternaam','Client.Voornaam','clvsstatus.clientopnamestatus_id',
'clstatus.naam','afd.afdeling_naam','clsrtopn.naam'])
->join([
'clvsstatus' => [
'table' => 'client_vs_clientsoortstatus',
'type' => 'INNER',
'conditions' => [
'clvsstatus.client_id = client.id',
'clvsstatus.datum_van <='=>'2016-10-21',
'clvsstatus.datum_tot >='=>'2016-10-21',
**'OR' => ['clvsstatus.datum_tot'=>'0000-00-00']**
],
],
'clstatus' => [
'table' => 'clientsoortstatus',
'type' => 'INNER',
'conditions' => 'clstatus.id = clvsstatus.clientopnamestatus_id',
],
'clvsafdeling' => [
'table' => 'client_vs_afdeling',
'type' => 'INNER',
'conditions' => [
'clvsafdeling.client_id = clvsstatus.client_id',
'clvsafdeling.client_id = clvsstatus.client_id '
],
],
'afd' => [
'table' => 'afdeling',
'type' => 'INNER',
'conditions' => 'afd.afdeling_afdelingid = clvsafdeling.afdeling_id',
],
'clvssrtopn' => [
'table' => 'client_vs_clientsoortopname',
'type' => 'INNER',
'conditions' => 'clvssrtopn.client_id = client.id',
],
'clsrtopn' => [
'table' => 'clientsoortopname',
'type' => 'INNER',
'conditions' => 'clsrtopn.id = clvssrtopn.clientopnamesoort_id',
]
]) ;
Resulting SQL
SELECT
Client.id AS `Client__id`,
Client.achternaam AS `Client__achternaam`,
Client.Voornaam AS `Client__Voornaam`,
clvsstatus.clientopnamestatus_id AS `clvsstatus__clientopnamestatus_id`,
clstatus.naam AS `clstatus__naam`,
afd.afdeling_naam AS `afd__afdeling_naam`,
clsrtopn.naam AS `clsrtopn__naam`
FROM
client Client
INNER JOIN client_vs_clientsoortstatus clvsstatus ON (
clvsstatus.client_id = client.id
AND clvsstatus.datum_van <= '2016-10-21'
AND clvsstatus.datum_tot >= '2016-10-21'
**AND clvsstatus.datum_tot = '0000-00-00'**
)
INNER JOIN clientsoortstatus clstatus ON clstatus.id = clvsstatus.clientopnamestatus_id
INNER JOIN client_vs_afdeling clvsafdeling ON (
clvsafdeling.client_id = clvsstatus.client_id
AND clvsafdeling.client_id = clvsstatus.client_id
)
INNER JOIN afdeling afd ON afd.afdeling_afdelingid = clvsafdeling.afdeling_id
INNER JOIN client_vs_clientsoortopname clvssrtopn ON clvssrtopn.client_id = client.id
INNER JOIN clientsoortopname clsrtopn ON clsrtopn.id = clvssrtopn.clientopnamesoort_id
LIMIT
15 OFFSET 0
COMMENT :
As you see in the above code and resulting SQL even when explicitly ask for an OR condition cake always makes it AND, can anyone help with this thnxs

You have to rewrite the conditions on your first join to the following:
'conditions' => [
'clvsstatus.client_id = client.id',
'OR' => [
'clvsstatus.datum_tot'=>'0000-00-00',
'AND' => [
'clvsstatus.datum_van <='=>'2016-10-21',
'clvsstatus.datum_tot >='=>'2016-10-21',
]
]
]

Related

Order my consulting by field of my contain

I want order by proyecto_id who is in my ProyectosCategoraisTareas and also order by my categoria id, this is my contain Tareas.Categorias.
I try this but not work.
$proyectostareas = $this->ProyectosCategoriasTareas
->find('all', [
'contain' => [
'Proyectos',
'Tareas',
'Tareas.Categorias' => [
'order' => [
'Tarea.Categoria.id' => 'DESC'
]
]
]
])
->where([
'activa' => '1'
])
->order([
'proyecto_id' => 'DESC'
]);
Try this:
$proyectostareas = $this->ProyectosCategoriasTareas
->find('all')
->where([
'activa' => '1'
])
->join([
'Proyectos',
'Tareas'])
->order([
'proyecto_id DESC',
'Tarea.Categoria.id DESC'
]);

CakePHP 2 - Two foreign keys of a table linked to the same single table primary key

How can i use cakephp 2X model hasone or other association concept here to execute the find query.
In my Schinfo.php model is
class Schinfo extends AppModel {
public $tablePrefix = 'sko_';
public $hasOne = [
'State' => [
'className' => 'Masterlocation',
'foreignKey' => 'master_locid'
],
'City' => [
'className' => 'Masterlocation',
'foreignKey' => 'master_locid'
],
'Area' => [
'className' => 'Masterlocation',
'foreignKey' => 'master_locid'
]
];
}
With the above I got
SELECT
`Schinfo`.`skool_id`,
`Schinfo`.`skool_code`,
`Schinfo`.`skool_name`,
`Schinfo`.`skool_addr`,
`Schinfo`.`master_state_id`,
`Schinfo`.`master_city_id`,
`Schinfo`.`master_area_id`,
`Schinfo`.`skool_pin`,
`Schinfo`.`skool_board`,
`Schinfo`.`skool_type_id`,
`Schinfo`.`skool_affilated_to`,
`Schinfo`.`skool_affilated_no`,
`Schinfo`.`skool_contact_no`,
`Schinfo`.`skool_mailid`,
`Schinfo`.`skool_website`,
`Schinfo`.`skool_logo`,
`Schinfo`.`skool_delete`,
`State`.`master_locid`,
`State`.`master_parentid`,
`State`.`master_locname`,
`State`.`is_checked`,
`City`.`master_locid`,
`City`.`master_parentid`,
`City`.`master_locname`,
`City`.`is_checked`,
`Area`.`master_locid`,
`Area`.`master_parentid`,
`Area`.`master_locname`,
`Area`.`is_checked`
FROM
`skoolata`.`sko_schinfos` AS `Schinfo`
LEFT JOIN
`skoolata`.`sko_masterlocations` AS `State`
ON (`State`.`master_locid` = `Schinfo`.`id`)
LEFT JOIN
`skoolata`.`sko_masterlocations` AS `City`
ON (`City`.`master_locid` = `Schinfo`.`id`)
LEFT JOIN
`skoolata`.`sko_masterlocations` AS `Area`
ON (`Area`.`master_locid` = `Schinfo`.`id`)
WHERE
1 = 1
Now I need to change
LEFT JOIN
skoolata.sko_masterlocations AS State
ON (State.master_locid = Schinfo.id)
LEFT JOIN
skoolata.sko_masterlocations AS City
ON (City.master_locid = Schinfo.id)
LEFT JOIN
skoolata.sko_masterlocations AS Area
ON (Area.master_locid = Schinfo.id)
to
LEFT JOIN
skoolata.sko_masterlocations AS State
ON (State.master_locid = Schinfo.master_state_id)
LEFT JOIN
skoolata.sko_masterlocations AS City
ON (City.master_locid = Schinfo.master_city_id)
LEFT JOIN
skoolata.sko_masterlocations AS Area
ON (Area.master_locid = Schinfo.master_area_id)
to get my desire output
You want to define three relationships, Country, State and City and specify the className for each to be the model you are linking to, for example Location. You can then also specify the column you will be using as the foreign keys in your Student model using foreignKey:-
public $hasOne = [
'Country' => [
'className' => 'Location',
'foreignKey' => 'country_id'
],
'State' => [
'className' => 'Location',
'foreignKey' => 'state_id'
],
'City' => [
'className' => 'Location',
'foreignKey' => 'city_id'
]
];
Then when it comes to finding the results you can use contain like:-
$students = $this->Student->find('all', [
'contain' => ['Country', 'State', 'City']
]);

How to include from another table in query Cakephp

I need to know the cakeish way of adding the from Features_properties. so when I do
where FeaturesProperty.feature_id = 3
it won't give an error
The below will generate a MySQL query
$this->Paginator->settings = array('conditions' => array($conditionID, $categoryID, $localityID, $serviceTypeID,
'Property.price BETWEEN ' . $params['priceFrom'] . ' AND ' . params['priceTo'],
$bedrooms,$bathrooms,'FeaturesProperty.feature_id = 3','Property.viewable = 1'),
'contain' => array('Image' => array('conditions' => array('main_image' => true)),
'ServiceType','Category','FeaturesProperty', 'Condition', 'Locality',),
'limit' => 15);
Which can be seen hereunder
SELECT `Property`.`id`, `Property`.`address1`, `Property`.`address2`,
`Property`.`area`, `Property`.`category_id`, `Property`.`condition_id`,
`Property`.`contact_detail_id`, `Property`.`country_id`, `Property`.`description`,
`Property`.`length`, `Property`.`main_image_id`, `Property`.`price`,
`Property`.`service_type_id`, `Property`.`locality_id`, `Property`.`viewable`,
`Property`.`width`, `Property`.`bathroom_qty`, `Property`.`bedroom_qty`,
`Category`.`id`, `Category`.`category`, `Condition`.`id`, `Condition`.`condition`,
`ServiceType`.`id`, `ServiceType`.`service_type`, `Locality`.`id`,
`Locality`.`locality`, `Locality`.`region_id`, (SELECT concat(`Locality`.`locality`,"
- ", region) FROM regions where id = `Locality`.`region_id`) AS `Locality__fullname`
FROM `realestate`.`properties` AS `Property` LEFT JOIN `realestate`.`categories` AS
`Category` ON (`Property`.`category_id` = `Category`.`id`) LEFT JOIN
`realestate`.`conditions` AS `Condition` ON (`Property`.`condition_id` =
`Condition`.`id`) LEFT JOIN `realestate`.`service_types` AS `ServiceType` ON
(`Property`.`service_type_id` = `ServiceType`.`id`) LEFT JOIN
`realestate`.`localities` AS `Locality` ON (`Property`.`locality_id` =
`Locality`.`id`)
WHERE `Property`.`price` BETWEEN 0 AND 99999999 AND
`FeaturesProperty`.`feature_id` = 3 AND `Property`.`viewable` = 1 LIMIT 15
What I need is
SELECT `Property`.`id`, `Property`.`address1`, `Property`.`address2`,
`Property`.`area`, `Property`.`category_id`, `Property`.`condition_id`,
`Property`.`contact_detail_id`, `Property`.`country_id`, `Property`.`description`,
`Property`.`length`, `Property`.`main_image_id`, `Property`.`price`,
`Property`.`service_type_id`, `Property`.`locality_id`, `Property`.`viewable`,
`Property`.`width`, `Property`.`bathroom_qty`, `Property`.`bedroom_qty`,
`Category`.`id`, `Category`.`category`, `Condition`.`id`, `Condition`.`condition`,
`ServiceType`.`id`, `ServiceType`.`service_type`, `Locality`.`id`,
`Locality`.`locality`, `Locality`.`region_id`, (SELECT concat(`Locality`.`locality`,"
- ", region) FROM regions where id = `Locality`.`region_id`) AS `Locality__fullname`
FROM `realestate`.`properties` AS `Property` LEFT JOIN `realestate`.`categories` AS
`Category` ON (`Property`.`category_id` = `Category`.`id`) LEFT JOIN
`realestate`.`conditions` AS `Condition` ON (`Property`.`condition_id` =
`Condition`.`id`) LEFT JOIN `realestate`.`service_types` AS `ServiceType` ON
(`Property`.`service_type_id` = `ServiceType`.`id`) LEFT JOIN
`realestate`.`localities` AS `Locality` ON (`Property`.`locality_id` =
`Locality`.`id`) left outer join `realestate`.`features_properties` AS `FeaturesProperty` ON
(`Property`.`id` = `FeaturesProperty`.`property_id`)
WHERE `Property`.`price` BETWEEN 0 AND 99999999 AND
`FeaturesProperty`.`feature_id` = 3 AND `Property`.`viewable` = 1 LIMIT 15
The most important part is
left outer join realestate.features_properties AS FeaturesProperty ON
(Property.id = FeaturesProperty.property_id)
Also since it might help hereunder are the relations from property model
/**
* belongsTo associations
*/
public $belongsTo = array(
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id'
),
'Condition' => array(
'className' => 'Condition',
'foreignKey' => 'condition_id'
),
'ContactDetail' => array(
'className' => 'ContactDetail',
'foreignKey' => 'contact_detail_id'
),
'ServiceType' => array(
'className' => 'ServiceType',
'foreignKey' => 'service_type_id'
),
'Country' => array(
'className' => 'Country',
'foreignKey' => 'country_id'
),
'Locality' => array(
'className' => 'Locality',
'foreignKey' => 'locality_id'
)
);
/**
* hasMany associations
*/
public $hasMany = array(
'Image' => array(
'className' => 'Image',
'foreignKey' => 'property_id',
'dependent' => false,
),
'DetailsProperty' => array(
'className' => 'DetailsProperty',
'foreignKey' => 'property_id'
),
'FeaturesProperty' => array(
'className' => 'FeaturesProperty',
'foreignKey' => 'property_id'
)
);
public $hasAndBelongsToMany = array(
'Detail' =>
array(
'className' => 'Detail',
'joinTable' => 'details_properties',
'foreignKey' => 'property_id',
'associationForeignKey' => 'detail_id',
),
'Feature' =>
array(
'className' => 'Feature',
'joinTable' => 'features_properties',
'foreignKey' => 'property_id',
'associationForeignKey' => 'feature_id',
)
);
I found the answer although it might have been a bit dumb I didn't know how to handle joins in cakephp
so now my code is
$this->Paginator->settings = array('conditions' => array($conditionID, $categoryID, $localityID, $serviceTypeID,
'Property.price BETWEEN ' . $params['priceFrom'] . ' AND ' . $params['priceTo'], $bedrooms, $bathrooms, 'FeaturesProperty.feature_id = 2', 'Property.viewable = 1'),
'contain' => array('Image' => array('conditions' => array('main_image' => true)),
'ServiceType', 'Category', 'FeaturesProperty', 'Condition', 'Locality',),
'joins' => array(
array(
'table' => 'features_properties',
'type' => 'left outer',
'alias' => 'FeaturesProperty',
'conditions' => array('property.id = FeaturesProperty.property_id')
)
),
'limit' => 15);
the code for the join being
Although this leaves me with multiple rows rather than a distinct 1 row
I have changed my idea of using a join to using an exists as was suggested by AD7six this has solved my problem with multiple rows.
so my code now is
$this->Paginator->settings = array('conditions' => array($conditionID, $categoryID, $localityID, $serviceTypeID,
'Property.price BETWEEN ' . $params['priceFrom'] . ' AND ' . $params['priceTo'], $bedrooms, $bathrooms, '(exists (select 1 from features_properties where features_properties.feature_id = 2))', 'Property.viewable = 1'),
'contain' => array('Image' => array('conditions' => array('main_image' => true)),
'ServiceType', 'Category', 'FeaturesProperty', 'Condition', 'Locality',),
'joins' => array(
array(
'table' => 'features_properties',
'type' => 'left outer',
'alias' => 'FeaturesProperty',
'conditions' => array('property.id = FeaturesProperty.property_id')
)
),
'limit' => 15);

CakePHP 2.x: Join on belongsto

in my model 'mesn' i have belongsto relations:
public $belongsTo = array(
'Order' => array(
'className' => 'Order', 'foreignKey' => 'order_id', 'conditions' => '', 'fields' => '', 'order' => ''
), 'SaleOrder' => array(
'className' => 'SaleOrder', 'foreignKey' => 'sale_order_id', 'conditions' => '', 'fields' => '',
'order' => ''
), 'ShippedBox' => array(
'className' => 'Box', 'foreignKey' => 'shipped_box_id', 'conditions' => '', 'fields' => '',
'order' => ''
)
); /* * * hasMany associations** #var array
In one of my model-functions i want to join another table on the "belongsto" "ShippedBox" (table: boxes). But doesn't matter how i try to write the join i get an error message of unknown column:
$arr_s_result = $this->find('all', array(
'joins' => array(
array('table' => 'shipments',
'alias' => 'MyShipments',
'type' => 'INNER',
'conditions' => array(
'MyShipments.id = ShippedBox.shipment_id'
)
)),
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
I have tried:
'MyShipments.id = ShippedBox.shipment_id'
and
'MyShipments.id = box.shipment_id'
and even
'MyShipments.id = Boxes.shipment_id'
where the table "boxes" with the field "shipment_id" exists.
How can i get this join working?
'MyShipments.id = box.shipment_id'
to:
'MyShipments.id = Box.shipment_id'
Also what about this:
$arr_s_result = $this->find('all', array(
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
The belongsTo join is done automatically.
I think you'll need to do something like use subqueries to get what you want -
$arr_s_result = $this->find('all', array(
'joins' => array(
array('table' => '(SELECT boxes.id, [enter other fields you need here] FROM shipments JOIN boxes ON boxes.shipment_id = shipments .id)',
'alias' => 'MyShipments',
'type' => 'INNER',
'conditions' => array(
'Mens.shipped_box_id = MyShipments.id'
)
)),
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));

CakePHP: Using bindModel to trace backwards by 3 models?

I have the following models:
-> = 1:many, <-> = many:many
User<->Product->MessageList<->Message
My goal with this query is to find all messages corresponding to the logged in . I also filter out messages that have been read (I find the messages ids in the prior find and store them in $messageIdsReadByPerson).
Here is my attempt:
// only grab messages belonging to this user
$this->Message->unbindModel(array('hasAndBelongsToMany'=>array('MessageListsMessage')));
$this->Message->bindModel( array(
'hasOne' => array(
'MessageListsMessage' => array(
'className' => 'MessageListsMessage',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'MessageListsMessage.message_id = Message.id'
)
),
'MessageList' => array(
'className' => 'MessageList',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'MessageList.id = MessageListsMessage.message_list_id'
)
),
'Product' => array(
'className' => 'Product',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'Product.id = MessageList.product_id'
)
),
'ProductsUser' => array(
'className' => 'ProductsUser',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'ProductsUser.product_id = Product.id'
)
),
'User' => array(
'className' => 'User',
'foreignKey' => false,
'conditions' => array(
'User.id = ProductsUser.user_id',
'User.id' => $this->Auth->user('id')
)
)
)
));
$messages = $this->Message->find('all', array(
'recursive' => -1
));
$this->set('messages', $messages);
But that only gives this query:
SELECT `Message`.`id`, `Message`.`text`, `Message`.`url` FROM `messages` AS `Message` WHERE 1 = 1
How can this be done properly using bindModel (or some easier method that I'm unaware of, although joins is apparently not the way to go).
EDIT:
this doesnt work either:
function index() {
// only grab messages belonging to this user
$messages = $this->Message->find('all', array(
'contain' => array(
'MessageList' => array(
'Product' => array(
'User.id = ' . $this->Auth->user('id')
)
)
)
));
$this->set('messages', $messages);
}
I think the same answer applies as I just gave here:
How to get only products with images in CakePhp
containable or recursive higher