PDO fetchAll() primary key as array group key - php

I want to store the contents of a specific database into an array, grouped by their primary keys. (Instead of the useless way PDO fetchAll() organises them).
My current code:
$DownloadsPDO = $database->dbh->prepare("SELECT * FROM `downloads`");
$DownloadsArray = $DownloadsPDO->execute();
$DownloadsArray = $DownloadsPDO->fetchAll();
Which then outputs:
Array ( [0] => Array ( [id] => 0 [0] => 0 [path] => /xx-xx/testfile.zip [1] => /xx-xx/testfile.zip [name] => Test Script [2] => Test Script [status] => 1 [3] => 1 ) [1] => Array ( [id] => 1 [0] => 1 [path] => /xx-xx/test--file.zip [1] => /xxxx/testfile.zip [name] => New Script-UPDATE [2] => New Script-UPDATE [status] => 1 [3] => 1 ) )
I was considering to use PDO::FETCH_PAIR, however I will be very soon expanding the amount of data I want to be able to use on this script. This works currently, but when I start to expand the amount of downloads and more clients come into play, obviously the way the data is grouped causes an issue.
Is it possible for me to group each array by their primary key (which is id)?

You can just use
$results = array_map('reset', $stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC))
PDO::FETCH_GROUP|PDO::FETCH_ASSOC returns an array of arrays. The first column is used as the key, and then within key is an array of all the results for that key. However, in our scenario each key will only contain 1 row. reset() returns the first element in array, thus eliminating 1 level of nesting.

This should yield what you are looking for :
$results = $pdos->fetchAll(\PDO::FETCH_UNIQUE|\PDO::FETCH_ASSOC);

I decided to just loop through the results with fetch() and enter them into an array as I go along, this is the code I have used and it works just fine:
$DownloadsPDO = $database->dbh->query("SELECT * FROM `downloads`");
$Array = array();
while ($d = $DownloadsPDO->fetch()) {
$Array[$d['id']]["id"] = $d['id'];
$Array[$d['id']]["name"] = $d['name'];
$Array[$d['id']]["path"] = $d['path'];
}
// Outputs
Array ( [1] => Array ( [id] => 1 [name] => Test Script [path] => /xxxx/testfile.zip ) [2] => Array ( [id] => 2 [name] => New Script-UPDATE [path] => /xxxx/testfile.zip ) )
Which uses the primary key (being id) as the name for the array key, and then adds the data into it.
Thought I would add this as the answer as this solved it, thanks to the guys that helped out and I hope this is helpful to anyone else hoping to achieve the same thing.

I'd like to point out the only solution that works for me:
fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_UNIQUE|\PDO::FETCH_ASSOC);
Beware that this will strip the first column from the resultset. So the query must be:
SELECT id_keyname AS arrkey, id_keyname, .... FROM ...

I'm still suggesting you to loop using fetch() method. Otherwise, you can use array_reduce() to iterate over the array. A sample on codepad is here.
The code(in human readable form) will be:
$myFinalArray = array_reduce($myInputArray, function($returnArray, $temp) {
$temp2 = $temp['id'];
unset($temp['id']);
$returnArray[$temp2] = $temp;
return $returnArray;
}
);

So, my question is; is it possible for me to group each array by their
primary key (which is id)
Off course, you have 2 options here: Either to change the query or parse a result-set.
So, I'm sure you don't want to change query itself, so I'd go with parsing result-set.
Note:
You should use prepared SQL statements when they make sense. If you want to bind some parameters then its OKAY. But in this case, you only want get get result-set, so prepare() and fetch() will be kinda overdo.
So, you have:
Array ( [0] => Array ( [id] => 0 [0] => 0 [path] => /xx-xx/testfile.zip [1] => /xx-xx/testfile.zip [name] => Test Script [2] => Test Script [status] => 1 [3] => 1 ) [1] => Array ( [id] => 1 [0] => 1 [path] => /xx-xx/test--file.zip [1] => /xxxx/testfile.zip [name] => New Script-UPDATE [2] => New Script-UPDATE [status] => 1 [3] => 1 ) )
And you want:
Array( [id] => Array('bar' => 'foo') ....)
Well, you can do something like this:
$stmt = $database->dbh->query("SELECT * FROM `downloads`");
$result = array();
foreach($stmt as $array){
$result[$array['id']] = $array;
}
print_r($result); // Outputs: Array(Array('id' => Array(...)))

Related

php push an array into an existing array by it's index

I'm having trouble with putting this question to words so ill just use a simple example, hope the title sortof got my problem across.
I'm creating a blog site where I can create blogposts and people can post comments. This is all saved in JSON except for login details which are saved in MySQL.
Now saving the blogposts go fine but I'm now trying to save comments.
Lets say the blogpost array looks like this:
Array
(
[0] => Array
(
[id] => 0
[title] => first blogpost
[content] => blogpost text
)
[1] => Array
(
[id] => 1
[title] => second blogpost
[content] => blogpost 2 text
)
)
Now someone writes a comment on 'second blogpost', I save it into an array like this(user taken from MySQL):
Array
(
[user] => myusername
[comment] => first post was better!
)
Now I want to merge them like this:
Array
(
[0] => Array
(
[id] => 0
[title] => first blogpost
[content] => blogpost text
)
[1] => Array
(
[id] => 1
[title] => second blogpost
[content] => blogpost 2 text
[comments] => Array
(
[user] => myusername
[comment] => first post was better!
)
)
)
I tried searching for a while and I'd expect this to be somewhere on the site already but I can't find it. I tried a couple variations of array_push and array_merge but it always ended up replacing the relevant blogpost instead of adding onto it.
EDIT: Someone noted the new array can't just float around, I think it's better now.
If you had any related key between posts and comments ( like having post_id in comment array ) that would make more sense to merge/put them.
I assume that's your blogpost
Array
(
[0] => Array
(
[id] => 0
[title] => first blogpost
[content] => blogpost text
)
[1] => Array
(
[id] => 1
[title] => second blogpost
[content] => blogpost 2 text
)
)
And your comments should be like:
Array
(
[user] => myusername
[comment] => first post was better!
[post_id] => 1
)
That way, you would be able to find the matched blogpost.
But, outside of your data structure, here is an example to merge an item into an element of an array of array.
A nested loop example.
foreach($posts as &$post){
foreach($comments as $comment){
if($post['id'] == $comment['post_id']){
$post['comments'][] = $comment;
}
}
}
the key here is sending each reference of the element into loop by &$post and then just manipulate them in loop.
Working with indexed arrays. (Like you already have index names as post_id and a comments index as an empty array)
foreach($comments as $comment){
$posts[$comment['post_id']]['comments'][] = $comment;
}
When the blogpost is updated, I assume you can get the id of that blogpost.
Then you can check if your data structure already has a key "comments". If it does not, add the key and create an array containing the comment and the user as the first array.
If it already exists, add a new array with the user and the comment so that there can be multiple comments for each blogpost.
For example using array_map:
$blogPosts = array_map(function ($blogPost) use ($blogPostId, $comment) {
if ($blogPost["id"] === $blogPostId) {
isset($blogPost["comments"]) ? $blogPost["comments"][] = $comment : $blogPost["comments"] = [$comment];
return $blogPost;
}
return $blogPost;
}, $blogPosts);
Php demo
So I fixed it after a bit of thinking
This is the final structure:
Array
(
[0] => Array
(
[id] => 0
[title] => 1st post
[content] => 1st post works!
[date] => 21-01-2019
[comments] => Array
(
[0] => Array
(
[user] => Me
[comment] => hey 1
[date] => 12:02 21-01-2019
)
[1] => Array
(
[user] => Me
[comment] => hey 2
[date] => 12:03 21-01-2019
)
)
)
)
I added a timestamp because of a suggestion here. It's also a simplified version of what I actually use, I tried adding many more comments and on multiple posts which both work.
This is the code, I should mention the ID is in the URL and it's saved as JSON:
$filename = file.json;
$currentArray = json_decode(file_get_contents($filename), true);
$comment = $_POST['comment'];
$username = $_SESSION['username'];
$date = date("H:i d-m-Y");
$id = $_GET['id'];
Pretty straightforward so far, here is how the array is created:
$currentArray[$id]["comments"][] = array (
'user' => $username,
'comment' => $comment,
'date' => $date
);
[$id] saves it to the correct post, ["comments"] saves it to the comments key(or creates it) and the last [] gives every comment a different index inside the ["comments"].
$newJSON = json_encode($currentArray, JSON_PRETTY_PRINT);
file_put_contents($filename, $newJSON);
And lastly encoding it and saving it to JSON.
Hope this helps someone.

Remove related element from multidimensional array in php

I have an array of image data like this:
[other-image] => Array
(
[img] => Array
(
[0] => 1526973657.jpg
[1] => 1526973661.jpg
[2] => 1526973665.jpg
)
[path] => Array
(
[0] => ../post-upload/1/
[1] => ../post-upload/1/
[2] => ../post-upload/1/
)
[type] => Array
(
[0] => 1
[1] => 1
[2] => 1
)
[thumb] => Array
(
[0] => thumb_1526973661.jpg
[1] => thumb_1526973665.jpg
[2] => thumb_1526973668.jpg
)
)
Now I want to delete an image and it's all related data from sub arrays. (path, type, thumb data)
This is how I tried it in php:
$delkey = '1526973657.jpg';
if(in_array($delkey, $_SESSION['other-image']['img'])){
$imgkey = array_search($delkey, $_SESSION['other-image']['img']);
if($imgkey) unset($_SESSION['other-image']['img'][$imgkey]);
}
But problem is I can't delete related data from other arrays.
Can anybody tell me how to do this?
Thank you.
You should use !==false after array_search() because it may return first index i.e. 0 in some cases, so your condition will not executed. And regarding delete related data from other arrays, you have to unset other data related to that key.
if($imgkey!==false){
unset($_SESSION['other-image']['img'][$imgkey]);
unset($_SESSION['other-image']['path'][$imgkey]);
unset($_SESSION['other-image']['type'][$imgkey]);
unset($_SESSION['other-image']['thumb'][$imgkey]);
}
Is the related data has same key with img?
If they are same, I think you only need to add some codes to delete other data like the way was used to delete img.
if($imgkey) unset($_SESSION['other-image']['path'][$imgkey]);
if($imgkey) unset($_SESSION['other-image']['type'][$imgkey]);
if($imgkey) unset($_SESSION['other-image']['thumb'][$imgkey]);
If the keys in img sub-array are related with the same key(index) in sub-arrays(path, type and thumb, you can also unset those keys. e.g.
$delkey = '1526973657.jpg';
if(in_array($delkey, $_SESSION['other-image']['img'])){
$imgkey = array_search($delkey, $_SESSION['other-image']['img']);
if($imgkey){
unset($_SESSION['other-image']['img'][$imgkey]);
unset($_SESSION['other-image']['path'][$imgkey]);
unset($_SESSION['other-image']['type'][$imgkey]);
unset($_SESSION['other-image']['thumb'][$imgkey]);
}
}

Changing values of an array which consists of multiple objects

I would like to replace a value within the path array and I'm quite stuck for a while. So here is what I got.
My array:
// $myArr
Array
(
[0] => stdClass Object
(
[doc] => stdClass Object
(
[path] => Array
(
[0] => Bob
[1] => pictures
[2] => food
)
)
)
[1] => stdClass Object
(
[doc] => stdClass Object
(
[path] => Array
(
[0] => Alice
[1] => pictures
[2] => vacations
[3] => rome
)
)
)
)
PHP code:
for ($i=0; $i < count($myArr) ; $i++) {
$search = array($old_name); // pictures
$replace = array($new_name); // test
$result = str_replace($search, $replace, $myArr[$i]->doc->path);
}
Result:
It only changes one array and gives me a hint on my str_replace line. Both, $search and $replace are of type array and I know that I need to access elements in an array via array notation -> $item['price'] for example. That is not what is wrong here right?
Notice: Trying to get property of non-object in ...
Array
(
[0] => Bob
[1] => test
[2] => food
)
1) Do you see why he only modifies the last object so to speak?
2) Why is he giving me a Notice whereas I don't violate type conventions in my opinion?
Your code is working fine on my end, however..
I think the problem is in your $result variable. With every iteration, you are overwriting the last written value in the array.
You have to either use that $result variable directly, or replace $result by $myArr[$i]->doc->path. That way you can use the $myArr with the rewritten values.

PHP Find value in object

I have a result of an SQL query that looks like this
Array
(
[0] => stdClass Object
(
[field_number] => 1
[value] => Joe
)
[1] => stdClass Object
(
[field_number] => 2
[value] => Bloggs
)
[2] => stdClass Object
(
[field_number] => 3
[value] => 12566
)
[3] => stdClass Object
(
[field_number] => 4
[value] => 2000-07-24
)
)
It wont always return all the fields as some are not required therefore not saved to the database.
I know that first name is stored with field number 1. How can I look this up in the object.
EG
$first_name = $result => field_number == 1
I know thats not right, but Im sure there must be a simple way to get this info?
Thanks
If the values in the array are not in order (eg array[0] does not always contain field_number 1) then you will need to iterate the array:
foreach($array as $item){
if($item->field_number==1){
$first_name = $item->value;
break;
}
}
However, if this is the result of an SQL query, probably you need to rewrite the query to give you data in a more useable form

PHP why does my function return twice the result of the array with different keys?

I've a problem with one of my function in PHP.
It returns the result two times with different keys…
I want the result only one time without the number keys.
This query and function returns the following array:
<?php
#The query
$typo = GetRowsParams("SELECT * FROM glyphs WHERE g_OK=1");
#The function
function GetRowsParams($requete, $params = array())
{
global $bdd;
$stmt = $bdd->prepare($requete) or die(print_r($req->errorinfo()));;
$stmt->execute($params);
$result = $stmt->fetchAll();
return $result;
}
?>
# The Array
Array (
[0] => Array (
[g_ID] => 1
[0] => 1
[g_name] => zero_Nagar.svg
[1] => zero_Nagar.svg
[g_height] => 1174
[2] => 1174
[g_width] => 352
[3] => 352
[g_tag] => Test
[4] => Test
[g_u_ID] => 2
[5] => 2
[g_path] => 02uploads/Test/zero_Nagar.svg
[6] => 02uploads/Test/zero_Nagar.svg
[g_path_PNG] => 02uploads/Test/zero_Nagar.png
[7] => 02uploads/Test/zero_Nagar.png
[g_OK] => 1
[8] => 1
)
[1] => Array (
[g_ID] => 2
[0] => 2
[g_name] => A
Nagar.svg [1] => A
…
…
Why each row is displayed twice with a different key? Where is my mistake?
Thank you for your help…
it is because by default php returns an array where all data has a textual AND a numeric index.
To keep only the textual index, passe PDO::FETCH_ASSOC in the fechAll function like that :
stmt->fetchAll(PDO::FETCH_ASSOC);
Add the argument PDO::FETCH_ASSOC like so:
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
(You can see the different fetch styles here: http://www.php.net/manual/en/pdostatement.fetch.php)
Read up on the PDOStatement::fetch methods. The first argument is a "fetch style," which defaults to fetching an array that looks like the above. If you just want an array that maps field names to valuse, use:
$result = $bdd.fetchAll(PDO::FETCH_ASSOC);

Categories