unexpected behavior of object pushed in an array - php

I've made a script which creates an object in a foreach loop, the object gets filled with information and then goes in a nested foreach loop adding even more information.
The script is to make an overview of information, posts by user + some other information
$data = array();
foreach ($users as $user)
{
$row = new stdClass();
$row->user = $user;
$row->name = fullname($user);
$posts = getPosts($user);
foreach ($posts as $post)
{
$row->title = $post->title;
$row->datetime = $post->date;
$row->views = getViews($post->id);
$data[] = $row;
}
}
When the script is done all "rows" in $data are the same per user, all showing the last added row for that user.
When I check the row before putting it in the array, it's the information I expect, it seems the object is still actively used although I've put it in an array.
Should I close the object before putting it in an array or something else?
Thanks in advance!
=EDIT=
$data[] = $row; is in the right spot because I want the output to be like this:
Emma | 'My first post!' | 22-10-2014 | 8
Emma | 'posting again!' | 23-10-2014 | 24
Emma | 'Back from ...' | 02-01-2014 | 69
Rick | 'youknowit' | 10-10-2013 | 45
Freud | 'Yo momma' | 01-01-1970 | 123
Frued | 'fruitsalad' | 02-02-2010 | 3

[Update] Your code makes a lot more sense with the new information added to the question :) And the solution gets far more easy : Simply clone $row in each $post-loop .
foreach ($users as $user)
{
$row = new stdClass();
$row->user = $user;
$row->name = fullname($user);
$posts = getPosts($user);
foreach ($posts as $post)
{
$item = clone $row; //<-- clone $row, $data will end up as you desire
$item->title = $post->title;
$item->datetime = $post->date;
$item->views = getViews($post->id);
$data[] = $item;
}
}

Related

change json key name dynamic

i have generated a json according to my sql query out put here is my json output, i have listed few of my json code
"42":"",
"field_id_25":"",
"43":null,
"field_ft_25":null,
"44":"",
"field_id_26":"",
"45":null,
"field_ft_26":null,
"46":"",
"field_id_27":"",
"47":null,
"field_ft_27":null,
i have to change json key field_ft_$$ according to my database table values..
|---------------------|------------------|
| field id | field name |
|---------------------|------------------|
| field_id_27 | meta_description |
|---------------------|------------------|
ive coded in php then after i dont know how to finish..
<?php
$con=mysqli_connect("localhost","root","","penn");
if (!$con) {
echo "Failed";
}
// Retrive Data From WebLog Title
$sql="SELECT * FROM `exp_weblog_titles` LEFT JOIN `exp_weblog_data` ON `exp_weblog_data`.`entry_id` = `exp_weblog_titles`.`entry_id` WHERE exp_weblog_titles.weblog_id='13' LIMIT 2 ";
$query=mysqli_query($con,$sql);
while ($row=mysqli_fetch_array($query))
{
$data[] = $row;
}
// Convert The Weblog title data to json
$json_string = json_encode($data, JSON_PRETTY_PRINT);
echo $json_string;
// Retrive web_log_field_List as a array from database
$sql1="SELECT field_id,field_name FROM exp_weblog_fields";
$query1=mysqli_query($con,$sql1);
while ($row1=mysqli_fetch_array($query1)) {
$web_log_field[$row1['field_id']] = $row1['field_name'];
}
// echo $web_log_field[21];
?>
example - i need to change "field_ft_27":null to "meta_description": null and others according to my database values
Use a regular expression to extract the appropriate parts of field_ft_XX and get the corresponding field_id_XX element of $web_log_field. Then you can delete the old key and add the replacement key.
foreach ($data as &$row) {
foreach ($row as $key => $value) {
if (preg_match('/^field_ft_(\d+)$/', $key)) {
$idkey = "field_id_$key[1]";
if (isset($web_log_field[$idkey])) {
$row[$web_log_field[$idkey]] = $value;
unset($row[$key]);
}
}
}
}

Format JSON with PHP

I need some helping formatting my JSON correctly. Create parent objects for each of the activities and then add children to them. With the example data below it would be one parent activity for 'Test' with two children and another parent for 'Test2' with three children. I've linked in two jsonblobs with the format i'm getting and the format I need. Any help would be appreciated.
+---------------+-------+--------------+------------+------------+--------+
| ACTIVITY_NAME | GROUP | START_DATE | END_DATE | COMPLETED | TOTAL |
+---------------+-------+--------------+------------+------------+--------+
| Test | 1 | 04/30/2015 | 05/01/2015| 10 | 15 |
| Test | 2 | 04/30/2015 | 05/01/2015| 20 | 25 |
| Test2 | 1 | 05/2/2015 | 05/03/2015| 30 | 35 |
| Test2 | 2 | 05/2/2015 | 05/03/2015| 40 | 45 |
| Test2 | 3 | 05/2/2015 | 05/03/2015| 50 | 55 |
+---------------+-------+--------------+------------+------------+--------+
PHP:
<?php
include("connect.php");
if( $conn === false ) {
echo "Could not connect.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Set up and execute the query. */
$sql = "<query>";
$stmt = sqlsrv_query( $conn, $sql);
do {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$json[] = $row;
}
} while ( sqlsrv_next_result($stmt) );
foreach ($json as $result) {
$data[data][][$result['ACTIVITY_NAME']]['children'] = $result;
}
echo json_encode($data);
?>
This is what i'm getting: https://jsonblob.com/5550c921e4b002ae4e370469
This is what I need: https://jsonblob.com/5550c942e4b002ae4e370471
Edit -
Here is what my working script ended up looking like:
<?php
include("connect.php");
if( $conn === false ) {
echo "Could not connect.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Set up and execute the query. */
$sql = "<query> ";
$stmt = sqlsrv_query($conn, $sql);
// This is where the data will be organized.
// It's better to always initialize the array variables before putting data in them
$data = array();
// Get the rows one by one
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Extract the activity name; we want to group the rows by it
$name = $row['ACTIVITY_NAME'];
$group = '';
$sdate = '';
$edate = '';
$completed = '';
$total = '';
$perc = '';
// Check if this activity was encountered before
if (! isset($data[$name])) {
// No, this is the first time; we will make room for it, first
$data[$name] = array(
// Remember the name
'ACTIVITY_NAME' => $name,
'MAINTENANCE_GROUP' => $group,
'START_DATE' => $sdate,
'END_DATE' => $edate,
'COMPLETED' => $completed,
'TOTAL_CLUSTERS' => $total,
'COMPLETE_PERC' => $perc,
// No children yet
'children' => array(),
);
}
// Put the row into the list of children for this activity
$data[$name]['children'][] = $row;
}
// Here, the entries in $data are indexed by the values they also have in 'ACTIVITY_NAME'
// If you want them numerically indexed, all you have to do is:
$data = array_values($data);
echo json_encode(array('data' => $data));
//echo json_encode($data);
?>
You didn't show the query/queries you run but for such a simple task I think a single query is enough. The outer do/while loop on sqlsrv_next_result() is not needed. You have to use it when you send more than one query (separated by semicolons) in a single call to sqlsrv_query().
You do not need to run two times through the result set. You can organize your data as soon as you get it from the database.
All you need is to check the values you get from the database and create the data structure as you need:
// ...
$stmt = sqlsrv_query($conn, $sql);
// This is where the data will be organized.
// It's better to always initialize the array variables before putting data in them
$data = array();
// Get the rows one by one
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Extract the activity name; we want to group the rows by it
$name = $row['ACTIVITY_NAME'];
// Check if this activity was encountered before
if (! isset($data[$name])) {
// No, this is the first time; we will make room for it, first
$data[$name] = array(
// Remember the name
'ACTIVITY_NAME' => $name,
// No children yet
'children' => array(),
);
}
// Put the row into the list of children for this activity
$data[$name]['children'][] = $row;
}
// Here, the entries in $data are indexed by the values they also have in 'ACTIVITY_NAME'
// If you want them numerically indexed, all you have to do is:
$data = array_values($data);
// That's all
Change these 3 lines:
foreach ($json as $result) {
$data[data][][$result['ACTIVITY_NAME']]['children'] = $result;
}
To this:
foreach ($json as $result) {
$data['data'][] = array('ACTIVITY_NAME' => $result['ACTIVITY_NAME'], 'children' => $result);
}
You can save the children fields in an array
do {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$children = array("MAINTENANCE_GROUP" => $row["MAINTENANCE_GROUP"], "START_DATE" => $row["START_DATE"],
"END_DATE" => $row["END_DATE"], "COMPLETED" => $row["COMPLETED"], "TOTAL" => $row["TOTAL"] );
$json[] = array("MAINTENANCE_GROUP" => $row["MAINTENANCE_GROUP"], "children" => $children);
}
} while ( sqlsrv_next_result($stmt) );
i guess use below code
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Extract the activity name; we want to group the rows by it
$name = $row['ACTIVITY_NAME'];
// Check if this activity was encountered before
if (! isset($data[$name])) {
// No, this is the first time; we will make room for it, first
$data[$name] = array(
// Remember the name
'ACTIVITY_NAME' => $name,
// No children yet
'children' => array(),
);
}
// Put the row into the list of children for this activity
$data[$name]['children'][] = $row;
}
$json=json_encode($data);

combine two foreach statements( image& text)

I'm using a "foreach" statement to fetch all images from a folder to print on webpage.
I also need to give 'links' to these images.
Links are saved in database table called 'advertisement'.
I fetched all images and displayed correctly.
but I can't make these images as links.
I also used another "foreach" statement to fetch 'link' rows from table 'advertisement' table.
but how to combine these two.
Here is an example of how you could do it:
$files = array('1.jpg','2.jpg');
$stm = $pdo->query('SELECT * FROM advertisement');
$linkInfo = $stm->fetchAll(PDO::FETCH_ASSOC);
$outputArray = array();
foreach( $linkInfo as $row )
{
if( in_array($row['file'], $files) )
{
$outputArray['file'] = $row['link'];
}
}
foreach( $outputArray as $file => $link )
{
echo "<a href='".$link."'><img src='". $file ."'></a>";
}
Not sure how your structure is, but say you have a table like this:
------------------------------
| file | link |
------------------------------
| 1.jpg | http://... |
+
+
+
This should work, with some adjustment according to your own structure.

PHP merge tablerows

I got a table as DOMDocument which looks like this:
name | user | comment
-----------------------------
Test | user1 | Line 1
Abc | user2 | Line 1
| | Line 2
Test2 | user3 | Line 1
Test3 | user3 | Line 1
| | Line 2
| | Line 3
as you can see, sometimes the comment Wraps over multiple tablerows. (Apparently when the comment is a long one)
When those wraps occur, all fields except for the comment one are empty.
How can I merge those wrapped comments together and output them?
I am currently outputting them like this:
foreach ($xml->getElementsByTagName('table')->item(1)->getElementsByTagName('tr') as $row) {
echo "<tr>";
foreach ($row->getElementsByTagName('td') as $column) {
echo "<td>" . $column->textContent . "</td>";
}
echo "</tr>";
}
}
You are outputting each row before you know what the next one contains. A different approach would be to store each row in an array, allowing you to correct the previous row if the following row meets a certain condition (eg. wrapping). You can then output the resulting array as an HTML table once processed.
Something like this (untested):
// build array
$rows = array();
$xmlRows = $xml->getElementsByTagName('table')->item(1)->getElementsByTagName('tr');
foreach ($xmlRows as $xmlRow) {
$emptyFields = 0;
$row = array();
$xmlColumns = $xmlRow->getElementsByTagName('td');
foreach ($xmlColumns as $xmlColumn) {
if (empty($xmlColumn->textContent)) { // count empty fields
$emptyFields++;
}
$row[] = $xmlColumn->textContent;
}
if ($emptyFields >= 2) { // detect if wrapping has occurred
$lastRow = array_pop($rows); // remove last row from array
$lastRow[2] .= $row[2]; // update last row with wrapped data
$row = $lastRow; // use newly merged row
}
$rows[] = $row;
}
// output array
foreach ($rows as &$row) {
$row = '<td>' . implode('</td><td>', $row) . '</td>';
}
echo '<table><tr>' . implode('</tr><tr>', $rows) . '</tr></table>';

Reducing Mysql Querys & OOP

Let's say I have:
class language_text{
protected $id;
protected $keyword;
protected $language;
protected $text;
function __construct($clave,$lan){
$consulta = mysql_query("SELECT id,clave,lengua,texto,id_usuario FROM textos WHERE clave = '$clave' AND lengua = '$lan'");
if(mysql_num_rows($consulta)>0){
while($item = mysql_fetch_array($consulta)){
$this->id = $item['id'];
$this->clave = $item['clave'];
$this->lengua = $item['lengua'];
$this->texto = $item['texto'];
$this->id_usuario = $item['id_usuario'];
$this->exists = true;
}
return true;
}else{
$this->exists = false;
$this->clave = $clave;
return $this->clave;
}
}
}
function get_texto_clave_html($clave){
$clave = htmlspecialchars($clave);
$lan = detectarIdioma();
$temporal = new texto($clave, $lan);
if($temporal->exists()==true){
return $temporal->get_texto_html();
}else{
return $clave;
}
}
}
So everytime I need some language text I call: get_texto_clave($lan, $keyword), but in every page might be about 25 texts, so I think I should load all language in an array and then access it instead of the database.
For example:
I want welcome text under Spanish get_texto_clave(2,'welcome_html');
I want goodbye text under Spanish get_texto_clave(2,'bye_bye_html');
Questions:
What do you think about it?
Would you add a new class like language_text_collection or something like that?
Thanks to experimentX contribution, here we have current solution:
Use static method to get the instances of object.
$data = language_text::getData($lan, $keyword);
And on getData method
public function getData($lan, $keyword)
{
$data = array();
//query here
$consulta = mysql_query("SELECT id,clave,lengua,texto,id_usuario FROM textos WHERE clave = '$clave' AND lengua = '$lan'");
while($item = mysql_fetch_array($consulta))
{
$selfitem = new self;
$selfitem->id = $item['id'];
$selfitem->clave = $item['clave'];
...
...
$data[] = $selfitem;
}
return $data[]; //end the end you send an array of data
}
Now $data will contain an array of objects. Use the loop to access its properties.
foreach($data as $d)
{
echo $d->id;
echo $d->clave;
...
...
}
but I can't see it yet,
I asume in $data we have all language text for current languageId,
so, how i can i extract, for example, 'welcome_body' from $data?
UPDATE::
I think database is not quite suited for this kind of operation. I would advise you to revise your database design.
+----+---------------+---------------+----------+
| id | message_type | message_text | language |
+----+---------------+---------------+----------+
| 1 | good morning | good morning | english |
| 2 | good_morning | something.... | spanish |
+----+---------------+---------------+----------+
First create a database like
Create a database object to query database like this one.
//do not use keyword, its no use at all
//Of course it's pointless say good morning and at the end ...goodbye in some language
//and also logically, it's useless because we have to query data
$message = language_text::getData($lan);
Your query must be something like this SELECT* FORM message WHERE language='english' or something. //also it's better to add DISTINCT for selecting. I will explain later why.
And use the the content message_type type to add property to the object.
while($item = mysql_fetch_array($consulta))
{
$selfitem = new self;
$selfitem->$item['message_type'] = $item['message_type'];
$data[] = $selfitem;
}
return $data;
And now echo out the property echo $data->hello_message; or goodbye message
Now, you have to consider that no two duplicate entry for message_type should be added for same language. So, it's better to add DISTINCT in select statement. And also you have to check it.
OTHER WAY:: You can also create database with static messages, its not flexible, but reliable, and can be used with the other method i presented to you.
+----+------------+--------------+-------------+
| id | language | goodmorning | goodnight |
+----+------------+--------------+-------------+
| 1 | english | good morning | good night | -- and so on and on
| 2 | spanish | something....| .......... | -- and so on and on
+----+---------------+-----------+-------------+
NOTE::Usually the content of page is loaded at once than to load one by one.
PS::Your english is terrible.

Categories