CakePHP 3.7.7
I have a series of checkboxes. Name attributes are: emailFrequency_daily, emailFrequency_weekly and emailFrequency_monthly.
I want to save the ones that have been checked and need to save these alongside some other data I have stored in the session: session data o_id and u_id are the same every time a row is inserted. A frequency field in the database matches the appropriate checkbox and is different every time as per the list above.
So I have tried following https://book.cakephp.org/3.0/en/orm/saving-data.html#saving-multiple-entities
In my Controller I have the following
$TblAlertFrequency = TableRegistry::get('TblAlertFrequency');
$frequencies = [];
// 'daily' emails enabled
if ($this->request->getData('emailFrequency_daily')) {
$frequencies[] = [
'u_id' => $this->_UserModel->getUserId(),
'o_id' => $this->_UserModel->getOrgId(),
'frequency' => 'daily'
];
}
// 'weekly' emails enabled
if ($this->request->getData('emailFrequency_weekly')) {
$frequencies[] = [
'u_id' => $this->_UserModel->getUserId(),
'o_id' => $this->_UserModel->getOrgId(),
'frequency' => 'weekly'
];
}
// 'monthly' emails enabled
if ($this->request->getData('emailFrequency_monthly')) {
$frequencies[] = [
'u_id' => $this->_UserModel->getUserId(),
'o_id' => $this->_UserModel->getOrgId(),
'frequency' => 'monthly'
];
}
if (!empty($frequencies)) {
$entities = $TblAlertFrequency->newEntities($frequencies);
$TblAlertFrequency->saveMany($entities);
}
It's giving a 500 Internal Server error with the message:
Error: Cannot insert row, some of the primary key values are missing. Got (, ), expecting (o_id, u_id)
Why is this, given I'm passing it those values (o_id and u_id)?
The table structure is as follows:
mysql> describe tbl_alert_frequency;
+-----------+------------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------------------------------+------+-----+---------+-------+
| u_id | mediumint(8) unsigned | NO | PRI | NULL | |
| o_id | smallint(5) unsigned | NO | PRI | NULL | |
| frequency | enum('never','daily','weekly','monthly') | NO | | weekly | |
+-----------+------------------------------------------+------+-----+---------+-------+
The only thing I'm not passing it is the id because that's AUTO_INCREMENT and therefore written by MySQL on inserting a new row.
The code I've written here isn't DRY because it repeats:
'u_id' => $this->_UserModel->getUserId(),
'o_id' => $this->_UserModel->getOrgId(),
But if I remove those it won't save them, and they are needed on every row.
Surely there is an easier and more efficient way to write this?
I also looked at How to save multiple records in cakephp 3 but that seems outdated and didn't work for me.
Related
In my Cypress test, I am retrieving a SQL Server DB record from a table, looping through the response, & logging each column value like so:
And('the below values are populated in DB ', (dataTable) => {
cy.task('myDb', `SELECT * FROM Customer WHERE CustomerName = '${customerName}'`).then((response) => {
response.forEach(record => {
cy.log(record)
});
});
});
With the above code, I am logging the below array, each item in the array is a column value:
I have a datatable in my feature file that corresponds to the table structure:
And the below values are populated in DB
| CustomerId | CustomerName | AddressLine1 | AddressLine2 | City | State | Zip |
| 1 | Kevin Mitchell | | | | NULL | NULL |
What I am looking to do is update my existing code so that it can loop through my datatable & compare the above array against the datatable values in my feature file.
Can someone please explain what changes are required for this?
I've managed to get this working, & it works functionally so I'm going to post it here, but I'm sure there's a more efficient way to do this.
I'm happy for someone to suggest improvements to the below answer:
And('the below values are populated in DB', (dataTable) => {
cy.task('glp', `SELECT * FROM Customer WHERE CustomerName = '${customerName}'`).then((response) => {
dataTable.rows().forEach(function ($ele) {
response.forEach(function (record) {
record.forEach(function(record, index) {
expect(record.value).to.eq($ele[index])
});
});
});
});
});
I was looking through gorm.DB's docs and sources but can't seem to understand the purpose of Preload.
I thought that is the "preloaded schema/tables/rows" that you can use afterwards" but cannot somehow use it that way.
For instance I have the following struct
package model
type Currency struct {
ID uint64 `gorm:"primary_key"`
CurrencyCode string `gorm:"size:3"`
}
but when I do something like this to compare Find and Preload
logger.Info("Preload")
var preloadCurrencies []model.Currency
dbMySQL.Preload("currencies").Find(&preloadCurrencies)
for i, curr := range preloadCurrencies {
// stuff
}
logger.Info("find")
var currencies []model.Currency
dbMySQL.Find(¤cies)
for i, curr := range currencies {
// stuff
}
I get the following (with ):
INFO[0000] Preload
(/go/src/SOMESOURCES/main.go:28)
[2018-01-21 11:08:47] [1.02ms] SELECT * FROM `currencies`
[168 rows affected or returned ]
(/go/src/SOMESOURCES/main.go:28)
[2018-01-21 11:08:47] can't preload field currencies for model.Currency
INFO[0000] find
(/go/src/SOMESOURCES/main.go:37)
[2018-01-21 11:08:47] [0.90ms] SELECT * FROM `currencies`
[168 rows affected or returned ]
DB schema:
show columns from currencies;
+---------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| currency_code | char(3) | NO | | NULL | |
+---------------+---------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
Im working on getting data from a database, in this case from 3 tables, 'product' is used to check if the product is deleted or enabled, if the product is not deleted and is enabled than the 'product_translation' is used to get the language , translation & product_id (this is used to group the data with ArrayHelper::index) this goes well(see code below), but I now need to get data from a third table (in this case a category -> category_translation) which has a translation field which we want to to add to the data output, this field must match the following ways the category_id, attribute & language fields must match all. I hope that somebody understands this.
Im new to yii2 so I still are figuring out how to use this all.
----------------------------------------------
| product |
----------------------------------------------
| id | is_deleted | is_enabeld | category_id |
----------------------------------------------
---------------------------------------------------
| product_translation |
---------------------------------------------------
| product_id | attribute | language | translation |
---------------------------------------------------
----------------------------------------------------
| category_translation |
----------------------------------------------------
| category_id | attribute | language | translation |
----------------------------------------------------
Used query until now:
$query = new Query;
$slugs = $query->select('pt.language , pt.translation , pt.product_id , p.category_id , ct.translation as category')
->from(['pt' => 'product_translation'])
->leftJoin(['p' => 'product'] , 'p.id = pt.product_id')
->leftJoin(['ct' => 'category_translation'] , 'ct.category_id = p.category_id')
->where(['p.is_deleted' => 0,
'p.is_enabled' => 1,
'pt.attribute' => 'slug',
'ct.attribute' => 'slug'
// when adding this it will not return any data at all
// when not adding this it will return double/wrong data
'ct.language' => 'pt.language'
])
->all();
// Group values by id.
$results = ArrayHelper::index( $slugs , null , 'product_id' );
I'm working with a CakePHP 2.x application and using the Tree Behaviour which comes with it - https://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html
My table is called navigations and has the following schema which is provided in the docs:
mysql> DESCRIBE navigations;
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| parent_id | int(10) | YES | | NULL | |
| lft | int(10) | YES | | NULL | |
| rght | int(10) | YES | | NULL | |
| name | varchar(255) | YES | | | |
+-----------+------------------+------+-----+---------+----------------+
5 rows in set (0.02 sec)
My Model, Navigation.php is configured to use the Tree behaviour:
class Navigation extends AppModel {
public $actsAs = array('Tree');
}
I can write data into my table as per the documentation, e.g.
$data['Navigation']['parent_id'] = 3;
$data['Navigation']['name'] = 'United Kingdom';
$this->Navigation->save($data);
However... I have a requirement to store some additional data in the table.
If I add a field to my table, jstree_data of type VARCHAR(255), I cannot write it to the table with the following:
$data['Navigation']['parent_id'] = 3;
$data['Navigation']['name'] = 'United Kingdom';
$data['Navigation']['jstree_data'] = 'foo'; // Attempt to write to 'jstree_data' field in database
$this->Navigation->save($data);
Does anyone know if it's possible to do this? It seems that by using the Tree Behaviour (public $actAs = array('Tree') in the model) you lose the normal functionality of models and being able to save other data.
Background info:
Why am I trying to do this? I'm using jstree on a project. I need to delete all of the existing records before resaving the tree. However, because the id column is an auto_increment I need to store a reference for the "old ID" in jstree_data because that's what's present in the JSON data that comes from jstree. Based on this I can then look up the "new" ID (the auto increment value) and assign that with $data['Navigation']['parent_id'] when resaving the new child elements.
I have multiple checkboxes on a form generated from a model to view which is presented this way:
{{Form::open(array('action'=>'LaboratoryController#store'))}}
#foreach (Accounts::where('accountclass',$i)->get() as $accounttypes)
{{ Form::checkbox('accounttype[]', $accounttypes->id)}}
#endforeach
{{Form::submit('Save')}}
{{Form::close()}}
When I return the Input::all() from my controller store method, it outputs like this:
{"client":"1","accounttype":["2","3","5","12","13","14","16","31","32","33"]}
Now I want to store the accounttypes array values to the accounts table by looping through the array in order to store each values on each rows using the same client id.
The same accounttype will be inserted to the second table but with different data.
So, my accounts table:
+-------------+---------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------------+------+-----+---------+----------------+
| accountno | int(11) unsigned zerofill | NO | PRI | NULL | auto_increment |
| accounttype | int(11) | NO | | NULL | |
| client | int(11) | NO | | NULL | |
| created_at | datetime | NO | | NULL | |
+-------------+---------------------------+------+-----+---------+----------------+
My controller store method:
public function store()
{
$accounttypes = Input::get('accounttype');
if(is_array($accounttypes))
{
for($i=0;$i < count($accounttypes);$i++)
{
// insert data on first table (accounts table)
$accountno = DB::table('accounts')->insertGetId(array('client'=>Input::get('client'),'accounttype',$accounttypes[$i]));
// insert data on the second table (account summary table) using the account no above
// DB::table('accountsummary')...blah blah
}
}
return Redirect::to('some/path');
}
The function seems to work but only for the first array value which is "2". I don't know what's wrong with the code but it seems that the loop doesn't go through the rest of the values. I was testing other loop methods like while and foreach but still the looping variable ($i) returns zero.
I was thinking if laravel controller doesn't allow loops on POST methods.
Your inputs are greatly appreciated. Thanks..
Foreach and DB::insert() works for me.
foreach ($accounttypes as $accounttype) {
DB::insert('INSERT INTO tb_accounts (accounttype,client) VALUES (?,?)', array($accounttype,Input::get('client'));
}
I just need to create separate query to get the last insert id because DB::insertGetId doesn't work the way I want it. But that's another issue. Anyway, thanks.