Updating a Magento product attribute's database field type after creation - magento

The scenario: You've created a product attribute programmatically using a database migration. Several months later you'd like to change that attribute from a VARCHAR to a TEXT field type.
How do you change the field type of an EAV attribute after creation while preserving the data?
My gut feeling is that this isn't supported directly through Magento's setup classes, due to the myriad of tables that would need to be touched, records that would need to be updated and content that would need to be copied from table to table.

I'm not going to pretend this is the prettiest solution around, and I'm doubtful it's database agnostic, but here's my solution:
<?php
/** #var $this Mage_Eav_Model_Entity_Setup */
$this->startSetup();
$attribute_id = $this->getAttribute(
Mage_Catalog_Model_Product::ENTITY,
'your_attribute_code',
'attribute_id'
);;
if (!is_numeric($attribute_id)) {
Mage::throwException("Couldn't run migration: Unable to find attribute id");
}
/** #var Varien_Db_Adapter_Pdo_Mysql $connection */
$connection = $this->getConnection();
$connection->beginTransaction();
/**
* Copy the data from the VARCHAR table to the TEXT table.
*/
$connection->query("
INSERT INTO catalog_product_entity_text
(entity_type_id, attribute_id, store_id, entity_id, value)
SELECT
entity_type_id, attribute_id, store_id, entity_id, value
FROM catalog_product_entity_varchar
WHERE attribute_id = ?
",
array($attribute_id)
);
/**
* Update eav_attribute to use the text table instead of the varchar.
*/
$connection->query("UPDATE eav_attribute SET backend_type = 'text' WHERE attribute_id = ?", array($attribute_id));
/**
* Delete the attribute values from the VARCHAR table.
*/
$connection->query("DELETE FROM catalog_product_entity_varchar WHERE attribute_id = ?", array($attribute_id));
$connection->commit();
$this->endSetup();

Yeah I confirm it's not supported.
You could try to update tables with SQL but it will be a pain ...
I would export all your products, apply the upgrade script that modify your attribute backend table and re-import all your products.
That way magento will fill automatically the new table (catalog_product_entity_text) used by your attribute.
After that, you should clean your varchar table to delete unused values linked to your products (values that will be never deleted nor updated as your attribute's product is now TEXT)

Related

How to get specific columns from relation table in laravel?

I am trying to fetch soecific columns data from relational table but it is giving me null
$allConsignments = Consignment::query();
$allConsignments->select(['id','customer_reference'])->with('customers:name,id')->orderBy('id', 'desc')->limit(5000)->get();
When I don't use select() then it gives correct data .
like this
$allConsignments = Consignment::query();
$allConsignments->with('customers:name,id')->orderBy('id', 'desc')->limit(5000)->get()
it is working but I also need specific columns from Consignment Table. what could be the reason?
You can also do like this.
$allConsignments = Consignment::query();
$allConsignments::with('customers:name,id')->orderBy('id', 'desc')->limit(5000)->get(['id','customer_reference']);
Actually, I also need to select the foreign key column from the table on which relationship is based. for example in my case I have customer_id in consignment table so it should be like that
$allConsignments = Consignment::query();
$allConsignments->select('id','customer_reference','customer_id')->with('customers:name,id')->orderBy('id', 'desc')->limit(5000)->get();
I need to select customer_id as well

Replace $request->all() with only non empty form fields

is it possible to replace $request->all() in the below line with only fields that are not empty in submitted form.
$product = Product::create($request->all());
when some form fields are empty, the query generated is something like
insert into `products` (`name`, `companyname`, `ip`, `host`, `status`, `language`, `updated_at`, `created_at`) values (efesar, ewrewrewre, , , , , 2018-04-18 10:29:11, 2018-04-18 10:29:11))
And that's returning error.
This would get you only the fields with values:
$data = collect($request->all())->filter()->toArray();
$product = Product::create($data);
But you should get from the request only the fields which are appropriate for your Product model or better yet, add validation for them. Depending on what you need, you might have to change some your table fields to be nullable to be able to save empty fields.
Its not a problem to submit null fields. Just make them nullable in migration file:
$table->string('ip')->nullable();
$table->string('host')->nullable();
$table->string('status')->nullable();
$table->string('language')->nullable();

where are category NAMES stored in magento?

Seems like this should be a findable question but I could not locate it.
Where is the category NAME stored in the magento database? I can see catalog_category_entity has the key ID, and then there are the other EAV tables. But I cannot find the actual name of the category stored in any table prefixed by catalog_category.
At least with products the catalog_products_entity table has the SKU (some human-readable value) in it.
The categories names are in the table catalog_category_entity_varchar
The request you are looking for :
select cat.*, cv.value as `category_name` from `catalog_category_entity` as cat
join `catalog_category_entity_varchar` as cv on cat.entity_id = cv.`entity_id`
join `eav_attribute` as att on att.`attribute_id` = cv.`attribute_id`
join `eav_entity_type` as aty on att.`entity_type_id` = aty.`entity_type_id`
where aty.`entity_model` = 'catalog/category' and att.`attribute_code` = 'name' and cv.`store_id` = 0
Please note that this is the name of your categories for your default store view.
If you do have multiple store or store view in your magento you just have to adapt the condition cv.`store_id` = 0.
The list of your stores can be found in the table core_store
'name' is an EAV attribute of type VARCHAR so you can find the values for that attribute on the catalog_category_entity_varchar table, but it contains all values for attributes that are type VARCHAR, so to query for only the values for the name attribute you have to find what the attribute id is, which you can find in that eav_attributes table using something like:
SELECT * FROM `eav_attribute` WHERE `entity_type_id` = ##CATEGORY ENTITY TYPE ID## AND `attribute_code` = 'name'
If you have ID's with you then this works:
SELECT DISTINCT value, entity_id FROM catalog_category_entity_varchar WHERE entity_id IN (ID's of the category) AND attribute_id = 111 AND STORE = 0
Make sure to replace "ID's of the category" with ID's seperated by commmas and Store ID too. ) is default Store ID.

Add a column, with a default value, to an existing table in oracle

I created a table named- books and have a column in that by the title 'color' . Initially I have null values in the column 'color'. Now, when I run the following query :
alter table books modify color default 'blue';
schema is formed but on doing select *from books , all the values in column color are still null. What would be the correct query to fire?
here is the link:
http://sqlfiddle.com/#!4/f4210/1
Of course. Alter table just changes the table structure but not the content. New entries will get the default.
To update the existing values run a sql-update query like:
update books set color='blue' where colore is null;
If you now inserting into table then only will come with default values. This statement don't know about previous contents of this table. In non technical language, you are telling oracle to do so now on-wards. This statement will not perform check to old values.
alter is ok for the next values to be inserted: try to insert lines without specifying a value for column color, value should be blue.
But this does not work for existing values, for which you just need an update:
update books set color = 'blue';
Hi this query will be used to add column with default value in existing table in oracle.
alter table <table_name> add <column_name> <contraint> default <default_value> not null;
example:
alter table books add record_status number(1,0) default 1 not null;
alter table books add color varchar(20) default 'blue' not null;

Soft delete on a intermediate table for many-to-many relationship

How do I set soft delete on an intermediate table which is connecting two different types of entities? I've added deleted_at column, but the docs say that I need to put this into the model:
protected $softDelete = true;
Of course, I don't have a model for an intermediate table.
Any idea?
You can put a constraint on the Eager Load:
public function groups()
{
return $this
->belongsToMany('Group')
->whereNull('group_user.deleted_at') // Table `group_user` has column `deleted_at`
->withTimestamps(); // Table `group_user` has columns: `created_at`, `updated_at`
}
Instead of HARD deleting the relationship using:
User::find(1)->groups()->detach();
You should use something like this to SOFT delete instead:
DB::table('group_user')
->where('user_id', $user_id)
->where('group_id', $group_id)
->update(array('deleted_at' => DB::raw('NOW()')));
You could also use Laravel's Eloquent BelongsToMany method updateExistingPivot.
$model->relation->updateExistingPivot($relatedId, ['deleted_at' => Carbon\Carbon::now()]);
So to use #RonaldHulshof examples you have a User model with a groups relationship which is a belongsToMany relationship.
public function groups() {
return $this->belongsToMany(Group::class)->whereNull('groups_users.deleted_at')->withTimestamps();
}
Then in order to soft delete the pivot table entry you would do the following.
$user->groups()->updateExistingPivot($groupId, ['deleted_at' => Carbon\Carbon::now()]);
As far as I understand it; an intermediate table is simply a length of string attaching one tables record to a record in another table and as such it does not require a soft delete method.
To explain, imagine you have a Users table and a Groups table, each user can have more than one Group and each Group can belong to more than one User. Your pivot table may be User_Group or something like that and it simply contains two columns user_id and group_id.
Your User table and Group table should have a deleted_at column for soft deletes, so when you "delete" say a Group, that group association will not appear in $User->Groups() while the pivot table row has remained unaffected. If you then restore that deleted Group, it will once again appear in $User->Groups().
The pivot table row should only be affected if that group record is hard deleted, in which case the pivot rows should also be hard deleted.
Now I have explained why I do not believe you need to add soft delete to a pivot table; is there still a reason why you need this behavior?

Resources