Laravel inserting data to a table which has 2 "BelongsTo" - php

I want to insert data to one table (called Startups) which has 2 "BelongsTo" relations, I found how to do this with one table (One to Many) in a good Laravel's documentation but I'm beginner in this area and I don't know how to insert data to related to 2 different tables (Categories - Contacts) in one common table (Sturtups), to understand this better please see the image I attached below
Here is my code (please don't pay attention to Sessions, it doesn't matter in that case):
$category_id = Session::get('category_id');
$country_id = Session::get('country_id');
$new_contact = new Contact([
'name' => Session::get('contact_name'),
'phone' => Session::get('contact_phone'),
'email' => Session::get('contact_email')
]);
$country = Country::find($country_id);
$country->contacts()->save($new_contact);
$new_startup = new Startup([
'name' => Session::get('startup_name'),
'description' => Session::get('startup_description'),
'url' => Session::get('startup_url'),
'logo' => Session::get('logo_name')
]);
$category = Category::find($category_id);
$category->startups()->save($new_startup);
$contact = Contact::find( $country->contacts()->id );
$contact->startups()->save($new_startup);
Database Relations image:
image of relations between tables in the DB
Additional info: I have this error:
"General error: 1364 Field 'contact_id' doesn't have a default value"
I know why that error happens (I'm trying to create Startup without id of contact)
I just want to know how insert data in that case
Thank you guys for any help!

Answer to your question is:
make that field nullable in database migration so this error will not occur
$table->unsignedInteger('contact_id')->nullable();

Related

Laravel update specific column in database 'cost' and add supplier_id to another database table

i'm working with sensitive data hope you can help find if there any wrong in code's writing
i have list of suppliers in my database i added column 'cost'
i'm trying to update and insert cost for existing suppliers from specific query
and i created model and migration to get foreign keys too by adding the puled supplier id from the query
....
$suppliers_data = $suppliers_query->fetchall(PDO::FETCH_ASSOC);
foreach ($suppliers_data as $supplier_data) {
$supplier_name = $supplier_data['supplier_name'];
$cost_rate = $supplier_data['Cost'];
if (!Supplier::where('supplier', $supplier_name)->exists()) {
Supplier::insert([
'supplier' => $supplier_name,
'cost_rate' => $cost_rate
]);
} else {
Supplier::update([
'cost_rate' => $cost_rate // does this will update cost for the current supplier ?
]);
}
$supplier_id = Supplier::where('supplier', $supplier_name)->pluck('supplier_id');
Test::insert($supplier_id);
}
$supplier_count = test::count();
Test::update(['test_data_count' => $supplier_count]);
Updating table data with supplier name is not correct here I believe. Instead of using supplier name in where condition using particular supplier id is recommended for better application. Names can be duplicate so its not a good idea to use supplier name in where.
In your current code I have 2 things to say :
You need to add where in update eloquent to work properly
Supplier::where('supplier', $supplier_name)
->update([
'cost_rate' => $cost_rate // this will update cost for the current supplier
]);
Or to minimalize the code you can use updateorCreate method instead of making insert and update in the if() else() condition
Supplier::updateOrCreate(
['supplier' => $supplier_name],
['cost_rate' => $cost_rate]
);

Laravel Eloquent - bulk update with whereIn array

I'm working on a project where I need to update many rows at once per coin Id.
in order to update all coins values, Im getting them all from the API, so for example I have back:
$coinsList= [[id="bitcoin", symbol="btc", name="Bintcoin"],[id="etherium", symbol="eth", name="Etherium"]];
and the database table columns is the following:
**| id | coin_id | symbol | name |**
now, I want to update all values to the database, according to the id only, so this is what I did:
// first get ids from my table
$exist_ids = Coinlist::all('coin_id')->pluck('coin_id')->toArray();
//get all ids to update (to ignore other ids):
$updatable_ids = array_values(array_intersect($exist_ids, $allCoinIds));//result for example is: array("bitcoin","etherium");
//and now, update the database:
Coinlist::whereIn('coin_id', $updatable_ids)
->update([
'symbol' => $coinsList[$key]['symbol'],
'name' => $coinsList[$key]['name'],
'updated_at' => now()
]);
the problem is, I don't have the "$key" in order to update the right row, what am I missing here?
Thanks!
Here is a good way to solve it:
in the beginning, I used this library: https://github.com/mavinoo/laravelBatch
to update many dynamic rows, but it was really slow, then thanks to Yasin, I moved to: https://github.com/iksaku/laravel-mass-update and now it works way better.
the implementation is simple, add a simple code to the Model class, then add:
User::massUpdate(
values: [
['username' => 'iksaku', 'name' => 'Jorge González'],
['username' => 'gm_mtz', 'name' => 'Gladys Martínez'],
],
uniqueBy: 'username'
);
while uniqueBy is the key for the row, and add other columns values to change them dynamically.

CakePHP 4 - saving associated data not working with 3 simple tables

I have an application in CakePHP 4 and am having problems saving associated model data. I have read Saving Associated Data in the Cake documentation but it's very unclear how this applies especially in my use-case.
The application has 3 tables which are relevant to this question:
items
sizes
items_sizes_wanted
The application allows users to request items of clothing (items) and the form to input/save such an item has a dropdown of different sizes (sizes). Each size has a unique ID. A user can select one or more size when saving an item. The items_sizes_wanted table is supposed to hold one (or more) rows depending on the sizes the user selected, with the corresponding item ID. For example if they saved sizes 2, 3 and 4 for Item 999 there would be 3 rows in this table:
size_id | item_id
--------|---------
2 | 999
3 | 999
4 | 999
The code has been baked and the associations in the Table classes look ok:
// src/Model/Table/ItemsSizesWantedTable.php
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('items_sizes_wanted');
$this->belongsTo('Items', [
'foreignKey' => 'item_id',
'joinType' => 'INNER',
]);
$this->belongsTo('Sizes', [
'foreignKey' => 'size_id',
'joinType' => 'INNER',
]);
}
The Entity class for the item also looks ok:
// src/Model/Entity/Item.php
// #property \App\Model\Entity\ItemsSizesWanted[] $items_sizes_wanted
protected $_accessible = [
// ...
'items_sizes_wanted' => true,
// ...
];
In the form where the item gets saved (src/templates/Items/add.php) I have used the Form Helper and named it using dot notation:
<?php
// Note that $sizes is an array of key/value pairs from the
// 'sizes' table.
?>
<?= $this->Form->control('items_sizes_wanted.size_id', ['options' => $sizes, 'multiple' => 'multiple']) ?>
When rendered in the browser this produces a valid array syntax name. The <option>'s rendered inside all have valid ID's, i.e. the ones from the sizes table.
<select name="items_sizes_wanted[size_id]" multiple="multiple">
When I save the data in my Controller (src/Controller/ItemsController.php) using the following:
public function add()
{
$item = $this->Items->newEmptyEntity();
if ($this->request->is('post')) {
$item = $this->Items->patchEntity($item, $this->request->getData());
// Edit: some of the entity properties are manually set at this point, e.g.
$item->item_status = 'Wanted';
if ($this->Items->save($item)) {
$this->Flash->success(__('Your item has been listed.'));
}
}
}
The data is saved correctly to the items table and the flash success message, "Your item has been listed." is displayed in the browser.
But - no data is written to items_sizes_wanted.
I'm unsure why this is. The linked docs don't specifically say how the Form Helper should be used, so I'm assuming my syntax for that form field is correct, but it might not be.
If I debug the entity after pressing Save using debug($item); die; in the Controller it has 'items_sizes_wanted' => [ ] even though I selected multiple size options using the form.
Please can somebody help as I'm lost as to what's going wrong here?
Disclaimer: I do not know CakePHP well, but I think I either know the solution, or can at least point you in the right direction.
The reason you're only getting the one selected size, instead of multiple, is because the generated input fields are named items_sizes_wanted[size_id], however, in order for PHP to parse multiple values into an array, they need to be named items_sizes_wanted[size_id][]. When the request parameter ends with [], then PHP will properly parse all request properties into an array.
For example: Here's var_dump($_POST); of a request containing the POST body of items_sizes_wanted[size_id][]=A&items_sizes_wanted[size_id][]=B&items_sizes_wanted[size_id][]=C
array (size=1)
'items_sizes_wanted' =>
array (size=1)
'size_id' =>
array (size=3)
0 => string 'A' (length=1)
1 => string 'B' (length=1)
2 => string 'C' (length=1)
Compare that to a POST body of items_sizes_wanted[size_id]=A&items_sizes_wanted[size_id]=B&items_sizes_wanted[size_id]=C (notice the empty braces at the end of each have been removed):
array (size=1)
'items_sizes_wanted' =>
array (size=1)
'size_id' => string 'C' (length=1)
This is the part where I'm less familiar with CakePHP. I looked over the code
for CakePHP's FormHelper, and based on the template code, I think you need to change your form code in add.php to be something like this (reformatted for readability):
<?php
// Note that $sizes is an array of key/value pairs from the
// 'sizes' table.
?>
<?=
$this->Form->control(
'items_sizes_wanted.size_id',
[
'options' => $sizes,
'multiple' => 'multiple'
'type' => 'selectMultiple'
]
)
?>
Based on the __call() method in FormHelper, You might also be able to write it like this:
$this->Form->selectMultiple(
'items_sizes_wanted.size_id',
[
'options' => $sizes,
'multiple' => 'multiple'
]
);
However, I'm not familiar with the nuances between creating a control($fieldName, $options) and inputType($fieldName, $options), so they might produce different outputs.
I'm currently working in a project in CakePHP 4.x. My project also have many to many associations and it saves ok in the tables, but CakePHP baked it quite differently from yours. Let me show you the differences, maybe it is of some help.
I'll "translate" the names of my entities, tables, etc., to the ones used in your question, ok?
First, a brief: in my project, cake didn't bake models (entity and table) for the relational table. The relational table don't have its own models, and is only refered to in the initialize method from the ItemsTable and WantedSizesTable. There are also minor changes in the Item and WantedSize entities and in the view.
Second, your entity names doesn't comply with Cake's naming conventions, which can lead to many issues. This can even be the cause to the problems you're enduring now. I have changed some names to comply with them, but I'd suggest to you to read it thoroughly: https://book.cakephp.org/4/en/intro/conventions.html.
Third and more important, lets start.
My many-to-many relational mySQL tables doesn't have their own Table models. My SQL does indeed have a items_wanted_sizes table, but the CakePHP project does NOT have corresponding models called ItemsWantedSizesTable nor ItemsWantedSizes. It does have ItemsTable and WantedSizesTable tables and Item and WantedSize entities, and it's all.
Let's see the Table Models. The relational mySQL table items_wanted_sizes is refered only in the tables initialize method of both table models in PHP, like this:
// ItemsTable.php
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('items');
$this->setDisplayField('item_name');
$this->setPrimaryKey('id');
// ...
// Other associations...
// ...
// The relational mysql table only shows here:
$this->belongsToMany('WantedSizes', [
'foreignKey' => 'item_id', // Item Id field from the relational table
'targetForeignKey' => 'wanted_size_id', // Size Id field from the relational table
'joinTable' => 'items_wanted_sizes',
]);
}
The same happens on WantedSizesTable:
// WantedSizesTable.php
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('wanted_sizes');
$this->setDisplayField('wanted_size_name');
$this->setPrimaryKey('id');
// ...
// Other associations...
// ...
// The relational mysql table only shows here:
$this->belongsToMany('Items', [
'foreignKey' => 'wanted_size_id', // Size Id fieldname from the relational table
'targetForeignKey' => 'item_id', // Item Id fieldname from the relational table
'joinTable' => 'items_wanted_sizes',
]);
}
Regarding to the entities models, I also don't have a relational entity model. Both Item and WantedSize entity models refer to each other, but, contrary to your case, they don't refer to the relational table (only to each other):
// src/Model/Entity/Item.php
// #property \App\Model\Entity\WantedSize[] $wanted_sizes // NOT item_wanted_sizes
protected $_accessible = [
// ...
'wanted_sizes' => true, // NOT item_wanted_sizes
// ...
];
Same in WantedSize:
// src/Model/Entity/WantedSize.php
// #property \App\Model\Entity\Item[] $items // NOT item_wanted_sizes
protected $_accessible = [
// ...
'items' => true, // NOT item_wanted_sizes
// ...
];
Now we saw our models, lets jump the add (or edit) action view. With the associations correctly set, I only needed to do this:
// src/templates/Items/add.php
echo $this->Form->control('wanted_sizes._ids', ['options' => $wantedSizes]);
I didn't even needed to tell FormHelper it's a multiselect, because it is in the table configurations.
The HTML generated is quite different from yours (like 404 also answered above):
<select name="wanted_sizes[_ids][]" multiple="multiple" id="wanted-sizes-ids">
<option value="1">Some wanted size...</option>
<!-- ... -->
</select>
This worked perfectly fine for me, saving data in the relational table in mysql.
In Cakephp4 one thing to check. If the entities are not showing the associated data after being patched prior to saving. You can test by dumping the entity after its patched in the controller.The associated data should show there.
$discount = $this->Discounts->patchEntity($discount, $this->request->getData());
dd($discount);
Check the Entity. Is the associated data in the $_accessible array? The fields that you update need to be in this array but also the associated models/tables.
class Discount extends Entity
{
protected $_accessible = [
...
'products' => true,
...
];
}
https://api.cakephp.org/4.0/class-Cake.ORM.Entity.html#$_accessible

php yii2 how to make automaticly id in query yii2 insert?

i have a code like this ,
$request = Yii::$app->request;
$post = $request->post();
$filesettingid = $post['filesettingid'];
$checkboxValue = $post['selection'];
for($i=0;$i<sizeof($checkboxValue);$i++) {
$store = Yii::$app->db->createCommand('SELECT id FROM store WHERE port='.$checkboxValue[$i])->queryAll();
$storeid = $store[$i]['id'];
Yii::$app->db->createCommand()->insert('tes',
[
'id' => $i+1,
'filesetting_id' => $filesettingid,
'store_id' => $storeid
])->execute();
}
what i want is, each i insert the new data, id will generate automaticly like 1,2,3,4.
the problem in above code is, the ID always be 1.
is it possible to make it real?
so what i want is :
First time insert, id = 1, second is id = 2 , and that is happen automatically.
Have you considered setting database engine to auto increment values with each insert?
Take as an example Yii2 default user table. ID filed is auto incremented, and you don't have to worry about setting it problematically. Every time you send a new insert engine increments ID filed by itself.
See default migration under "advanced template"\console\migrations\m130524_201442_int. (your file name might be different depending on the Yii2 version)
$this->createTable('{{%user}}', [
'id' => $this->primaryKey(),
'username' => $this->string()->notNull()->unique(),
'auth_key' => $this->string(32)->notNull(),
'password_hash' => $this->string()->notNull(),
'password_reset_token' => $this->string()->unique(),
'email' => $this->string()->notNull()->unique(),
'status' => $this->smallInteger()->notNull()->defaultValue(0),
.........
], $tableOptions);
When setting 'id' to primary key database automatically knows to auto increment it. If you already have a table the ID field is not primary key you can use the followign migration:
$this->alterColumn('{{%databaseName}}', 'columnName', $this->integer()->notNull().' AUTO_INCREMENT');
You can also set it from management console, or run a SQL query. Depending on database engine you are using this might look a little different but the concept is the same.
MYSQL:
In MySQL workbench right click on table in question, select Alter Table and check NNm and AI next to column you want auto increment. See Screenshot
Or run command:
ALTER TABLE `dbName`.`nameOfTheTable` MODIFY `columnName` INT AUTO_INCREMENT NOT NULL;
I am a bit rusty on my SQL, so if it does not work let me know I will get you right command.
Hope this helps. Good luck.

How to get data from Relations with joins in yii

I am beginner in Yii, So I am asking this question.
I have three different tables.
First Table
First table is language(id, language_name)
// id is primary key.
Second Table
Second Table is verse(id, topic_id, surah_id, verse_text)
// id is primary key,
Third Table
Third table is verse_translations(id, verse_id, language_id, translations_text)
// id is primary key, language_id is foreign key references with language table,
// verse_id is foreign key references with verse table.
Now My Question is.
I want to get the list of languages of available translations with specific verse_id. ? For that i want to make relations in verse model file that will return an available languages in my view, so how to get result in view also.? and what will be the changes in verse model, view and controller if any changes occur.
I have written MySQL query which is in below.
SELECT language.language_name from language
Inner Join verse_translations ON verse_translations.language_id = language.id
Where verse_translations.verse_id = 1
But i need this in Yii.
I have generated verse model through gii code generator.
My Verse Model Relations function.
public function relations()
{
return array(
'sorah' => array(self::BELONGS_TO, 'Sorah', 'sorah_id'),
'topic' => array(self::BELONGS_TO, 'Topic', 'topic_id'),
'verseFeedbacks' => array(self::HAS_MANY, 'VerseFeedback', 'verse_id'),
'verseImages' => array(self::HAS_MANY, 'VerseImages', 'verse_id'),
'verseLinks' => array(self::HAS_MANY, 'VerseLinks', 'verse_id'),
'verseTafseers' => array(self::HAS_MANY, 'VerseTafseer', 'verse_id'),
'verseTranslations' => array(self::HAS_MANY, 'VerseTranslations', 'verse_id'),
'language_name' => array(self::HAS_MANY, 'Language', 'id'),
);
}
I wrote you your sql code,
$result = Yii::app()->db->createCommand()
->select('l.language_name')
->from('language l')
->join('verse_translations vt' , 'l.id = vt.language_id ')
->join('verse v' , 'vt.id = v.id')
->where('v.id = :var' , array(':var'=>1))
->queryAll();
btw I didn't read all your post, just read your sql :D
UPDATE: if you define your relations in mysql before you generate model files, you get the relations generated for you.this is the easiest way possible, then you can do this:
$vers = Ver::model()->findByPk(1);
$allLangs = $vers->language_name; // this will give you an array of Language Model back
let me know what did
cheers
You can easily get the list of available translated languages from language table.
Let see first.
'verseTranslations' => array(self::HAS_MANY, 'VerseTranslations', 'verse_id'),
this relation will take all the rows of verse translation of specific verse id, mean if you have 10 different translation in 10 different languages with verse_id 1, it will display all. Now you can see in question verse_translation table have language_id.
So we can get all languages by that language_id.
Now we make another relation which is relating to language_id through verseTranslations, and this relation will display all the translated languages.
'verse_lang' => array(self::HAS_MANY, 'Language', array('language_id'=>'id'), 'through'=>'verseTranslations'),
So as i have written a Sql Query is equivalent to these two relations.
'verseTranslations' => array(self::HAS_MANY, 'VerseTranslations', 'verse_id'),
'verse_lang' => array(self::HAS_MANY, 'Language', array('language_id'=>'id'), 'through'=>'verseTranslations'),
On view, we can easily access it by var_dump($data->verse_lang)
That's it.
for understanding relations. You may read carefully to this link.
http://www.yiiframework.com/doc/guide/1.1/en/database.arr#relational-query-with-through
Hope it will help.
If you need any help then leave a message in comment box.
Thanks.

Categories