Magento: Get products without images using collections - magento

I would like to filter a product collection by image not null. The easiest way should be the methods mentioned here, but this doesn't work: the returned collection has no elements.
I think that the problem here is that products that never had an image have no relationship between product/media_gallery tables. As a consequence, when Magento tries to filter using all these conditions, the returned collection is empty. It doesn't take into account that it might not be any type of relationship between the involved tables.
$collection->addAttributeToFilter(array(
array (
'attribute' => 'image',
'like' => 'no_selection'
),
array (
'attribute' => 'image', // null fields
'null' => true
),
array (
'attribute' => 'image', // empty, but not null
'eq' => ''
),
array (
'attribute' => 'image', // check for information that doesn't conform to Magento's formatting
'nlike' => '%/%/%'
),
));
I guess I should use a joinLeft condition, but I have not idea how it should be. Could please anyone help me on this?
I found a very interesting query that should do the trick. But I need to apply this to my collection:
SELECT *
FROM `catalog_product_entity` AS a
LEFT JOIN `catalog_product_entity_media_gallery` AS b ON a.entity_id = b.entity_id
WHERE b.value IS NULL
Thanks

To apply the query to your products collection, you can use
$collection->getSelect()
->joinLeft(
array('_gallery_table' => $collection->getTable('catalog/product_attribute_media_gallery')),
'e.entity_id = _gallery_table.entity_id',
array()
)
->where('_gallery_table.value IS NULL');

Same answer but for magento 2:
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
........
/**
* #var CollectionFactory
*/
public $productCollectionFactory;
........
$collection = $this->productCollectionFactory->create();
$collection->addAttributeToSelect('*');
$collection->getSelect()
->joinLeft(
['gallery_table' => $collection->getTable('catalog_product_entity_media_gallery_value_to_entity')],
'e.entity_id = gallery_table.entity_id',
[]
)
->where('gallery_table.value_id IS NULL');

Related

Laravel insert or update multiple rows

Im new in laravel, and im trying to update my navigation tree.
So i want to update my whole tree in one query without foreach.
array(
array('id'=>1, 'name'=>'some navigation point', 'parent'='0'),
array('id'=>2, 'name'=>'some navigation point', 'parent'='1'),
array('id'=>3, 'name'=>'some navigation point', 'parent'='1')
);
I just want to ask - is there posibility in laravel to insert(if new in array) or update my current rows in database?
I want to update all, because i have fields _lft, _right, parent_id in my tree and im using some dragable js plugin to set my navigation structure - and now i want to save it.
I tried to use
Navigation::updateOrCreate(array(array('id' => '3'), array('id'=>'4')), array(array('name' => 'test11'), array('name' => 'test22')));
But it works just for single row, not multiple like i tried to do.
Maybe there is another way to do it?
It's now available in Laravel >= 8.x
The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. The method's third and final argument is an array of columns that should be updated if a matching record already exists in the database:
Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
I wonder why this kind of feature is not yet available in Laravel core (till today). Check out this gist The result of the query string would look like this: here
I am putting the code here just in case the link breaks in the future, I am not the author:
/**
* Mass (bulk) insert or update on duplicate for Laravel 4/5
*
* insertOrUpdate([
* ['id'=>1,'value'=>10],
* ['id'=>2,'value'=>60]
* ]);
*
*
* #param array $rows
*/
function insertOrUpdate(array $rows){
$table = \DB::getTablePrefix().with(new self)->getTable();
$first = reset($rows);
$columns = implode( ',',
array_map( function( $value ) { return "$value"; } , array_keys($first) )
);
$values = implode( ',', array_map( function( $row ) {
return '('.implode( ',',
array_map( function( $value ) { return '"'.str_replace('"', '""', $value).'"'; } , $row )
).')';
} , $rows )
);
$updates = implode( ',',
array_map( function( $value ) { return "$value = VALUES($value)"; } , array_keys($first) )
);
$sql = "INSERT INTO {$table}({$columns}) VALUES {$values} ON DUPLICATE KEY UPDATE {$updates}";
return \DB::statement( $sql );
}
So you can safely have your arrays inserted or updated as:
insertOrUpdate(
array(
array('id'=>1, 'name'=>'some navigation point', 'parent'='0'),
array('id'=>2, 'name'=>'some navigation point', 'parent'='1'),
array('id'=>3, 'name'=>'some navigation point', 'parent'='1')
)
);
Just in case any trouble with the first line in the function you can simply add a table name as a second argument, then comment out the line i.e:
function insertOrUpdate(array $rows, $table){
.....
}
insertOrUpdate(myarrays,'MyTableName');
NB: Be careful though to sanitise your input! and remember the timestamp fields are not touched. you can do that by adding manually to each arrays in the main array.
I've created an UPSERT package for all databases: https://github.com/staudenmeir/laravel-upsert
DB::table('navigation')->upsert(
[
['id' => 1, 'name' => 'some navigation point', 'parent' => '0'],
['id' => 2, 'name' => 'some navigation point', 'parent' => '1'],
['id' => 3, 'name' => 'some navigation point', 'parent' => '1'],
],
'id'
);
Eloquent Style
public function meta(){ // in parent models.
return $this->hasMany('App\Models\DB_CHILD', 'fk_id','local_fk_id');
}
.
.
.
$parent= PARENT_DB::findOrFail($id);
$metaData= [];
foreach ($meta['meta'] as $metaKey => $metaValue) {
if ($parent->meta()->where([['meta_key', '=',$metaKey]] )->exists()) {
$parent->meta()->where([['meta_key', '=',$metaKey]])->update(['meta_value' => $metaValue]);
}else{
$metaData[] = [
'FK_ID'=>$fkId,
'meta_key'=>$metaKey,
'meta_value'=> $metaValue
];
}
}
$Member->meta()->insert($metaData);
No, you can't do this. You can insert() multiple rows at once and you can update() multiple rows using same where() condition, but if you want to use updateOrCreate(), you'll need to use foreach() loop.
I didn't find a way to bulk insert or update in one query. But I have managed with only 3 queries. I have one table name shipping_costs. Here I want to update the shipping cost against the shipping area. I have only 5 columns in this table id, area_id, cost, created_at, updated_at.
// first get ids from table
$exist_ids = DB::table('shipping_costs')->pluck('area_id')->toArray();
// get requested ids
$requested_ids = $request->get('area_ids');
// get updatable ids
$updatable_ids = array_values(array_intersect($exist_ids, $requested_ids));
// get insertable ids
$insertable_ids = array_values(array_diff($requested_ids, $exist_ids));
// prepare data for insert
$data = collect();
foreach ($insertable_ids as $id) {
$data->push([
'area_id' => $id,
'cost' => $request->get('cost'),
'created_at' => now(),
'updated_at' => now()
]);
}
DB::table('shipping_costs')->insert($data->toArray());
// prepare for update
DB::table('shipping_costs')
->whereIn('area_id', $updatable_ids)
->update([
'cost' => $request->get('cost'),
'updated_at' => now()
]);
in your controller
use DB;
public function arrDta(){
$up_or_create_data=array(
array('id'=>2, 'name'=>'test11'),
array('id'=>4, 'name'=>'test22')
);
var_dump($up_or_create_data);
echo "fjsdhg";
foreach ($up_or_create_data as $key => $value) {
echo "key ".$key;
echo "<br>";
echo " id: ".$up_or_create_data[$key]["id"];
echo "<br>";
echo " Name: ".$up_or_create_data[$key]["name"];
if (Navigation::where('id', '=',$up_or_create_data[$key]["id"])->exists()) {
DB::table('your_table_ name')->where('id',$up_or_create_data[$key]["id"])->update(['name' => $up_or_create_data[$key]["name"]]);
}else{
DB::insert('insert into your_table_name (id, name) values (?, ?)', [$up_or_create_data[$key]["id"], $up_or_create_data[$key]["name"]]);
}
}

How to add categories in Joomla 2.5

Does anyone know how to properly insert new content categories to the DB programatically?
For each post in the categories table, there is also a post saved in the assets table with lft and rgt set.
Is there any native Joomla class I can use for this instead of plain SQL?
Please Please Only use the native classes, which categories will handle for you seamlessly. As soon as you add categories the whole thing will be handled automagically. Just look at any core component to see how.
It is not easy to update the assets table using sql, it is all very specifically managed and part of a complex series of foreign keyed tables.
Extend JTable or JTableContent to handle this.
Here is some code I just whipped together that just uses the JTableCategory class, so it can be used simply on the front or admin side of Joomla
$table = JTable::getInstance('category');
$data = array();
// name the category
$data['title'] = $title;
// set the parent category for the new category
$data['parent_id'] = $parent_id;
// set what extension the category is for
$data['extension'] = $extension;
// Set the category to be published by default
$data['published'] = 1;
// setLocation uses the parent_id and updates the nesting columns correctly
$table->setLocation($data['parent_id'], 'last-child');
// push our data into the table object
$table->bind($data);
// some data checks including setting the alias based on the name
if ($table->check()) {
// and store it!
$table->store();
// Success
} else {
// Error
}
Naturally you would want to get the data pieces set correctly, but these are the core ones to set.
Here is a function I've created just for this purpose, after some digging & experimenting.
It uses core classes, so it needs an access to them (for me it's basically a part of Joomla component).
Mind, it's for Joomla 3, for Joomla 2.5 and before, you need to change JModelLegacy to JModel.
function createCategory( $name, $parent_id, $note )
{
JTable::addIncludePath( JPATH_ADMINISTRATOR . '/components/com_categories/tables' );
$cat_model = JModelLegacy::getInstance( 'Category', 'CategoriesModel' );
$data = array (
'id' => 0,
'parent_id' => $parent_id,
'extension' => 'com_content',
'title' => $name,
'alias' => '',
'note' => $note,
'description' => '',
'published' => '1',
'access' => '1',
'metadesc' => '',
'metakey' => '',
'created_user_id' => '0',
'language' => '*',
'rules' => array(
'core.create' => array(),
'core.delete' => array(),
'core.edit' => array(),
'core.edit.state' => array(),
'core.edit.own' => array(),
),
'params' => array(
'category_layout' => '',
'image' => '',
),
'metadata' => array(
'author' => '',
'robots' => '',
),
);
if( !$cat_model->save( $data ) )
{
return NULL;
}
$categories = JCategories::getInstance( 'Content' );
$subcategory = $categories->get( $cat_model->getState( "category.id" ) );
return $subcategory;
}
You can perhaps use the save() in category.php file.
File location: root\administrator\components\com_categories\models\category.php
It saves the form data supplied to it!
The JOS_assets table is to store the ACL for each asset that is created.
If you do not update this table while programatically creating the category, the default ACL will apply. And when later you open and save the category in the administrative panel, the ACL will be updated as it should have been by core Joomla!.
You can create an SQL query very easily though and update the asset table as well. Its easy to understand once you open the table's content in phpmyadmin.

How to get invoice increment_id on order grid? (Magento 1.7)

I'm trying to get the increment_id from the sales_flat_invoice table to appear on my orders grid.
I've managed to do that, but then it will only show orders which has been invoiced.
The sum it up, what I'm trying to do, is to create a column which contain the increment_id of the invoice (if the order has been invoiced - if not, it should be blank).
The code is used was the following:
In _prepareCollection() :
protected function _prepareCollection()
{
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()
->join(
array('address' => $collection->getTable("sales/order_address")),
'main_table.entity_id = address.parent_id AND address.address_type = "shipping"',
array('postcode')
);
//$collection->join('invoice', 'main_table.entity_id = invoice.order_id', 'increment_id as invoice_id');
$this->setCollection($collection);
return parent::_prepareCollection();
}
In _prepareColumns() :
$this->addColumn('invoice_id', array(
'header' => 'Faktureret',
'index' => 'invoice_id',
'width' => '70px',
'type' => 'text',
));
Thanks and have a beautiful day!
If you want to add the invoice id in the sales order grid then you can use the following code in your prepareCollection() function as
$collection->getSelect()->joinLeft('sales_flat_invoice', 'main_table.entity_id = sales_flat_invoice.order_id', 'increment_id as invoice_id');
By using the following code you will able to get the invoice id from the current order id in sales order grid.
after this add column field as
$this->addColumn('invoice_id',
array(
'header'=> $this->__('Invoice Id'),
'align' =>'right',
'type=' => 'text',
'index' => 'invoice_id',
)
);
For more follow me on
http://www.webtechnologycodes.com
You need to do a LEFT JOIN. Use ->joinLeft. ->join references to ->joinInner
To get invoice details from order detail. you can use
$_orders = $this->getOrders();
$_invoices = $_order->getInvoiceCollection();

Codeigniter - Sending a query result_arry() to a View for form_dropdown

I am using form_dropdown() and have a a problem below:
The form code is:
echo form_dropdown($level,$level_options,'1');
It works when I use
$level_options = array(
'1' => 'Grade 6',
'2' => 'Grade 7'
);
but not when I send a $data['levels'] from controller to view
For reference, the model database retrieve code is:
public function getAllLevelNames() {
$query = $this->db->query("SELECT level_description from levels ORDER BY level_description");
return $query->result_array();
}
The Problem
The problem is I get a dropdown pick list with:
0
Grade 6
1
Grade 7
The indexes are greyed out.
How do I get rid of the indexes?
Thanks in advance!
P.S.
I seem to have the form working now with a data['levels'] sent to the view. Now, the following code in my view seems to return "null" to my controller. Any ideas why please?
$level = array(
'name' => 'level',
'id' => 'level',
'value' => '1',
'maxlength' => '50',
'size' => '50',
'style' => 'width:50%',
);
$level_options = $levels;
echo "<p>Level: ";
echo form_dropdown($level,$level_options,'1');
Thanks!
You'll need to loop through your results_array and create a new array which is formatted correctly.
$query = $this->db->query("SELECT level_description from levels ORDER BY level_description");
$for_dropdown = array();
foreach ($query->result_array() as $row) {
$for_dropdown[$row->level_description] = $row->level_description;
}
return $for_dropdown;
Also I'm not sure how your levels table is structured, but usually you'll have an ID of some sort, which will be the primary key. If you do have that, you can include it in your query and have something like this instead:
$query = $this->db->query("SELECT id, level_description from levels ORDER BY level_description");
... // other code
$for_dropdown[$row->id] = $row->level_description;

Magento sort by entity_id

Does anyone know how to make entity_id visible on the frontend as a sortable attribute? I went to manage attributes and I can't add entity_id as an attribute as it says
"The attribute code 'entity_id' is reserved by system. Please try another attribute code"
So I tried to do a search in the whole database I had Magento on using the following SQL CMD:
select attribute_id from eav_attribute where attribute_code = 'updated_at';
and it returned zero results, I tried other attributes and those showed...
Does anyone know how I can add entity_id as an attribute, as I can't even make it visible because I have no idea what the attribute_id # is even while searching the whole database for that value.
Here is the code I use to make a attribute visible on the admin section of magento:
UPDATE `catalog_eav_attribute`
SET `is_visible` = '1'
WHERE `catalog_eav_attribute`.`attribute_id` = 105;
I've tried searching high and low for days, and trying different variations - so stuck at this point, any help would be great.
I'm using Magento Enterprise 12.2 if that helps, but to be honest the DB is not much different than the community version the only differences are the added modules but when it comes to products it's pretty much the same.
This is surprisingly nasty - I can't see a way to do this simply in the DB, as entity_id isn't a standard attribute (it's really just a key field) and the core code repeats the same logic in three place (urgh).
It's also changed a lot since the older versions of Magento, so many of the tutorials and forum posts on this no longer apply.
What you can do is add "entity_id" in as a new sorting option, similar to the way "Best Value" exists as a sorting option. In the following example I've labelled it "Newest"
The usual caveats apply: You should do this in an extension (or at the least in /local/ overrides) but the three core file methods that need overriding in Community Edition 1.7 are:
Mage_Adminhtml_Model_System_Config_Source_Catalog_ListSort
public function toOptionArray()
{
$options = array();
$options[] = array(//benz001
'label' => Mage::helper('catalog')->__('Newest'),
'value' => 'entity_id'
); //end benz001
$options[] = array(
'label' => Mage::helper('catalog')->__('Best Value'),
'value' => 'position'
);
foreach ($this->_getCatalogConfig()->getAttributesUsedForSortBy() as $attribute) {
$options[] = array(
'label' => Mage::helper('catalog')->__($attribute['frontend_label']),
'value' => $attribute['attribute_code']
);
}
return $options;
}
Then Mage_Catalog_Model_Category_Attribute_Source_Sortby
/**
* Retrieve All options
*
* #return array
*/
public function getAllOptions()
{
if (is_null($this->_options)) {
$this->_options = array(
array(//benz001
'label' => Mage::helper('catalog')->__('Newest'),
'value' => 'entity_id'
), //end benz001
array(
'label' => Mage::helper('catalog')->__('Best Value'),
'value' => 'position'
));
foreach ($this->_getCatalogConfig()->getAttributesUsedForSortBy() as $attribute) {
$this->_options[] = array(
'label' => Mage::helper('catalog')->__($attribute['frontend_label']),
'value' => $attribute['attribute_code']
);
}
}
return $this->_options;
}
And then Mage_Catalog_Model_Config
public function getAttributeUsedForSortByArray()
{
$options = array(
'entity_id' => Mage::helper('catalog')->__('Newest'), //benz001
'position' => Mage::helper('catalog')->__('Position'),
);
foreach ($this->getAttributesUsedForSortBy() as $attribute) {
/* #var $attribute Mage_Eav_Model_Entity_Attribute_Abstract */
$options[$attribute->getAttributeCode()] = $attribute->getStoreLabel();
}
return $options;
}
With those in place, flush the cache and refresh and you can then select to sort by Newest/entity_id in the config and on the category page and on the frontend.
Note: even if you have caching turned off it's still a good idea to flush the cache - parts of the admin are cached even when caching is disabled.

Resources