Cakephp3 multiple join table by Model - mysql

I have problem with my code. At this moment I have code view like this:
...Table.php
public function containBasic(){
return [
//Keywords
'CandidatesKeywords',
'CandidatesKeywords.Keywords',
//User
'CandidatesUser',
'CandidatesUser.User',
];
}
...Controller.php
$this->loadModel('Candidates');
$candidates = $this->Candidates->find()
->contain($this->Candidates->containBasic())
->where([
'CandidatesKeywords.Keywords.id'=>5
])
->all();
I include all other Models via contain. This method its works but when I try to search data in this code I have error like:
Unknown column 'CandidatesKeyword.id' in 'where clause
I don't know, how I can get column CandidatesKeywords -> Keywords -> Id from database :/
When I get (debug) all rows without where condition I get data like this:
'items' => [
(int) 0 => object(Cake\ORM\Entity) {
'id' => (int) 4,
.........
,
'candidates_user' => null,
'candidates_keyword' => object(App\Model\Entity\CandidatesKeyword) {
'id' => (int) 1,
..................
'keyword' => object(App\Model\Entity\Keyword) {
'id' => (int) 5,
.............
And I need to get rows with only keyword.id = 5.

Related

How to avoid _matchingData and get a specific value instead

In the Orders Table Model I need the category ids of the products associated with the order
Model/Table/OrdersTable.php
public function updateQuantityForInventoryItems(array $orders_items): void
{
$ordersItemsIds = [];
foreach ($orders_items as $orders_item) {
array_push($ordersItemsIds, $orders_item->product_id);
}
$catIds = $this->find('ordersItemsCategories', ['ordersItemsIds' => $ordersItemsIds])->toArray();
dd($catIds);
$InventoriesTable = TableRegistry::getTableLocator()->get('Inventories');
$InventoriesTable->updateQuantityForInventoryItems('orders', $catIds);
}
public function findOrdersItemsCategories(Query $query, array $options): Query
{
$query = $this->OrdersItems->Products
->find()
->select(['Products.id','CategoriesProducts.category_id'])
->matching(
'CategoriesProducts', function (Query $q) use ($options) {
return $q->where([
'CategoriesProducts.product_id IN' => $options['ordersItemsIds'],
]);
});
return $query->hydrate(false);
}
the generated SQL query
SELECT Products.id AS `Products__id`, CategoriesProducts.category_id AS `CategoriesProducts__category_id` FROM products Products INNER JOIN categories_products CategoriesProducts ON (CategoriesProducts.product_id in (4325,3632) AND Products.id = (CategoriesProducts.product_id))
When I print out the array with dd($catIds); , I get an array with _matchingData
array:4 [▼
0 => array:2 [▼
"id" => 3632
"_matchingData" => array:1 [▼
"CategoriesProducts" => array:1 [▼
"category_id" => 10
]
]
]
1 => ...
]
how do i get category_id under id
(i have already checked that thread How to print _matchingData object value in cakephp 3 but still no success)
got it. i need to alias the category_id to prevent nesting
->select(['category_id' => 'CategoriesProducts.category_id'])

How to have relationship in Laravel 5.7 based on a json data key saved in a table column?

I am using this Staudenmein package in Laravel and referring to this answer given by the package owner himself.
I have two tables, pets and notifications with models Pet and Notification.
The notifications table has a column called data which is of JSON dataType and stores JSON data
{"pet_id":"4","pet_type_id":1,"lost_report_id":3,"pet_sighting_id":21,"latitude":"22.676846","longitude":"88.338509"}
The key pet_id denotes the id column of the pets table. I need a relationship so that I can fetch the name of the pet from pets table.
By referring to the answer link given above, I wrote my Notification model like this:-
namespace App\Models;
use DB, App, Auth, Hash, Lang, Mail, Config, Exception, Validator, Globals;
use Illuminate\Database\Eloquent\Model;
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
use App\User;
use App\Models\AdminConfig;
use App\Models\ReceivedAppNotification;
class Notification extends Model
{
protected $casts = [
'data' => 'json'
];
public function notificationPet()
{
return $this->belongsTo('App\Models\Pet', 'data->pet_id');
}
}
When I am running the query like this:-
$notificationQuery = Notification::with('notificationPet')
->whereRaw("FIND_IN_SET('$userId', in_app_notification_receiver)")
->where(array(
'status' => Globals::SMALL_CHAR_ACTIVE,
'is_delete' => Globals::SMALL_CHAR_NO,
))->get()->toArray();
I get the notificationPet relationship as empty, ie. the data-set is like this:-
Array
(
[id] => 10
[title] =>
[message] =>
[data] => Array
(
[pet_id] => 4
[latitude] => 22.676846
[longitude] => 88.338509
[pet_type_id] => 1
[lost_report_id] => 3
[pet_sighting_id] => 34
)
[no_of_in_app_notification_receiver] => 2
[no_of_push_notification_receiver] => 1
[from_user] => 22
[in_app_notification_receiver] => 2,23
[push_notification_receiver] => 2
[status] => a
[is_delete] => n
[push_notification_sent] => n
[created_date] => 2020-03-19 13:23:17
[modified_date] => 2020-03-19 13:23:17
[created_at] => 2020-03-19 13:23:17
[updated_at] => 2020-03-19 13:23:17
[notification_pet] =>
)
However, I have a record in pets table with id = 4, already. So the relationship should not be empty.
What am I doing wrong?
Change:
protected $casts = [
'data' => 'json'
];
To:
protected $casts = [
'data' => 'array'
];

how to id as key in mysql select return

I need return of my mysql query
from
SELECT name as id FROM table
but I need return like this in mysql (I wrote it in an array because it's easy to write)
[
20: 'Jack',//20 is id from table and Jack is name from table
40: 'Nano',
49: 'Hakase'
]
Use WHERE condition
SELECT * FROM table WHERE ID = yourId
just replace yourId for the ID number you want.
First, select all id and name using
SELECT id, name FROM table SOME CONDITIONS
this query would return a result like
$result = [
[ id => 1, name => 'name' ],
[ id => 1, name => 'name' ],
[ id => 1, name => 'name' ],
[ id => 1, name => 'name' ],
]
then arrange array
$accepted_output = array_column($result, 'id', 'name')
$accepted_output = [
[ 1 => 'name' ],
[ 1 => 'name' ],
[ 1 => 'name' ],
[ 1 => 'name' ],
]
array_column docs - https://www.php.net/manual/en/function.array-column.php
You want to return the ID and the name so you should rewrite your query to:
SELECT id,name FROM table
You should use commas to seperate field names.
For more information you can do some reading here.

YII2 creating relations in models between tables from 2 databases

I have defined 2 databases , for example
return [
'components' => [
'db1' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db1name',
'username' => 'db1username',
'password' => 'db1password',
],
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db2name',
'username' => 'db2username',
'password' => 'db2password',
],
],
];
Now i have a table as 'users' in 'db1' and table 'countries' in 'db2'
users
id , country_code , username , password
1 , DE , xyz , 12345
2 , FR , abc , 12345
countries
code , name
DE , Germany
FR , France
IN , India
I have defined the foreign key relation between users.country_code & countries.code
ISSUE
But when i try to create the model for 'users' table using gii it gives an error , possibly because the tables relation are from 2 different databases.
How to use tables from different databases in relations of a model.
Any suggestions are welcomed
This works in my case to list iten on GridView::widget
-> bd_sisarc is my secound data base
-> deposito_sondagem is a table from my first data base
public static function getDb() // on your model
{
return Yii::$app->get('db1');
}
public static function getDb() // on your model
{
return Yii::$app->get('db2');
}
public function getEmpresaSondagem() // Relation on you model
{
return $this->hasOne(EmpresaSondagem::className(), ['idEmpSondagem' => 'entidade_deposito']);
}
public function search($params)
{
$this->load($params);
$sql = "SELECT deposito_sondagem.*
FROM
deposito_sondagem,
`bd_sisarc`.`tbempresasondagem`
WHERE
`bd_sisarc`.`tbempresasondagem`.`idEmpSondagem`=`deposito_sondagem`.`entidade_deposito`
and deposito_sondagem.estado=1
and tbempresasondagem.estado=1
and numero_registo LIKE '%$this->numero_registo%'
and nomeempsondagem LIKE '%$this->nomeEntidade%'
and dono_sondagem LIKE '%$this->dono_sondagem%'
and data_deposito LIKE '%$this->data_deposito%'";
$query = DepositoSondagem::findBySql($sql);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
return $dataProvider;
}
Try this one
SELECT `users`.* FROM `users` LEFT JOIN `db2name`.`countries` ON `users`.`country_code` = `db2name`.`countries`.`code `

Cakephp find('list') with summarized data returns nulls

I have the following query in a Cakephp 2.4 model:
$scores = $this->WorkInfo->find('list', array(
'conditions' => array('WorkInfo.work_id' => $work_ids),
'fields' => array('WorkInfo.date', 'SUM(WorkInfo.score)'),
'group' => array('WorkInfo.date')
));
Which generates the following query:
SELECT
`WorkInfo`.`date`,
SUM(`WorkInfo`.`score`)
FROM
`home`.`work_infos` AS `WorkInfo`
WHERE
`WorkInfo`.`work_id` IN (4, 7, 8, 12, 9, 11, 13, 10, 14, 6, 5)
GROUP BY
`WorkInfo`.`date`
The result I get in my application is:
'2014-03-24' => null
'2014-03-25' => null
'2014-03-26' => null
'2014-03-27' => null
'2014-03-28' => null
'2014-03-31' => null
While the result I get from pasting this very query in the mysql console is:
'2014-03-24' => 0
'2014-03-25' => 36
'2014-03-26' => 0
'2014-03-27' => 164
'2014-03-28' => 0
'2014-03-31' => 0
What is going on here? It is supposed that same queries output same results, isn't it?
I have read something about creating virtual fields for this, but I do not want to overkill, it should be possible to perform a simple aggregation query through Cakephp using the find function.
Thanks!
Try this
$scores = $this->WorkInfo->find('all', array(
'conditions' => array('work_id' => $work_ids),
'fields' => array('date', 'SUM(score) AS score'),
'group' => array('date')
));
then with Set::combine you can format your array cakephp find list
$scores = Set::combine($scores, '{n}.WorkInfo.date', '{n}.0.score');
prints=>
'2014-03-24' => 0
'2014-03-25' => 36
'2014-03-26' => 0
'2014-03-27' => 164
'2014-03-28' => 0
'2014-03-31' => 0
Ok, sadly, I think what you want to do can't be done as you want to do it.
Let's see, you use the find('list') method, so that's here in the API. Code looks normal, and as you said, query is ok, returns everything you want. Problem is in line 2883
return Hash::combine($results, $query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']);
That line organizes the returned array after the query is done. And seeing the doc for that function, we have
Creates an associative array using a $keyPath as the path to build its
keys, and optionally $valuePath as path to get the values. If
$valuePath is not specified, or doesn’t match anything, values will be
initialized to null.
Which is what happens to you. Now, debugging, the query result before applying the Hash::combine function is something like this
Array
(
[0] => Array
(
[WorkInfo] => Array
(
[date] => 2013-04-01
)
[0] => Array
(
[SUM(`WorkInfo`.`score`)] => 24
)
)
)
so you see, you get the results. And the respective Hash::combine
Array
(
[groupPath] =>
[valuePath] => {n}.SUM(WorkInfo.score)
[keyPath] => {n}.WorkInfo.date
)
which probably causes problem with the dot inside the parenthesis. And the combine function doesn't find the valuePath, and you get null, and you get sad.
If you change your query to 'SUM(WorkInfo.score) AS score' (leaving everything as is), you have almost the same problem with valuePath
Array
(
[groupPath] =>
[valuePath] => {n}.SUM(WorkInfo.score) as score
[keyPath] => {n}.WorkInfo.date
)
//respective result array
Array
(
[0] => Array
(
[WorkInfo] => Array
(
[date] => 2013-04-01
)
[0] => Array
(
[score] => 24
)
)
)
You might think that doing 'SUM(score) AS score' (without the dot) will solve it, but the code of find('list') adds the alias if it doesn't find a dot (in line 2865).
So... I guess what I'm saying is: do a virtual field, or listen to Isaac Rajaei, or create a custom find function. But with find('list') and SUM() you won't have luck :(