PDO fetch obj with defined objectname - php

Similar too:
PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE
I want to do the same with:
PDO::FETCH_OBJ
Means I want to pick each row as an object named by the first value.
Example:
id name url
1 Test www.test.de
2 Test2 www.test2.de
Select name, id, url FROM whatever;
$processes = $result->fetchAll(PDO::FETCH_OBJ);
returns the objects idexed from 0 - x
fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP)
Returns it nearly like I want just 2 downsides:
test {
0: [
'id': 1,
'src': 'www.test.de'
]
}
First is I want to keep name in the object (could douple select (select name, name ...) and I have the unecessary array inside.
So any idea how I get it to this:
test [
'name': 'test',
'id': 1,
'src': 'www.test.de'
]
test2 [
'name': 'test2',
'id': 2,
'src': 'www.test2.de'
]

You can use this:
$dbh = new PDO('mysql:dbname=my;host=localhost', 'root', '');
$sth = $dbh->prepare("SELECT name, id, name, url FROM data");
$sth->execute();
var_dump($sth->fetchAll(PDO::FETCH_OBJ | PDO::FETCH_GROUP | PDO::FETCH_UNIQUE));
The output will be like this:
array(3) {
'test 1' =>
class stdClass#6 (3) {
public $id =>
string(1) "4"
public $name =>
string(6) "test 1"
public $url =>
string(13) "www.gmail.com"
}
'test 2' =>
class stdClass#4 (3) {
public $id =>
string(1) "2"
public $name =>
string(6) "test 2"
public $url =>
string(14) "www.google.com"
}
'test 3' =>
class stdClass#5 (3) {
public $id =>
string(1) "3"
public $name =>
string(6) "test 3"
public $url =>
string(21) "www.stackoverflow.com"
}
}
But be noticed: if you add duplicate values into the name column, you will get values of last record with the same name. In my example above I have table with this dataset:
select * from data;
+----+--------+-----------------------+
| id | name | url |
+----+--------+-----------------------+
| 1 | test 1 | www.ya.ru |
| 2 | test 2 | www.google.com |
| 3 | test 3 | www.stackoverflow.com |
| 4 | test 1 | www.gmail.com |
+----+--------+-----------------------+
4 rows in set (0,00 sec)
So you have data from record with ID = 4 in object named "test 1".

Related

create array using two foreach

I hope you guys can help me here, because I guess my code is not made correctly.
I have 2 mysql tables:
table: checks
+-----------+-------------+------------+
| id | name | host |
+-----------+-------------+------------+
| 1 | demo 1 | 1.1.1.1 |
+-----------+-------------+------------+
| 2 | demo 2 | 1.1.1.2 |
+-----------+-------------+------------+
| 3 | demo 3 | 1.1.1.3 |
+-----------+-------------+------------+
table: checks_history
+-----------+-------------+------------+------------+
| id | check_id | status | timestamp |
+-----------+-------------+------------+------------+
| 1 | 1 | 0 | 3451245 |
+-----------+-------------+------------+------------+
| 2 | 1 | 0 | 3451245 |
+-----------+-------------+------------+------------+
| 3 | 2 | 0 | 3451245 |
+-----------+-------------+------------+------------+
| 4 | 1 | 1 | 3451245 |
+-----------+-------------+------------+------------+
| 5 | 2 | 0 | 3451245 |
+-----------+-------------+------------+------------+
I want create a json file per id (table: checks) with this structure:
{
"info": { // Associated to table "checks"
"id": "1",
"name": "Demo 1",
"host": "1.1.1.1"
},
"data": { // associated to table check_history according with the id on table check
"1": { // associated to Column "id" on table checks_history
"status": "0",
"timestamp": "3451245"
},
"2": {
"status": "0",
"timestamp": "3451245"
},
"4": {
"status": "1",
"timestamp": "3451245"
}
}
}
There is my code PHP:
$info = array();
$history = array();
$incidents = $database->select("app_checks","*", false);
foreach ($incidents as $key => $value) {
$id = $value['id'];
$name = $value['name'];
$host = $value['host'];
$check_history = $database->select("app_checks_history", "*", [ "checkid" => $id, "ORDER" => ['id' => 'DESC'], "LIMIT" => 30 ]);
foreach ($check_history as $k => $v) {
$history = array(
$v['id'] => array(
'timestamp' => $v['timestamp'],
'status' => $v['status']
)
);
}
$info = array(
'info'=> array(
'id'=> $id,
'name'=> $name,
'host'=> $host
),
'data' => $history
);
$json_data = json_encode($info, JSON_PRETTY_PRINT);
$fileName = 'json/server_'.$id.'.json';
file_put_contents($fileName, $json_data);
}
When I try run the code, im getting the first value on "data" instead all loop:
{
"info": {
"id": "1",
"name": "Demo 1",
"host": "1.1.1.1"
},
"data": {
"1": {
"status": "0",
"timestamp": "3451245"
}
}
}
I searched in the forum and I did not found any similar issue related to my code.
I appreciate any help here.
Thanks in advance.
br
Well, I don't know PHP; however, I believe if you get your data model right, it should get you there. I would have my data model something like below in C#, an instance of Check class represent a check as per your table, serialize and save each instance in its own JSON file.
namespace Stackoverflow
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Check
{
[JsonProperty("info")]
public Info Info { get; set; }
[JsonProperty("data")]
public Dictionary<string, History> Data { get; set; }
}
public partial class History
{
[JsonProperty("status")]
[JsonConverter(typeof(ParseStringConverter))]
public long Status { get; set; }
[JsonProperty("timestamp")]
[JsonConverter(typeof(ParseStringConverter))]
public long Timestamp { get; set; }
}
public partial class Info
{
[JsonProperty("id")]
[JsonConverter(typeof(ParseStringConverter))]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("host")]
public string Host { get; set; }
}
}

How to join two MySQL tables for wp_rest_api

In my WordPress database I have three tables wp_companies which stores some company info and wp_product_types which stores a bunch of product types that a company can assign them selves then I have wp_company_products which is used to assign product types to a company using ids.
Heres an example of how the database looks:
wp_companies
id | company_name | member_type | logo
-----------------------------------------------------------------
1 | Google | full | https://via.placeholder.com/150
-----------------------------------------------------------------
2 | Crunchyroll | full | https://via.placeholder.com/150
wp_products
id | product_name |
----------------------
1 | Car Insurance |
----------------------
2 | House Insurance |
----------------------
3 | Life Insurance |
wp_company_products
id | company_id | product_id
----------------------------
1 | 1 | 2
----------------------------
2 | 2 | 1
----------------------------
3 | 1 | 3
Here's my current MySQL query that simply shows the data in wp_companies
add_action('rest_api_init', function() {
register_rest_route('custom-routes/v1', 'members', array(
'methods' => 'GET',
'callback' => 'get_members'
) );
});
function get_members($data) {
global $wpdb;
$query = $wpdb->get_results( "SELECT company_name, member_type, logo, site_url FROM {$wpdb->prefix}companies ORDER BY RAND()" );
foreach ( $query as $member ) {
$member_data[] = array(
"company_name" => $member->company_name,
"member_type" => $member->member_type,
"logo" => $member->logo,
);
}
return $member_data;
}
This displays my data like so on my api end point:
[
{
"company_name":"Google",
"member_type":"full",
"logo":"https://via.placeholder.com/150",
},
{
"company_name":"Crunchyroll",
"member_type":"full",
"logo":"https://via.placeholder.com/150",
}
]
But what I want is to combine the wp_companies and wp_company_products tables so that my data is displayed something like this on the api end point:
[
{
"company_name":"Google",
"member_type":"full",
"logo":"https://via.placeholder.com/150",
"products": [
"House Insurance",
"Life Insurance"
]
},
{
"company_name":"Crunchyroll",
"member_type":"full",
"logo":"https://via.placeholder.com/150",
"products": [
"Car Insurance",
]
}
]
How can I structure my MySQL query to be able to achieve this?
Please try this
function get_members($data) {
global $wpdb;
$query = $wpdb->get_results( "SELECT company_name, member_type, logo, site_url FROM {$wpdb->prefix}companies ORDER BY RAND()" );
foreach ( $query as $member ) {
$productQuery = $wpdb->get_results( "SELECT product_name FROM wp_products WHERE id IN (SELECT product_id from wp_company_products WHERE compony_id = '{$member->id}') " );
$products = array();
foreach ( $productQuery as $prduct ) {
array_push($products ,$prduct->product_name);
}
$member_data[] = array(
"company_name" => $member->company_name,
"member_type" => $member->member_type,
"logo" => $member->logo,
"products" => $products
);
}
return $member_data;
}

PHP processing data and create array

I have a mysql query with result like this:
ID | index | Mapping index | Date
1 | 27 | value27 | 2019-04
2 | 28 | value28 | 2019-05
3 | 28 | value28 | 2019-05
4 | 32 | value32 | 2019-07
5 | 32 | value32 | 2019-05
The results should be prepared to display stacked charts. As result i need in php:
// array to display google chart
['2019-04', 1, 0, 0,],
['2019-05', 0, 2, 1,],
['2019-07', 0, 0, 1,],
// explanation
ID | value27 | value28 | value 32 | Date
1 | 1 | 0 | 0 | 2019-04
2 | 0 | 2 | 1 | 2019-05
2 | 0 | 0 | 1 | 2019-07
This is my php script:
$preparevar = array();
foreach($data["timechart"] as $date){
array_push($preparevar,[$date->date, $date->count , '\''.$date->repcontent.'\'' ]);
}
$googleChartArray = array(); //Use this array to group the results using date.
foreach( $preparevar as $d ) {
$date = $d[0];
$value = $d[1];
if( !isset( $googleChartArray[$date] ) ) {
$googleChartArray[$date] = array( "'". $date. "'" ); //Date needs to be enclosed in quote.
}
$googleChartArray[$date][] = $value;
}
$f = array(); //Format the above array to split value in a comma separated format.
foreach( $googleChartArray as $g ) {
$f[] = implode( ',' , $g );
}
$json_out = json_encode(array_values($googleChartArray));
The problem with this format is, that the zero values will be ignored:
[
['2019-04',1],
['2019-05',2,1],
['2019-07',1]
]
should be:
[
['2019-04',1,0,0],
['2019-05',0,2,1],
['2019-07',0,0,1]
]
Here an example of $data["timechart"]:
array(11) {
[0]=>
object(stdClass)#43 (14) {
["id"]=>
string(2) "46"
["index"]=>
string(2) "31"
["index2"]=>
string(1) "0"
["keynr"]=>
string(2) "31"
["repcontent"]=>
string(41) "Value31"
["count"]=>
string(1) "1"
["date"]=>
string(7) "2007-06"
}
And here an example of my query. I canĀ“t use SUM(CASE) for example beacause index are variable.
SELECT
orders.id,
positions_list.index,
RepK.keynr,
RepK.content AS repcontent,
RepK.p_company,
COUNT(positions_list.index) AS count,
DATE_FORMAT(orders.date_placement, '%Y-%m') AS date
from orders
JOIN tools
ON tools.id=orders.tool_id
JOIN positions_list ON positions_list.order_id = orders.id
LEFT JOIN repkey as RepK
ON RepK.keynr=positions_list.index
AND RepK.p_company=orders.comp_id
WHERE
tools.id =:id
AND RepK.keynr IS NOT NULL
group by DATE_FORMAT(orders.date_placement, '%Y-%m'),positions_list.index
MySQL doesn't currently offer variable width pivots, so you can either:
make two queries, the first to collect the unique repcontent columns, then build a second query to implement a pivot technique by writing a SELECT clause with dynamic CASE WHEN statements for each column or
make one query, and let php prepare the results (this can be scripted up in a few different ways, but I'll recommend this one)
Code: (Demo)
$resultSet = [
['repcontent' => 'Value 27', 'date' => '2019-04'],
['repcontent' => 'Value 28', 'date' => '2019-05'],
['repcontent' => 'Value 28', 'date' => '2019-05'],
['repcontent' => 'Value 32', 'date' => '2019-07'],
['repcontent' => 'Value 32', 'date' => '2019-05'],
];
$columns = array_unique(array_column($resultSet, 'repcontent'));
$lookupKeys = range(1, count($columns));
$lookup = array_combine($columns, $lookupKeys);
$defaults = array_fill_keys($lookupKeys, 0);
foreach ($resultSet as $row) {
if (!isset($result[$row['date']])) {
$result[$row['date']] = array_merge([$row['date']], $defaults);
}
++$result[$row['date']][$lookup[$row['repcontent']]];
}
echo json_encode(array_values($result));
Output:
[["2019-04",1,0,0],["2019-05",0,2,1],["2019-07",0,0,1]]
For simplicity, generate a result set as an array of arrays.
Extract the unique repcontent values
Generate an array with values ranging from 1 to the unique repcontent count
Forge a lookup array consisting of #1 as keys and #2 as values -- this will determine where each "count" will stored when looping later
Create a default array consisting of #2 as keys and zeros as values
Now, loop through the result set and if a given row has a repcontent value which is encountered for the first time, create a new row in the output array using the date as the first element and the elements from #4 to follow.
Unconditionally, add 1 to the row's column that corresponds with with the repcontent value
If you don't quite understand why any of the variables ($columns, $lookupKeys, $lookup, $defaults) are generated or what they contain, call var_export() on my variables before entering the loop -- that should clear up any confusion.
I have a feeling that I could refine your query, but I won't venture a guess without having some realistic sample data to play with.
I don't see why you would need to add additional quotes to your json for the Google chart to work. If the chart doesn't render without the additional quotes, this is probably a symptom that you are passing the php variable to javascript in an improper fashion.
p.s. I see that you some development with Joomla, if this is a Joomla script and you are not able to craft your query with Joomla's query building methods, please post your best effort on Joomla Stack Exchange and I'll see if I can help.

MySQL query on table structure to make JSON friendly format

I want to have a result like this, to expand all nodes and make a defined treeview.
var defaultData = [
{
text: 'Parent 1',
href: '#parent1',
tags: ['4'],
nodes: [
{
text: 'Child 1',
href: '#child1',
tags: ['2'],
nodes: [
{
text: 'Grandchild 1',
href: '#grandchild1',
tags: ['0']
},
{
text: 'Grandchild 2',
href: '#grandchild2',
tags: ['0']
}
]
},
{
text: 'Child 2',
href: '#child2',
tags: ['0']
}
]
},
{
text: 'Parent 2',
href: '#parent2',
tags: ['0']
},
{
text: 'Parent 3',
href: '#parent3',
tags: ['0']
},
{
text: 'Parent 4',
href: '#parent4',
tags: ['0']
},
{
text: 'Parent 5',
href: '#parent5' ,
tags: ['0']
}
];
I've create a table like this, is it correct?
and how to query them in order to have result as above by json_encode the result?
First of all, you need to fix your table. It is highly irregular and text values will not work well with matching in any language. Try a table like this:
------------------------------
| id | parent | desc |
------------------------------
| 1 | 0 | parent 1 |
------------------------------
| 2 | 0 | parent 2 |
------------------------------
| 3 | 0 | parent 1 |
------------------------------
| 4 | 0 | parent 2 |
------------------------------
| 5 | 0 | parent 1 |
------------------------------
| 6 | 1 | child 1 |
------------------------------
| 7 | 1 | child 2 |
------------------------------
| 8 | 6 | Grandchild 1 |
------------------------------
| 9 | 6 | Grandchild 2 |
------------------------------
id and parent should be integer fields and desc can be text/varchar. Root or top level items should have a parent value of zero (0).
Then you can use a script similar to:
$db = new mysqli('127.0.0.1', 'your_db_user', 'your_secure_password', 'your_db_schema');
if( $mysqli->connect_error ) {
echo 'Something went wrong: ' . $mysqli->connect_error;
}
$json = [];
function sanitize_id($id) {
return preg_replace( '/[^a-z0-9]/', '', strtolower($id) );
}
function recursive( $parentId, &$json ) {
global $mysqli;
if ($stmt = $mysqli->prepare("SELECT * FROM your-table WHERE parent = ?")) {
// Bind parent id to query
$stmt->bind_param('i', $parentId);
$results = $stmt->execute();
// Loop over results
while ( $result = $results->fetch_assoc() ) {
// Add result to JSON structure at referenced location
$json[] = [
'text' => $result['desc'],
'href' => '#' . sanitize_id($result['desc']),
'tags' => ['0'], // Are the tags another field?
'nodes' => []
];
// Rerun recusive function to check for and add any children
recursive( $result['id'], $json['nodes'] );
}
$stmt->close();
}
};
recursive(0, $json);
echo json_encode( $json );
$db->close();

Complicated nested array issue

I want to query data from a database into a json array that ultimalty produces a force directed graph in javascript. Here is what the Json array should be like. However nodes can have mulitiple adjacencies or none, how can I query a json array where the adjacencies section varies from node to node and is able to adjust according to the number of adjacencies a node has?
Var JSON =[
{
"adjacencies": [
{
"nodeTo": "graphnode9",
"nodeFrom": "graphnode5",
"data": {}
}
],
"data": {
"$color": "#416D9C",
"$type": "star"
},
"id": "graphnode5",
"name": "graphnode5"
},
];
or they can have
Var JSON =[
{
"adjacencies": [
{
"nodeTo": "graphnode9",
"nodeFrom": "graphnode5",
"data": {}
},
{
"nodeTo": "graphnode9",
"nodeFrom": "graphnode5",
"data": {}
},
{
"nodeTo": "graphnode9",
"nodeFrom": "graphnode5",
"data": {}
}
],
"data": {
"$color": "#416D9C",
"$type": "star"
},
"id": "graphnode5",
"name": "graphnode5"
},
];
or they can not have any
Var JSON =[
{
"adjacencies": [],
"data": {
"$color": "#416D9C",
"$type": "star"
},
"id": "graphnode5",
"name": "graphnode5"
},
];
Here is my attempt so far, however this only produces a json that only allows one adjacencies, How can I setup a Json query that will adjust the the number of adjacencies a node have? while just loading the data and id section once but allowing the adjacenies to be varied?
Here is my Database structure
nodes Relationships
----- -------------
id int(11), id int(11),
name varchar(35), goingto int(11), //this is the destination node from the id relation
color varchar(7), data varchar(0) null
type varchar (12), Foreign key (id) references nodes(id)
Primary key (id)
engine = innodb
And here is my attempt that
function getjson(){
$db = adodbConnect();
$query = "SELECT nodes.*, relationships.* FROM nodes inner JOIN relationships ON nodes.id = relationships.id";
$result = $db -> Execute($query);
while($row=$result->FetchRow())
{
$id= (float)$row['id'];
$name = $row['name'];
$color1 = $row['color'];
$type1 = $row['type'];
$to= (float)$row['goingto'];
$thumb =$row['thumb']; //image path
$array[] = array(
"adjacencies" => array( array(
"nodeTo" => "$to",
"nodeFrom" => "$id",
"data" => array() )),
"data" => array(
"$"."color" => $color1,
"$"."type" => $type1 ),
"id" => $id,
"name" => "<img src='".$thumb."' height='25' width='25' alt='root'/><label>".$name."</label>");
}
$json = json_encode($array);
print "$json";
//return $json;
}
If you want to return the result in a single query, then you will end up with duplicated data for the node, in each separate row where there's a distinct adjacency from that node... Which is fine, that's how it works.
But as it sits, you won't get nodes returned if there's no adjacency on that node (because you're using an INNER join. You should use a LEFT join to include nodes that have no results from the related adjacency table).
By sorting by node id, we explicitly ensure that all nodes and their adjacencies appear grouped together. This is probably happening already because id is your pk and hence the sort is happening this way "automatically". But an ORDER BY nodes.id ensures this happens, and makes your intention clear to anyone looking at the code.
Also, because you're returning everything * from both tables, you're going to have column name conflicts, on node.id and relationship.id. Ideally you'd explicitly name your columns to avoid this so that you have predictable results back in PHP.
So your SQL could look more like:
SELECT
n.id as n_id,
n.name,
n.color,
n.type,
r.id as r_id,
r.goingto,
r.data
FROM
nodes n
LEFT JOIN relationships r
ON n.id = r.id
ORDER BY
n.id
This returns a result set that looks something like:
n_id | name | color | type | r_id | goingto | data
------+-------+--------+-------+------+---------+-----------
1 | node1 | red | type1 | 1 | 5 | stuff
1 | node1 | red | type1 | 2 | 6 | morestuff
2 | node2 | blue | type2 | 3 | 10 | whatever
3 | node3 | green | type3 | null | null | null
4 | node4 | orange | type4 | 4 | 20 | xxx1
4 | node4 | orange | type4 | 5 | 21 | xxx2
4 | node4 | orange | type4 | 6 | 22 | xxx3
etc...
(ie this assumes node 1 has two relationships, node 2 has 1 relationship, node 3 has no relationships, and node 4 has 3).
And then, your code that builds the array just needs to iterate the results, building a new node only when the current record's node is not the same as the previous one (ie we're relying on the ORDER BY node.id to "gather" all the info for a particular node, sequentially).
This code hasn't been tested, but I think the intent is clear, you should be able to bend this as required - but it basically just implements the above.
Replace your while loop with all of this.
$previd = -1;
while($row=$result->FetchRow())
{
$id= (float)$row['n_id']; // <--- note change from 'id' to 'n_id'
$name = $row['name'];
$color1 = $row['color'];
$type1 = $row['type'];
$to= (float)$row['goingto'];
$thumb =$row['thumb']; //image path
// Is this row the start of a new node?
if ($previd != $id) {
// Yes, new node. Record our new node id, for future new node checks.
$previd = $id;
// Store the previous node we've already built, now that it's complete (but only if there was a previous node!)
if ($previd != -1) {
$array.push($node);
}
// Start our new node off, ready to accept adjacencies
$node = array(
"adjacencies" => array(),
"data" => array(
"$"."color" => $color1,
"$"."type" => $type1
),
"id" => $id,
"name" => "<img src='".$thumb."' height='25' width='25' alt='root'/><label>".$name."</label>");
}
// Any adjacency for this node, on this row?
if ($to != null) { // <-- Not sure about this line!
// Yes there is, so create the new adjacency record and add it to the current node's adjacency array.
$node["adjacencies"].push(
array(
"nodeTo" => "$to",
"nodeFrom" => "$id",
"data" => array()
)
);
}
}
I'm not sure how "no adjacency" will be represented in $to - ie if this will be "null" or what. I'll leave that to you to test, but suffice to say you'll need to reflect this in the line if ($to != null) { // <-- Not sure about this line!

Categories