I have set an array to a session variable using key-value pairs, but I need to unset that specific session when I click on the delete button.
This is the code that stores the session variables:
$_SESSION['product'][] = array(
'product_id' => $part_id,
'title' => $title,
'price' => $price,
'default_img' => $default_img,
'quantity' => $quantity);
And here's the code that unsets the session:
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
foreach($_SESSION['product'] as $item) {
if ($_GET["partid"] == $item['product_id']) {
unset($_SESSION["product"]);
}
The problem I'm having is that instead of just unsetting one session instance, it unsets the entire session. I've tried unset($_SESSION["product"][$item]);
You tell the code to unset the whole session, so it does.
Include the key in the foreach and unset the specific key that you need to unset.
foreach($_SESSION['product'] as $key => $item) {
if ($_GET["partid"] == $item['product_id']) {
unset($_SESSION["product"][$key]);
}
}
You could also search for the specific value and skip the whole loop thing.
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$key = array_search($_GET["partid"], array_column($_SESSION['product'], 'product_id'));
if($key !== false) unset($_SESSION["product"][$key]);
}
Array_search searches for the GET partid and if it's found it returns the key of where it is, else it returns false.
If you have multiple array items that need to be removed the above array_search method will only remove the first.
You can however loop the array_search to get them all.
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$prodID = array_column($_SESSION['product'], 'product_id'); // creates a flat array that can be searched
while($key = array_search($_GET["partid"], $prodID)){
unset($_SESSION["product"][$key]);
}
}
Here we search to see if there is a matching value, if there is we delete the key, then the while loop searches again.
If a new matching value is forum it's deleted, if not array_search will return false and break the while loop.
A fourth method is to almost keep the code you have as it is, but loop the array by reference with & and unset the item.
foreach($_SESSION['product'] as &$item) { // notice the &
if ($_GET["partid"] == $item['product_id']) {
unset($item); //because we used &, we can now unset $item
}
}
A fifth method is to use array_diff and array_intersect.
This method is the slowest and should not be used on larger arrays, it can be used with very little difference on smaller arrays (less than 50-100 items).
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$_SESSION['product'] = array_intersect_key($_SESSION['product'], array_diff(array_column($_SESSION['product'], 'product_id'), $_GET["partid"]));
}
In order to explain it I need to explain it in "reverse" order from what you read it since it's nested.
I start with created a flat array with array_column.
This array only contains the productid's.
I use array_diff to return only the items that is not matching $_GET["partid"].
What we get is a flat array with only the productid's. That may sound useless, and it is, but the keys is useful.
The keys match what is in the session array.
So if we use array_intersect_key and use $_SESSION['product'] as the main array and the keys from the array_diff then the output is the items in $_SESSION['product'] that does not match $_GET["partid"].
It's complicated in the background but it's a simple on liner.
Related
Ok so I have two arrays, one is an input array full of data like :
$array1 = ["_token" => "62d46d4h6dfh841df8h", "sku62" => "3e", "name62" => "meh", "sku61" => "3e", "name61" => "mah", "sku64" => "3e", "name64" => "moh"]
The other holds simply id's: $array2 = [64, 74, 61]
edit for clarity: $array1 is a snippet of input from a post request i.e. $array1 = $request->all(); The numbers present within the keys of this array are unique Id's appended on form generation to distinguish between rows with multiple form elements.
Each row has an "update" checkbox also with an appended unique id. When ticked this id shows up in the request e.g. update64.
$array2 was populated by doing a foreach through the request, identifying the update string and isolating the id:
foreach ($array1 as $id => $value) {
$idInt = filter_var($id, FILTER_SANITIZE_NUMBER_INT);
$str = preg_replace('/[0-9]+/', '', $id);
if ($str === "update") {
array_push($array2, $idInt);
}
}
I want a solution that returns the elements from $array1 that have the appended ids found in $array2.
My own attempt looks like this:
$relevant_keys = function($key1, $key2) {
return ((preg_replace('/[0-9]+/', '', $key1) === $key2)) ? 1 : -1;
};
$filtered = array_intersect_ukey($array1, array_flip($array2), $relevant_keys);
However $filtered is returning empty and if I dd($key2) within the function it's not even returning an element from $array2, I get something from $array1 instead so this has left me confused.
Would appreciate any help.
Here's the solution to the exact problem you posted:
$filtered = [];
foreach ($array1 as $key => $value)
{
if ( ! preg_match('/(\d+)$/', $key, $matches)) continue;
if ( ! isset($matches[1]) || ! in_array($matches[1], $array2)) continue;
$filtered[$key] = $value;
}
But I'm not sure you're approaching this correctly. That input looks suspicious.
Are you sure there's no better way to format the request?
I have a few important insights to share based on your coding attempt.
array_intersect_ukey() should be the perfect function call for his task, but alas, it is not. I'll tell you why.
array_intersect_ukey() suffers in the same way as array_intersect_uassoc() and array_uintersect_uassoc() because the internal algorithm will stop looking for additional qualifying keys after it encounters its first one. I first came upon this reality here.
Also, the way that you've declared and used the custom function arguments ($key1 and $key2) indicates that you believe $key1 always relates to the first nominated array and $key2 always relates to the second nominated array. This is not true and I have seen many developers with this same false impression. The truth is that under the hood, the two parameters fed into the custom function may come from either array.
For the reasons in #1, I'll recommend that you shift your focus to array_filter(). By establishing a lookup array containing whitelisted keys and filtering on keys, you can swiftly filter your data. Inside the callback, I am using trim() to remove the letters before the id number at the end. This is just one way of isolating the whole number at the end of each key.
Code: (Demo)
$lookup = array_flip($array2);
var_export(
array_filter(
$array1,
fn($key) => isset($lookup[ltrim($key, 'a..z')]),
ARRAY_FILTER_USE_KEY
)
);
Output:
array (
'sku61' => '3e',
'name61' => 'mah',
'sku64' => '3e',
'name64' => 'moh',
)
I have an array that consists of an undetermined number of arrays, recursively (n levels deep). Each array might contain a name key. I want to create a unique list of those values.
Example
Suppose the array is:
$bigArray = array(
'name'=>'one',
'something'=>array(
'name'=>'two',
'subthing'=>array('name'=>'three')
),
'anotherthing'=>array('name'=>'one')
);
The expected result would be:
$uniques = array('one', 'two', 'three') // All the 'name' keys values and without duplicates.
Here's a fiddle of my attempt.
My approach was using array_walk_recursive passing a $uniques array as reference, and allowing the function to update that value:
$uniques = array();
function singleOut($item, $key, &$uniques) {
if ($key == 'name' && !in_array($itm,$uniques,true) )
$uniques[] = $item;
}
array_walk_recursive($bigArray, 'singleOut', $uniques);
However, it's not working for me.
You could use also array_unique on this one too. Example:
$uniques = array();
array_walk_recursive($bigArray, function($val, $key) use (&$uniques){
if($key == 'name') {
$uniques[] = $val;
}
});
$uniques = array_unique($uniques); // unique values
Your fiddle was nearly spot on - the problem was, that the user parameter is given by-reference only within same levels of recursion. You need to use indirection with a reference:
$bigArray = array(
'name'=>'one',
'something'=>array(
'name'=>'two',
'subthing'=>array('name'=>'three')
),
'anotherthing'=>array('name'=>'one')
);
function singleOut($item, $key, $indirect) {
$uniques=&$indirect[0];
if ($key == 'name' && !in_array($item,$uniques,true) ) $uniques[] = $item;
}
$uniques = array();
$indirect = array(&$uniques);
array_walk_recursive($bigArray, 'singleOut', $indirect);
print_r($uniques);
Edit:
Fiddle is here
To avoid doing an in_array() check inside of array_walk_recursive(), you can store name values as keys in the output array. This will effectively eliminate duplicates by overwriting previous identical keys. When array_walk_recursive() is finished, you can use array_keys() to move the data from keys to values.
Code: (Demo)
$bigArray=[
'name'=>'one',
'something'=>[
'name'=>'two',
'subthing'=>['name'=>'three']
],
'anotherthing'=>['name'=>'one']
];
array_walk_recursive($bigArray,function($v,$k)use(&$uniques){
if($k==='name')
$uniques[$v]='';
});
var_export(array_keys($uniques));
Output:
array (
0 => 'one',
1 => 'two',
2 => 'three',
)
Because array_unique() can be slow in some cases, using array_keys() should generally perform faster. That said, if micro-optimization is a concern then you should do benchmark testing using your actual data and your specific environment and select the best method for your project.
As I mentioned in a comment under Ghost's answer, it is a good habit to make === strict comparisons on keys in your multi-dimensional array because if you are looking for a string, but encounter a 0 key, then PHP's type juggling "feature" will provide unexpected results.
Here is a page where I discuss and demonstrate this behavior: Type juggling while making loose comparison yields unwanted result
I have an issue on how can I update my Previous array ?
What currently happening to my code is its just adding new session array instead of updating the declared key here's my code:
foreach ($items_updated as $key => $added)
{
if ($id == $added['item_id'])
{
$newquantity = $added['item_quantity'] - 1;
$update = array(
'item_id' => $items['item_id'],
'item_quantity' => $newquantity,
);
}
}
Session::push('items', $updated);
$items = Session::get('items', []);
foreach ($items as &$item) {
if ($item['item_id'] == $id) {
$item['item_quantity']--;
}
}
Session::set('items', $items);
If you have nested arrays inside your session array. You can use the following way to update the session: $session()->put('user.age',$age);
Example
Supppose you have following array structure inside your session
$user = [
"name" => "Joe",
"age" => 23
]
session()->put('user',$user);
//updating the age in session
session()->put('user.age',49);
if your session array is n-arrays deep then use the dot (.) followed by key names to reach to the nth value or array, like session->put('user.comments.likes',$likes)
I guess this will work for you if you are on laravel 5.0. But also note, that I haven't tested it on laravel 4.x, however, I expect the same result anyway:
//get the array of items (you will want to update) from the session variable
$old_items = \Session::get('items');
//create a new array item with the index or key of the item
//you will want to update, and make the changes you want to
//make on the old item array index.
//In this case I referred to the index or key as quantity to be
//a bit explicit
$new_item[$quantity] = $old_items[$quantity] - 1;
//merge the new array with the old one to make the necessary update
\Session::put('items',array_merge($old_items,$new_item));
You can use Session::forget('key'); to remove the previous array in session.
And use Session::push to add new items to Session.
Storing an array submitted from forms stores elements with null values. Is there a way to store only non null fields into the php array?
$_SESSION['items'] = $_POST['items'];
is my current code.
You should take a look at array_filter(). I think it is exactly what you are looking for.
$_SESSION['items'] = array_filter($_POST['items']);
# Cycle through each item in our array
foreach ($_POST['items'] as $key => $value) {
# If the item is NOT empty
if (!empty($value))
# Add our item into our SESSION array
$_SESSION['items'][$key] = $value;
}
Like #Till Theis says, array_filter is definitely the way to go. You can either use it directly, like so:
$_SESSION['items'] = array_filter($_POST['items']);
Which will give you all elements of the array which does not evaluate to false. I.E. you'll filter out both NULL, 0, false etc.
You can also pass a callback function to create custom filtering, like so:
abstract class Util {
public static function filterNull ($value) {
return isset($value);
}
}
$_SESSION['items'] = array_filter($_POST['items'], array('Util', 'filterNull'));
This will call the filterNull-method of the Util class for each element in the items-array, and if they are set (see language construct isset()), then they are kept in the resulting array.
I'm trying to create an array to display the last 5 products a customer has viewed.
The array is a 2 dimensional array like below...
$RView= array(
array( ID => "1001", RefCode => "Ref_01", Name => "Name_01" ),
...
array( ID => "1005", RefCode => "Ref_05", Name => "Name_05" )
);
The array values are retrieved from the products recordset and is designed to function as follows when a customer visits a product page.
Page will check if a Session Array exists
If yes, an array variable is created from existing Session
If no, a new array is created.
Array will add the new product details.
Array will count if there are more than 5 existing products in the array.
If yes, it will remove the oldest.
If no, moves to next step.
A Session is created/updated from the revised Array.
My current effort is attached below...
Many thanks for any help.
<?php
session_start()
// Get or Create Array
IF (isset($_SESSION['sessRView'])) {
$RView = ($_SESSION['sessRView']); }
ELSE {
$RView = array(array());
}
// Append currently viewed Product to Array
array(array_unshift($RView, $row_rsPrd['PrdID'], $row_rsPrd['RefCode'], $row_rsPrd['Name']));
// Check if more than 5 products exist in Array, if so delete.
IF (sizeof($RView) > 5) {
array(array_pop($RView)); }
// Update Session for next page
$_SESSION['sessRView'] = $RView;
// Display Array
for ($row = 0; $row < 5; $row++)
{
echo "<ul>";
echo "<li><a href='?PrdID=".$RView[$row]["PrdID"]."'>".$RView[$row]["RefCode"]."</a> : ".$RView[$row]["Name"]."</li>";
echo "</ul>";
}
?>
It's more or less right - just 2 lines need to be changed.
There's no need for the extra array() around array_unshift and array_pop.
When you use array_unshift you're pushing an array of items (not the id/codes individually) - I think you mean array_unshift($RView, array($prodid,$name,...))
What if $RView doesn't have 5 elements? In that case you're accessing undefined array indices (which may or may not show an error). Change it to a foreach loop: e.g.
foreach ($Rview as $prod) echo $prod['Name']...
It should work after you make these changes. You might want to clean up the coding style a bit, though :)
EDIT: Oh, I see, when you're referencing the array in the for loop it doesn't know that the array has "ProdID" and "Name" indices. When you make an array you have to define the indexes using the => operator.
Add indexes to the array when you array_unshift:
array_unshift($RView, array("ProdID" => $row_rsProd["ProdID"], "Name"...))
If row_rsProd isn't too big, you can just tack the entire row_rsprod onto $RView.
so change array_unshift(...) to just $RView[] = $row_rsProd
This way the indexes are preserved.
Alternatively you can change the indicies in the for loop to match. Right now the array you unshift onto $RView is 0-based - $RView[0][0] is the product ID for the first product, etc.
So you can change the stuff in the foreach loop to
echo "<li>..." $prod[0] $prod[1] $prod[2]
Hope that helps!