Can someone help me figure out what I'm doing wrong here. Basically, this script is looping through $replies from a query and adding values to the object. However, its overwriting the ->replies with the last one.
$store->{$f->id}->replies = $store->{$f->id}->replies ?? (object)[];
$store->{$f->id}->replies->{$reply->id} = $reply;
If this was to loop through 3 replies, it should store:
$store->{$f->id}->replies->one = 'reply 1';
$store->{$f->id}->replies->two = 'reply 2';
$store->{$f->id}->replies->three = 'reply 3';
Instead it only stores the third one:
$store->{$f->id}->replies->three
Here is full code of the loop:
while($f = $q->fetch()) {
$reply = static::chatter_message_format($f);
$store->{$f->id} = $f;
//If checking for posts from friends, user_id will be array
if(is_array($user_id)) {
if($reply) {
$store->{$f->id}->replies = $store->{$f->id}->replies ?? (object)[];
$store->{$f->id}->replies->{$reply->id} = $reply;
}
}
}
If I echo $reply in the loop, I see each reply. The $store is being written to a cache file but it seems to only save the last reply for each post.
I code in python mostly but have inherited this project in PHP - a lot of it is over my head but I'm learning rapidly :) I will be rebuilding this using an API-first approach soon but trying to salvage what I can for prototype.
Ah, figured it out. Issue in the loop, this fixed it:
if(is_array($user_id)) {
if(!isset($store->{$f->id})) {
$store->{$f->id} = $f; //Was creating a new object here before the isset check.
}
if($reply) {
$store->{$f->id}->replies = $store->{$f->id}->replies ?? (object)[];
$store->{$f->id}->replies->{$reply->id} = $reply;
}
Related
I am trying to get all images from an image API. It returns a maximum of 500 result at a time and if the result has a next_page field, then I have to grab the value of that field and add it to the URL. The code should continue looping until that field is absent. I used the following code to grab the first two pages:
$key = true;
$link = 'https://url.com/dhj/?prefix=images&type=download';
$json = file_get_contents($link);
$data = json_decode($json, true);
$dataArray = array();
foreach ($data["images"] as $r)
{
array_push($dataArray, array($r["id"], $r["image"]));
}
while($key)
{
if($data["next_page"])
{
$key=true;
$link2 = "https://url.com/dhj/?prefix=images&type=download&next_page=" . $data[$next_page];
$json2 = file_get_contents($link2);
$data2 = json_decode($json2, true);
foreach ($data2["images"] as $r2)
{
array_push($dataArray, array($r2["id"], $r2["image"]));
}
}
else
{
$key=false;
}
}
This should fetch 2000 records but is only fetching 1000 records, so it appears the loop is not working as expected.
So your problem is that you are only fetching twice. The second time, you never check $data2 for a next page, so everything stops. You do not want to keep going like this, or you will need $data3, $data4, etc.
A do/while loop is similar to a while loop, except that it always runs at least once. The condition is evaluated at the end of the loop instead of the beginning. You can use that behaviour to ensure you always get the first page of data, and then use the condition to check if you should keep getting more.
$page = "";
do {
$link = "https://url.com/dhj/?prefix=images&type=download&next_page=$page";
$json = file_get_contents($link);
$data = json_decode($json, true);
foreach ($data["images"] as $r) {
$dataArray[] = [$r["id"], $r["image"]];
}
$page = $data["next_page"] ?? "";
} while ($page);
Note I've got rid of your array_push() call. This is rarely used in PHP because the $var[] syntax is less verbose and doesn't require predeclaration of the array. Likewise, calls to array() have long been replaced by use of array literal syntax.
The expression $page = $data["next_page"] ?? "" uses the null coalesce operator, and is identical to:
if (isset($data["next_page"])) {
$page = $data["next_page"];
} else {
$page = "";
}
I want to insert the details of a quiz in which among a lot of strings (question, professor, course, etc) , I have one array of answers (and its corresponding array of is_correct), so I thought of creating a for loop to insert each answer properly.
The problem is I don't know how to correctly call the questionQuiz object. I noticed if I declare two different objects at the beginning and then do this manually:
$questionQuiz1 -> insert_question($quiz_name,$professor,$course,$question,$points,$answer[0],$is_correct[0]);
$questionQuiz2-> insert_question($quiz_name,$professor,$course,$question,$points,$answer[1],$is_correct[1]);
it works.
How should I declare this object as an array and use it in an iteration?
I tried something like this but it isn't correct.
$questionQuiz[] = new Test();
if(isset($_POST['quiz_name'],$_POST['professor'],$_POST['course'],$_POST['question'],$_POST['points'],$_POST['answer'], $_POST['is_correct'])) {
$quiz_name = $_POST['quiz_name'];
$professor = $_POST['professor'];
$course = $_POST['course'];
$question = $_POST['question'];
$points = $_POST['points'];
$answer = $_POST['answer'];
$is_correct = $_POST['is_correct'];
if(!empty($quiz_name) && !empty($professor)&& !empty($course)&& !empty($question)&& !empty($points)&& !empty($answer) && !empty($is_correct)){
for($i=0; $i<count($answer); $i++) {
$questionQuiz[$i] -> insert_question($quiz_name,$professor,$course,$question,$points,$answer[$i],$is_correct[$i]);
}
}else{
echo json_encode("param must not be empty");
}
}
Should I instantiate $questionQuiz[] = new Test(); inside the loop? I tested and it seems to work, is it correct to do it this way?
So the problem in your code, is that you only create 1 instance of Test class (at the top). And inside your for loop, you only reference it and call the insert_question method on it. Beware: in this case only $questionQuiz[0] exists, so in the other cases nothing happens (or an error might occur).
Option 1
If you only want to call the method on the Test class, you could call it in your for loop like this:
(new Test())->insert_question( ... etc ... );
Option 2
If you want to store the created class objects, you create a new Test object, call the insert_question method on it and add the object to your array:
$object = new Test();
$object->insert_question( ... etc ...);
$questionQuiz[] = $object;
You seem to have the logic all laid out, your just not doing what you're saying.
Create an array, and then add a new object to that array each time through the loop.
$questionQuiz[] = array();
if(isset($_POST['quiz_name'],$_POST['professor'],$_POST['course'],$_POST['question'],$_POST['points'],$_POST['answer'], $_POST['is_correct'])) {
...
for($i=0; $i<count($answer); $i++) {
$questionQuiz[$i] = new Test();
$questionQuiz[$i] -> insert_question($quiz_name,$professor,$course,$question,$points,$answer[$i],$is_correct[$i]);
}
...
I will note however, that something seems off about having a function called insert_question() where you individually insert single answers options on seemingly multiple-choice questions. I would think you would pass an array of answer options with corresponding correctness.
You mentioned storing the posts to an object array. would something like this work?
<?php
if(isset($_POST['quiz_name'], $_POST['professor'], $_POST['course'], $_POST['question'], $_POST['points'], $_POST['answer'], $_POST['is_correct']))
{
$quiz_name = $_POST['quiz_name'];
$professor = $_POST['professor'];
$course = $_POST['course'];
$question = $_POST['question'];
$points = $_POST['points'];
$answer = $_POST['answer'];
$is_correct = $_POST['is_correct'];
}
if(!empty($answer_array) && count($answer_array[5]) > 0)
{
$count = count($answer_array[5]);
$questionQuiz[] = new Test();
for($i=0; $i < $count; $i++)
{
//assuming your class is correct and you'll need to have it handle the incoming array how you want it to
$answer_array = array($quiz_name, $professor, $course, $question, $points, $answer[$i], $is_correct[$i]);
$questionQuiz[$i] -> insert_question($answer_array);
}
}
else
{
echo "param must not be empty";
}
?>
This is the structure of the php code that I am using
$Objects = $account->api1(); // This returns an object array with each object being O(data1, data2, data3)
$retValue = array();
foreach($Objects as $O)
{
if($O->data2 == 'something')
{
$data4 = $account->api2($O->data2); // returns a value $data4
// Initialize $tmp;
$tmp->data1 = $O->data1;
$tmp->data3 = $O->data3;
$tmp->data4 = $data4;
$retValue[] = $tmp;
}
}
Basically what I need is an object array of the following for which data2 = 'something'
O(data1,data3,data4)
Is there a way in which I can simplify this process. Each api call costs money and also involves request across request which makes this process both costly and also slow.Can this be improved anyway ? Even little bit improvement in performance/no of calls would be really helpful.
Important: I'll assume you have some typos in your question and the following equivalences
$data2 means $O->data2 Fixed in the question
$O->data4 means $data4 Fixed in the question
Calling $account->api2($O->data2) should always return the same value
because you always check that $O->data2 is equal to "something"..
So you can call it just once, insteand of each time you have a hit.
<?php
$Objects = $account->api1(); // This returns an object array with each object being O(data1, data2, data3)
$retValue = array();
foreach($Objects as $O)
{
if($O->data2 == 'something')
{
// Here, you just call api2 the first time (or never, maybe, if you never needed to)
$data4 = isset($data4) ? $data4 : $account->api2($O->data2);
// Initialize $tmp;
$tmp->data1 = $O->data1;
$tmp->data3 = $O->data3;
$tmp->data4 = $data4;
$retValue[] = $tmp;
}
}
?>
TL;DR
I have this data: var_export and print_r.
And I need to narrow it down to: http://pastebin.com/EqwgpgAP ($data['Stock Information:'][0][0]);
How would one achieve it? (dynamically)
I'm working with vTiger 5.4.0 CRM and am looking to implement a function that would return a particular field information based on search criteria.
Well, vTiger is pretty weakly written system, looks and feels old, everything comes out from hundreds of tables with multiple joins (that's actually not that bad) etc., but job is job.
The need arose from getting usageunit picklist from Products module, Stock Information block.
Since there is no such function as getField();, I am looking forward to filter it out from Blocks, that is actually gathering the information about fields also.
getBlocks(); then calls something close to getFields();, that again something close to getValues(); and so on.
So...
$focus = new $currentModule(); // Products
$displayView = getView($focus->mode);
$productsBlocks = getBlocks($currentModule, $displayView, $focus->mode, $focus->column_fields); // in theory, $focus->column_fields should/could be narrowed down to my specific field, but vTiger doesn't work that way
echo "<pre>"; print_r($productsBlocks); echo "</pre>"; // = http://pastebin.com/3iTDUUgw (huge dump)
As you can see, the array under the key [Stock Information:], that actually comes out from translations (yada, yada...), under [0][0] contains information for usageunit.
Now, I was trying to array_filter(); the data out from there, but only thing I've managed to get is $productsBlocks stripped down to only contain [Stock Information:] with all the data:
$getUsageUnit = function($value) use (&$getUsageUnit) {
if(is_array($value)) return array_filter($value, $getUsageUnit);
if($value == 'usageunit') return true;
};
$productsUsageUnit = array_filter($productsBlocks, $getUsageUnit);
echo "<pre>"; print_r($productsUsageUnit); echo "</pre>"; // = http://pastebin.com/LU6VRC4h (not that huge of a dump)
And, the result I'm looking forward to is http://pastebin.com/EqwgpgAP, that I've manually got by print_r($productsUsageUnit['Stock Information:'][0][0]);.
How do I achieve this? (dynamically...)
function helper($data, $query) {
$result = array();
$search = function ($data, &$stack) use(&$search, $query) {
foreach ($data as $entry) {
if (is_array($entry) && $search($entry, $stack) || $entry === $query) {
$stack[] = $entry;
return true;
}
}
return false;
};
foreach ($data as $sub) {
$parentStack = array();
if ($search($sub, $parentStack)) {
$result[] = $parentStack[sizeof($parentStack) - 2];
}
}
return $result;
}
$node = helper($data, 'usageunit');
print_r($node);
I'm new to OOP in PHP, is that to seems correct ?
class whatever {
Function Maths() {
$this->sql->query($requete);
$i = 0;
while($val = mysql_fetch_array($this)) {
$tab[i][average] = $val['average'];
$tab[i][randomData] = $val['sum'];
$i=$i+1;
}
return $tab;
}
I want to access the data contained in the array
$foo = new whatever();
$foo->Maths();
for ($i, $i <= endOfTheArray; i++) {
echo Maths->tab[i][average];
echo Maths->tab[i][randomData];
}
Thank you ;)
EDIT: i want to output the result of the SQL query as an array, so i can access it from outside the class
In the interest of helping you out, here are some modifications. Please hear this, though: a lot of this might not make sense without a good background in PHP or OOP in general. You should look at #webbiedave's link.
class whatever {
static function maths() {
$tabs = array();
$results = $this->sql->query($requete);
while($val = mysql_fetch_array($this)) {
$tabs = $val;
}
return $tabs;
}
This fixes syntax errors and logic errors (for instance, the creation of the $results variable to hold the SQL query run).
I made the maths method static, since there's really no need to instantiate a whatever() object with this current example.
Here are some modifications to how this would be used:
$results = whatever::maths();
foreacho ($results as $result) {
echo $result['average'];
echo $result['randomData'];
}
Since maths() returns something, you need to store that in a variable; simply calling it, as you did previously, doesn't do anything.
That convoluted for loop can be replaced with a foreach loop.
Please check out PHP OOP basics:
http://www.php.net/manual/en/language.oop5.basic.php
Edit: Thanks for cleaning up the code. Try something along the lines of:
$tabs = array();
while($val = mysql_fetch_assoc($result)) {
$tabs[] = $val;
}
And:
$foo = new whatever();
$tabs = $foo->Maths();
for ($tabs as $tab) {
echo $tab['average'];
echo $tab['randomData'];
}
http://www.php.net/manual/en/language.oop5.basic.php