Modify single Item of Laravel Collection without mapping every single item - laravel

I loop trough an eloquent Collection and I want to add the data to another Collection called "$tagCollection". If an entry with the same tag_id already exists I only want to increase the rating-column for the existing entry.
At the moment it looks like this. Has anyone an Idea?
$tagCollection = collect();
$entries->each(function($entry) use($tagCollection){
$tagId = $entry->tag_id;
//something like this
if($tagCollection->contains('tag_id', $tagId)){
$tagCollection->update ('rating' => $oldRating + 0.5)
} else{
$tagCollection->push(array(
'tag_id' => $tagId,
'rating' => 0.35
));
}
});
I also tried to use ->pull() to remove the Item out of the Collection and then push it again with the new rating but I also do not know how

Can you do it with array instead of collection? For example:
$tagArray = [];
$entries->each(function ($entry) use (&$tagArray) {
if (isset($tagArray[$entry['tag_id']])) {
$tagArray[$entry['tag_id']] += 0.5;
} else {
$tagArray[$entry['tag_id']] = 0.35;
}
});

If the end goal is to update all the entries present in $entries that belong to a specific $tagId, then you can do this
$entryIds = $entries->where('tag_id',$tagId)->pluck('id')->toArray();
Entry::whereIn('id', $entryIds)->update(['rating' => \DB::raw('rating + 0.5')]);
And thats it.

Related

Setting repeater values from database

I have this code
$w("#repeater1").forEachItem( ($item, itemData, index) => {
$item("#image2").src = reviews[count].ReviewerImage;
$item("#text17").text = reviews[count].ReviewerComment;
$item("#text28").text = reviews[count].ReviewerNickname;
$item("#ratingsDisplay1").value = reviews[count].ReviewerRating;
count++;
} );
When this runs, it updates the information in the repeater based on the information in the array reviews. The nickname, comment, and image all are being displayed correctly, but the ratings on the repeater are not updating with the rest of the data. I have tried console logging the 'reviews[count].ReviewerRating' which outputs a value of 5 for each item, but when the page loads, it the ratings display only shows 3 stars. Is there an event I need to trigger to update the reviews?
$w("#repeater1").forEachItem( ($item, itemData, index) => {
$item("#image2").src = reviews[count].ReviewerImage;
$item("#text17").text = reviews[count].ReviewerComment;
$item("#text28").text = reviews[count].ReviewerNickname;
$item("#ratingsDisplay1").rating= reviews[count].ReviewerRating;
count++;
} );
Had to set the ratings display with .rating instead of .value

Save multiple inputs Laravel 5.6

I'm trying to save a data to my database coming from 2 inputs which has multiple values. The scenario is that after a product has been saved, data will be save to my another table with columns 'product_id','price','size'. How ever when I tried to run my code, only the first value is saved in the column 'size', the data in 'price' are fine.
<input name="fix_size[]">
<input name="fix_price[]">
foreach($request->fix_price as $prc){
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
foreach($request->fix_size as $size){
$cprice->size = $size;
}
$cprice->save();
}
Remember, fix_size and fix_price are arrays.
You have to get the respective pairs of each fix_size and fix_price. So you have to monitor the index in the loop.
This is one of the possible solution in your problem:
$fix_sizes = $request->fix_size;
foreach($request->fix_price as $i => $prc){
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
$cprice->size = $fix_sizes[$i];
$cprice->save();
}
I may suggest to you to master the basic principles of programming and learn to debug codes by yourself.
Try this
foreach($request->fix_price as $prc){
foreach($request->fixed_size as $size){
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
$cprice->size = $size;
$cprice->save();
}
}
You could try this:
foreach($request->fix_price as $key => $prc) {
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
$cprice->size = $request->input('size')[$key];
$cprice->save();
}
The problem you had is because you loop over all elements inside the main loop and keeping only the last element. In other words, in the foreach loop, you are constantly overriding the $cprice->size property with the last you find.
Now with this code you access the "size" which has the same index as your "price".

how to change the color of each crud entry when ajax table is enabled?

I am using laravel backpack and recently enabled $this->crud->enableAjaxTable(); in my crud because there was a lot of data to show.
But now I am not able to color my crud entries depending upon a expiry_date as I was doing before by overriding list.blade.php like this:
#if (!$crud->ajaxTable())
#foreach ($entries as $k => $entry)
<?php
use Carbon\Carbon;
$today_date = Carbon::now();
$data_difference = $today_date->diffInDays(Carbon::parse($entry->expiry_date), false);
if($data_difference <= 7 && $data_difference >= 0) {
$color="#FF9900";
} elseif($data_difference < 0) {
$color="#EA2C12";
} elseif($data_difference > 7) {
$color="#539E05";
}
?>
<tr data-entry-id="{{ $entry->getKey() }}" style="color: {{$color}}">
Maybe because of this:
#if (!$crud->ajaxTable())
I tried to customize the AjaxTable.php search query using this link but I was not successful. Here is the code I tried in my ExampleCrudController by overriding search query of ajax:
public function search()
{
$this->crud->hasAccessOrFail('list');
// create an array with the names of the searchable columns
$columns = collect($this->crud->columns)
->reject(function ($column, $key) {
// the select_multiple, model_function and model_function_attribute columns are not searchable
return isset($column['type']) && ($column['type'] == 'select_multiple' || $column['type'] == 'model_function' || $column['type'] == 'model_function_attribute');
})
->pluck('name')
// add the primary key, otherwise the buttons won't work
->merge($this->crud->model->getKeyName())
->toArray();
// structure the response in a DataTable-friendly way
$dataTable = new \LiveControl\EloquentDataTable\DataTable($this->crud->query, $columns);
// make the datatable use the column types instead of just echoing the text
$dataTable->setFormatRowFunction(function ($entry) {
$today_date = Carbon::now();
$data_difference = $today_date->diffInDays(Carbon::parse($entry->expiry_date), false);
if($data_difference <= 7 && $data_difference >= 0) {
$color="#FF9900";
} elseif($data_difference < 0) {
$color="#EA2C12";
} elseif($data_difference > 7) {
$color="#539E05";
}
// get the actual HTML for each row's cell
$row_items = $this->crud->getRowViews($entry, $this->crud, $color);
// add the buttons as the last column
if ($this->crud->buttons->where('stack', 'line')->count()) {
$row_items[] = \View::make('crud::inc.button_stack', ['stack' => 'line'])
->with('crud', $this->crud)
->with('entry', $entry)
->render();
}
// add the details_row buttons as the first column
if ($this->crud->details_row) {
array_unshift($row_items, \View::make('crud::columns.details_row_button')
->with('crud', $this->crud)
->with('entry', $entry)
->render());
}
return $row_items;
});
return $dataTable->make();
}
So my question is how can I color my crud entries depending upon expiry_date when enableajaxtable is active in laravel backpack?
When using AjaxDataTables, the rows no longer taken from the DB directly and outputed as HTML, but taken from the DB with an AJAX call. So your previous code wouldn't work, I'm afraid.
The best way I can think of to achieve the same thing would be to use a custom view for this CRUD panel, with $this->crud->setListView('your-view');. This would allow you to setup some custom JavaScript in that file, to modify DataTables.js to color the rows before it puts them in the table.
A cleaner alternative, if you're using Backpack\CRUD 3.2+, would be to customize the list.js file, to have all that logic there.
Hope it helps!

Active Record Delete works false

I try to delete entries in the database with the active records of Yii. But I think it works really weird.
I want to delete all records of my table where vehicle_id = the given id and plug_id NOT IN (given string)
I tried a lot of ways and nothing worked but this
$query = "delete from `vehicle_details` where `vehicle_id`= ".$vehicle->id." AND `plug_id` NOT IN (".implode(',', array_map(function($item) {
return $item->type;
}, $vehicleDetails->plug)).")";
$command = Yii::app()->db->createCommand($query);
$command->execute();
But why isn't this working???
VehicleDetail::model()->DeleteAllByAttributes(
array('vehicle_id' => $vehicle->id),
array('condition' => 'plug_id NOT IN (:ids)',
'params' => array('ids' => implode(',', array_map(function($item) {
return $item->type;
}, $vehicleDetails->plug)))));
Or this:
VehicleDetail::model()->deleteAll(' vehicle_id = :vehicleId AND plug_id NOT IN (:ids)', array('vehicleId' => $vehicle->id, 'ids' => implode(',', array_map(function($item) {
return $item->type;
}, $vehicleDetails->plug))));
But if I make and Find by attributes out of this query it works well and returns the correct data.
I hope you can explain it to me.
Your code does not work because of wrong arguments passed in the methods. Problems occur when YII tries to build CDbCriteria object using your array arguments. Fortunetly, you can build a CDbCriteria by yourself and pass it into methods directly. Guess in this particular case it will be easier to use a CDbCriteria object to solve the issue.
$dbc = new CDbcriteria();
$dbc->condition = 'vehicle_id = :vehicleId';
$dbc->params = array(':vehicleId'=>$vehicle->id);
$dbc->addNotInCondition(
'plug_id',
array_map(
function($item) {
return $item->type;
},
$vehicleDetails->plug)
);
VehicleDetail::model()->deleteAll($dbc);
That is all you need.

Magento- configurable products options order to match the order they are in the attribute set

I have a magento site I'm building (1.6) my site has a bunch of configurable options with 6 or so attributes set as dropdowns for the customer to pick from. After saving a configurable product the order of the attributes changes. I've been able to find what I think is happening, it is reordering them according to the attribute id not the order I have them set up in the attribute set. I need to find a way to get magento to keep the order of the attributes the same as they are in the attribute set. Any help is greatly appreciated.
Trick is pretty simple.
Just drag'n'drop them in product->edit->associatedProduct tab ;)
The order of attributes from this page is saved to catalog_product_super_attribute table.
I was also looking for the same and finally i found this and it works for me hope it will work for others too.
From Admin Panel > Catalog > Attributes > Manage Attributes select the one like if you want to make it like for the capacity 4GB > 8GB > 16GB and so on then do this small changes.
Select Manage Label / Options > Manage Options (values of your attribute) and if you already created the variables just add the position manually, like:
4GB - 1
8GB - 2
16GB - 3
Save and flush the cache.
That's it, now it should show the attributes as per the position that you assign.
It is an old question but I have found a solution right now having the same problem.
If you are still interesting in changing the order of the configurable attribute you may want to look into this method:
Mage_Catalog_Model_Product_Type_Configurable::getConfigurableAttributes()
getConfigurableAttributes() load the collection of attributes.
The first time the collection is loaded, before saving the configurable, there is no position value, so I think the attribute ID rules on the display order.
If you want to alter this order you can only add a sort for attribute_id after the ->orderByPosition() and revert the order ( this will preserve the position functionality )
For example, here I have added ->setOrder('attribute_id','DESC')
public function getConfigurableAttributes($product = null)
{
Varien_Profiler::start('CONFIGURABLE:'.__METHOD__);
if (!$this->getProduct($product)->hasData($this->_configurableAttributes)) {
$configurableAttributes = $this->getConfigurableAttributeCollection($product)
->orderByPosition()
->setOrder('attribute_id','DESC')
->load();
$this->getProduct($product)->setData($this->_configurableAttributes, $configurableAttributes);
}
Varien_Profiler::stop('CONFIGURABLE:'.__METHOD__);
return $this->getProduct($product)->getData($this->_configurableAttributes);
}
OR
In case you want to modify the order in more radical way, you can also act on this method:
Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config::getAttributesJson()
This is basically calling the getConfigurableAttributes().
To understand if this is the first configurable load, you can check all the attributes in the array $attributes to see if they all have a position ==0 and then proceed with a manual reorder )
Example
I'm omitting all the module creation and the rewrite part.
Here an example modifying getAttributesJson() in order to have the color attribute always on the top.
public function getAttributesJson()
{
$attributes = $this->_getProduct()->getTypeInstance(true)
->getConfigurableAttributesAsArray($this->_getProduct());
if (!$attributes) {
return '[]';
} else {
// == START ==
// checking if I can re-order
if ($this->isNoSavedPosition($attributes)) {
$attributes = $this->attributeReorder($attributes);
}
// == END ==
// Hide price if needed
foreach ($attributes as &$attribute) {
if (isset($attribute['values']) && is_array($attribute['values'])) {
foreach ($attribute['values'] as &$attributeValue) {
if (!$this->getCanReadPrice()) {
$attributeValue['pricing_value'] = '';
$attributeValue['is_percent'] = 0;
}
$attributeValue['can_edit_price'] = $this->getCanEditPrice();
$attributeValue['can_read_price'] = $this->getCanReadPrice();
}
}
}
}
return Mage::helper('core')->jsonEncode($attributes);
}
public function isNoSavedPosition($attributes)
{
foreach ($attributes as $attribute) {
if (isset($attribute['position']) && $attribute['position'] != 0) {
return false;
}
}
// there is no position saved
// - this is the first time the configurable is loaded
// - (the position is saved on second save action)
return true;
}
public function attributeReorder($attributes)
{
// we want the Color attribute to be always on the top
$newAttributesOrderArray = array();
foreach ($attributes as $key => $attribute) {
if (isset($attribute['label']) && $attribute['label'] == 'Color') {
$newAttributesOrderArray[] = $attribute;
unset($attributes[$key]);
}
}
$newAttributesOrderArray = array_merge($newAttributesOrderArray,$attributes);
return $newAttributesOrderArray;
}

Resources