Structuring OOP Php methods and objects when using a JSON API call - php

I am making an application that pulls data through JSON with CURL. I'm using PHP and my script currently creates 2 different objects to contain the curl requests. I've got the data in a readable format, but I need to divide an average from the first call by an average from the second call.
This average is of equal relevance to each of the calls - and I'm new to working with objects and classes so am struggling to understand how to structure this in the right way. The following line of code doesn't work - but, if you read on it will hopefully help to explain what I'm trying to do.
$yield = object1->calculate_average($list)->average['price']/object2->calculate_average($list)->average['price'];
I want to code the $yield variable in to the listing class as a further method that will display when I call $anobject->yield. Should I access this via a) object1, b) object2, or c) it's own object (which seems excessive..as it will only be used occasionally). Is there a right way to do this, or does it not really matter?
My query is general (what is the best approach to using objects when an object appears to be as relevant to all options, and is it possible to reference arrays like this: calculate_average($list)->average['price']) as much as it is specific (how can I fix this script)
When this has come up before I've tended to just regrab the data from the source and fudge it, but because it's a JSON call and therefore takes a bit longer I've been prompted to find a better solution...
A simplified version of my best effort so far is below.
I've assumed that I need to use foreach on the json outputs:
class listing {
//This takes a stdClass object from the JSON and prepares it to be served
public function output_list($data) {
$price = "0";
$vals = "0";
$list = array();
foreach ($data->listing as $item) {
//Calculate average price
$price = $price + $item->price;
$vals = $vals + 1;
//Display information about each item
$list[$vals][] = "Price: £" . $item->price . " and various data";
$list[$vals][] = ...;
}
return $list;
}
// This function calculates equations on the data which I read above
public function calculate_average($list) {
$average = array();
$total_price = array_column($list, '1'); //Find the total sum of list[?][1] which = price
$vals = count($list); //count the number of values in the list
$average['denominator'] = $vals;
$average['week'] = $total_price / $average['denominator'];
//And a number of other calculations within the array...
return $average;
}
}
I then want to call these by using the following code:
$object1 = new listing();
$list1 = $object1->output_list($response); ////Output formatted data
print_r($list1);
$average = $object1->calculate_average($list);
$object2 = new listing();
$list2 = $object2->output_list($response); ////Output formatted data
print_r($list2);
$average = $object2->calculate_average($list);
The other thing is that $total_price = array_column($list,'1') needs me to have php 5.5 - which I don't have, so I need to find an alternative - and that makes me question whether my array approach is the right one in the first place. [I need to sum every [?][1] reference in the multi-dimensional array I've made].
If you're able to help I'd be so grateful - I've been trying to get my head around objects and classes for weeks!

Related

Processing multiple variables in a single function PHP

I'm pretty new and need guidance on how to approach a simple problem.
I'm building an app in PHP to allow different views of Fantasy Premier League (FPL) team data. I'm pulling data from an API (JSON array), looping through it, and storing it in a db. One of the API calls needs a team_id to pull that team's respective players.
My initial thinking is to write a function that takes the team_id as an argument, then parses the data to insert into the db. But how would I pass each of 12 different team_ids to the function to be processed without repeating the function 12 times for each team_id?
So, I might have:
$team_id_1 = 1;
$team_id_2 = 2;
$team_id_3 = 3;
etc...
Then my function might be:
function insert_team_data($team_id) {
$fplUrl = 'https://fantasy.premierleague.com/api/entry/' . $team_id . '/event/29/picks/';
foreach ($team_data as $key => $value) {
# code...
}
$sql = "INSERT INTO ..."
}
Is it possible to construct this in a way where each team_id gets passed to the function iteratively in a single process (i.e. without repeating the function code for each team_id)? Would I create an array of the team_ids and have the function loop through each one, then loop through each resulting team's data?
Yes, you can do either: use an array or a variadic function.
The way you're thinking of doing it is what's called a variadic function or variable-length function.
It can be achieved through either the use of func_get_args() or the splat operator, which handles argument packing/unpacking.
Here's an example.
function insert_team_data(... $team_ids) {
// $team_ids will appear as an array in your function
foreach ($team_ids as $team_id) {
$fplUrl = "https://fantasy.premierleague.com/api/entry/$team_id/event/29/picks/";
$sql = "INSERT INTO ..."
// rest of code...
}
}
You can now call the function like this: insert_team_data(1, 2, 3, 4, 5)

Completely remove objects from runtime

I'm running a job where I import stock information from loads of suppliers. Some of them have many products, so when I store them in memory it quickly gets pretty heavy.
For that reason, I'd like to - after doing whatever-i-do-with-them - completely unset each supplier.
Each "supplier" is a Reader and a Processor which gets injected into a Manager which will return all data to N writers. The manager stores the Reader and Processor (which is the classes where the big amount of data will be) in a simple array.
Here's a quick demonstration:
$first = new stdClass();
$first->name = "I'm an object";
$first->age = 12;
$second = new stdClass();
$first->name = "I'm also an object!";
$first->age = 9;
$arr = array($first, $second);
while ($data = array_shift($arr)) {
echo "Emptying array one by one... \n";
//doesn't matter if you unset($data) or do $data=null;
}
//I want this to be empty, but's not
var_dump($first);
For now, I do a foreach() on the array and makes the value be passed by reference, which I then passes (by reference) to a cleanup() method. This feels clumsy.
Am I missing something obvious? How can I achieve this?

Filtering through several SQL searches to build a single array - need pointers

I'm new to web developing.
This is part of a phone service, and I'm trying to filter through 3 different arrays that are filled with strings from three database searches: $sfaa, $sfipc, and $sfuaa. I have to filter the three database arrays to locate available customer service agents. The output would be an array filled with the IVR_Number to dial.
Heres an example of the string: "'Id', 'IVR_Number', 'Market_Id'"
I have to explode the string in order to get my data from each value in the arrays. Then based on a one-to-many id in each string I have to check if the id from $sfaa is in $sfipc or $sfuaa. If not then I have to build an array with the filtered records, from there I have to locate a value from the exploded string in $sfaa that belongs to that id. I wrote the following code but theres got to be an easier way?? I hope.... The client has to wait for these results before moving forward. There is usually only 10 or 15 records.
This code works I'm just wondering if there is an easier way to do this
Any tips
// formalua needed to filter above results and fill $aadl array
// explode each active agent array
$activeagentsfec=0;
$aaivra= array();
$aaida= array();
foreach ($sfaa as $aavalue)
{
${'aadetails'.$activeagentsfec} = explode("'",$aavalue);
${'aaivr'.$activeagentsfec} = ${'aadetails'.$activeagentsfec}[5];
${'aaid'.$activeagentsfec} = ${'aadetails'.$activeagentsfec}[1];
array_push($aaivra, ${'aaivr'.$activeagentsfec});
array_push($aaida,${'aaid'.$activeagentsfec});
$activeagentsfec++;
}
// explode each inprogress call array
$activecallsfec=0;
$actida= array();
$acfida= array();
foreach ($sfipc as $acvalue)
{
${'acdetails'.$activecallsfec} = explode("'",$acvalue);
${'actid'.$activecallsfec} = ${'acdetails'.$activecallsfec}[5];
${'acfid'.$activecallsfec} = ${'acdetails'.$activecallsfec}[7];
array_push($actida, ${'actid'.$activecallsfec});
array_push($acfida, ${'acfid'.$activecallsfec});
$activecallsfec++;
}
// explode each unvailable agent
$unavailableagentsfec=0;
$uaaida= array();
foreach ($sfuaa as $uavalue)
{
${'uadetails'.$unavailableagentsfec} = explode("'",$uavalue);
${'uaaid'.$unavailableagentsfec} = ${'uadetails'.$unavailableagentsfec}[3];
array_push($uaaida, ${'uaaid'.$unavailableagentsfec});
$unavailableagentsfec++;
}
// create available agent array by id
$aaafec=0;
$aada= array();
foreach ($aaida as $aaidavalue)
{
if (in_array($aaidavalue,$actida,true))
$aaafec++;
elseif(in_array($aaidavalue,$acfida,true))
$aaafec++;
elseif(in_array($aaidavalue,$uaaida,true))
$aaafec++;
else
array_push($aada, $aaidavalue);
}
// available agent arry by ivr
$aadl= array();
foreach ($aada as $aadavalue)
{
$aaaivrsv= array_search($aadavalue,$aaida,true);
array_push($aadl,$aaivra[$aaaivrsv]);
}
Given what you were saying in the comments, I'll try to give you some useful thoughts...
You carry out much the same process to parse $sfaa, $sfipc, and $sfuaa - explode, get certain columns. If you had some way to abstract that process, with a generic function for the parsing, that returns the data in a better format, called three times on each array, you'd see better through your code.
In the same way, your process is tightly coupled to the current state of the data - e.g. ${'acdetails'.$activecallsfec}[5]; is your fifth item today, but will it always be? Something generic, where you seek an column by name, might save you a lot of trouble...
finally, when merging data, if the data is sorted before hand the merge can be a lot quicker - seeking N items in a list of M, with an unsorted list takes O(n*m) operations, but if both are sorted it's O(min(m,n)).
I've taken the time to go through your code... Unless you're usign some of its variables elsewhere, here is a shorter equivalent:
// formula needed to filter above results and fill $aadl array
// explode each active agent array
$aaivra= array();
$aaida= array();
foreach ($sfaa as $aavalue)
{
$a = explode("'",$aavalue);
array_push($aaivra, $a[5]);
array_push($aaida,$a[1]);
}
// explode each inprogress call array
$actida= array();
$acfida= array();
foreach ($sfipc as $acvalue)
{
$a = explode("'",$acvalue);
array_push($actida, $a[5]);
array_push($acfida, $a[7]);
}
// explode each unvailable agent
$uaaida= array();
foreach ($sfuaa as $uavalue)
{
$a= explode("'",$uavalue);
array_push($uaaida, $a[3]);
}
// create available agent array by id
$aada= array();
foreach ($aaida as $aaidavalue)
{
if (!in_array($aaidavalue,$actida,true) &&
!in_array($aaidavalue,$acfida,true) &&
!in_array($aaidavalue,$uaaida,true))
array_push($aada, $aaidavalue);
}
// available agent arry by ivr
$aadl= array();
foreach ($aada as $aadavalue)
{
$aaaivrsv= array_search($aadavalue,$aaida,true);
array_push($aadl,$aaivra[$aaaivrsv]);
}

Create PHP array's on the fly

I am having the worst time trying to get this to work. In the following code, I am gathering data from a database query and trying to build a muti-dimensional array object that will keep totals and tally up some information in a specific way. The problem is that instead of getting a value that is incrementing as it should, the value seems to be suffering from the last value it was assigned problem. Here is the code:
$REVIEWS = array();
$USER_REVIEWS = array();
$USER_IMGREVS = array();
pseudo-code: loop here which iterates over the DB results creating
$date - which is into this function as its called for each day of month
$p1user - which is one of the users (there are 3) 'levels' of users
$hr - is the hour which is built from the transaction's timestamp
$hr = date('H', $row['P1TIMESTAMP']);
$p1user = $row['P1USER'];
$REVIEWS[$date] += 1;
$USER_REVIEWS[$date][$p1user][$hr] += 1;
$USER_IMGREVS[$date][$p1user][$hr] += $row['F5'];
print "PASS1<br/>\n";
print "Value of Total Reviews: [".$REVIEWS[$date]."]<br/>\n";
print "Value of User Reviews: [".$USER_REVIEWS[$date][$p1user][$hr]."]<br/>\n";
print "Value of Reviewed Images: [".$USER_IMGREVS[$date][$p1user][$hr]."]<br/>\n";
print "<br/><br/>\n";
So - the 'total reviews' increments by one, as it should, for each time i print this. SO far so good. The next two arrays will only print the last values they were assigned, and will not be added together like they should. Why not? I have attempted to do this another way by literally creating the arrays one by one and assigning them in whole to the array containing them - but that also does not seem to work. Any insights?
i don't know how you initilize your array, maybe this will help:
// replace this 2 lines:
$USER_REVIEWS[$date][$p1user][$hr] += 1;
$USER_IMGREVS[$date][$p1user][$hr] += $row['F5'];
// with this code:
if (!isset($USER_REVIEWS[$date]))
$USER_REVIEWS[$date] = array();
if (!isset($USER_REVIEWS[$date][$p1user]))
$USER_REVIEWS[$date][$p1user] = array();
if (!isset($USER_REVIEWS[$date][$p1user][$hr]))
$USER_REVIEWS[$date][$p1user][$hr] = 0;
$USER_REVIEWS[$date][$p1user][$hr] += 1;
if (!isset($USER_IMGREVS[$date]))
$USER_IMGREVS[$date] = array();
if (!isset($USER_IMGREVS[$date][$p1user]))
$USER_IMGREVS[$date][$p1user] = array();
if (!isset($USER_IMGREVS[$date][$p1user][$hr]))
$USER_IMGREVS[$date][$p1user][$hr] = 0;
$USER_IMGREVS[$date][$p1user][$hr] += $row['F5'];
Sir, I dont understand very well why your coed is not working, but in my first test, I would change these lines:
$count = 1;
$USER_REVIEWS[$count][$p1user][$hr] += 1;
$USER_IMGREVS[$count][$p1user][$hr] += $row['F5'];
$count++;
Please, check if this code helps you anyway.
Your print statements for those values rely on the value of $p1user:
print "Value of User Reviews: [".$USER_REVIEWS[$date][$p1user][$hr]."]<br/>\n";
print "Value of Reviewed Images: [".$USER_IMGREVS[$date][$p1user][$hr]."]<br/>\n";
If you want to print it for all users you should loop over all possible users rather than just using $p1user. Either that or add them up if you want their sum.
Edit: Something that was bugging me was your data structure. It doesn't seem to represent your data very well. In your loop why don't you build up useful information that you store at the base of the review array?

Autofill array with empty data to match another array size

I have 2 sets of arrays:
$dates1 = array('9/12','9/13','9/14','9/15','9/16','9/17');
$data1 = array('5','3','7','7','22','18');
// for this dataset, the value on 9/12 is 5
$dates2 = array('9/14','9/15');
$data2 = array('12','1');
As you can see the 2nd dataset has fewer dates, so I need to "autofill" the reset of the array to match the largest dataset.
$dates2 = array('9/12','9/13','9/14','9/15','9/16','9/17');
$data2 = array('','','12','1','','');
There will be more than 2 datasets, so I would have to find the largest dataset, and run a function for each smaller dataset to properly format it.
The function I'd create is the problem for me. Not even sure where to start at this point. Also, I can format the date and data arrays differently (multidimensional arrays?) if for some reason that is better.
You can do this in a pretty straightforward manner using some array functions. Try something like this:
//make an empty array matching your maximum-sized data set
$empty = array_fill_keys($dates1,'');
//for each array you wish to pad, do this:
//make key/value array
$new = array_combine($dates2,$data2);
//merge, overwriting empty keys with data values
$new = array_merge($empty,$new);
//if you want just the data values again
$data2 = array_values($new);
print_r($data2);
It would be pretty easy to turn that into a function or put it into a for loop to operate on your array sets. Turning them into associative arrays of key/value pairs would make them easier to work with too I would think.
If datas are related will be painful to scatter them on several array.
The best solution would be model an object with obvious property names
and use it with related accessor.
From your question I haven't a lot of hint of what data are and then I have to guess a bit:
I pretend you need to keep a daily log on access on a website with downloads. Instead of using dates/data1/data2 array I would model a data structure similar to this:
$log = array(
array('date'=>'2011-09-12','accessCount'=>7,'downloadCount'=>3),
array('date'=>'2011-09-13','accessCount'=>9), /* better downloadsCount=>0 though */
array('date'=>'2011-09-15','accessCount'=>7,'downloadCount'=>3)
...
)
Using this data structure I would model a dayCollection class with methods add,remove,get,set, search with all methods returning a day instance (yes, the remove too) and according signature. The day Class would have the standard getter/setter for every property (you can resolve to magic methods).
Depending on the amount of data you have to manipulate you can opt to maintain into the collection just the object data (serialize on store/unserialize on retrieve) or the whole object.
It is difficult to show you some code as the question is lacking of details on your data model.
If you still want to pad your array than this code would be a good start:
$temp = array($dates, $data1, $data2);
$max = max(array_map('count',$temp));
$result = array_map( function($x) use($max) {
return array_pad($x,$max,0);
}, $temp);
in $result you have your padded arrays. if you want to substitute your arrays do a simple
list($dates, $data1, $data2) = array_map(....
You should use hashmaps instead of arrays to associate each date to a data.
Then, find the largest one, cycle through its keys with a foreach, and test the existence of the same key in the small one.
If it doesn't exist, create it with an empty value.
EDIT with code (for completeness, other answers seem definitely better):
$dates_data1 = array('9/12'=>'5', '9/13'=>'3', '9/14'=>'7' /* continued */);
$dates_data2 = array('9/14'=>'12', '9/15'=>'1');
#cycle through each key (date) of the longest array
foreach($dates_data1 as $key => $value){
#check if the key exists in the smallest and add '' value if it does not
if(!isset( $date_data2[$key] )){ $date_data2[$key]=''; }
}

Categories