accessing mysql field in the simpleXML through Object / Method - php

I am working on generating XML file using simpleXml...I have the following code.
require_once('inc.php');
$query = $glb_connection->prepare('select * from table order by ID');
$query->execute();
$tree = $query->fetchAll();
$doc = $xml->init();
foreach($tree as $tr){
$xml_events = $doc->addChild('entr');
$xml_events->addAttribute('ID', $tr['ID']);
$xml_events->addAttribute('cmp', $tr['cmp']);
// add another child
$xml_supervisor = $xml_events->addChild('personDetail');
// instatiate class
$pro = new profile();
// passing getDetail method
$person = $pro->getDetail($tr['ID']);
// it prints all the detail of the ID as expected (using it to check if return true)
print_arr($person);
$xml_supervisor->addAttribute('firstname', $person->lastname);
$xml_supervisor->addAttribute('familyname', $person['lastname']);
}
$file = 'example.xml';
$xml->saveXML($doc,$file);
from the above code, the problem is here...I try to call the field-name from the result object person, but both way I have tried doesn't work...
$xml_supervisor->addAttribute('firstname', $person->lastname);
$xml_supervisor->addAttribute('familyname', $person['lastname']);
how can I call any key or value from generated result of person Object???
some one has help...
This is how the array generated when I call
print_arr($person);
Array
(
[0] => Array
(
[ID] => 10
[lastname] => Sara
)
)

Ohhh, Sorry to bother you every-one, I have found the problem...I don't know what is wrong with me today, any way...
Some one might need it the exact answer some-day, so here it is....
the array is Associative-array in which if we need to call ID it should be like this..
array[0][ID]...means
this should be called like this..
$xml_supervisor->addAttribute('familyname', $person[0]['lastname']);
That is it.

Related

Removing duplicates from merged array

I've been doing here some name processor, and I've run into small, kind of noob-ish problem.
I have CSV file with names and status, filters them only by 'Cool Ones" status, then i'm querying SQL, and getting another list of names that i have entered manually.
So here is code example, where i'm taking CSV file, filter, querying SQL, then it creates array, merges it and sorts alphabetically.
$nameFile = "names/$eid.csv";
$content = array_map('str_getcsv', file($nameFile));
$filteredData = array_filter($content, function($v){
return $v['1'] === 'Cool Ones'; },ARRAY_FILTER_USE_BOTH); //because in this file there are also 'Not Cool Ones'
$freePeople = array();
$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = '$eid' ORDER BY 'guestName'");
$sth->execute();
$result2 = $sth->fetchAll(PDO::FETCH_NUM);
$listNames = array();
foreach($result2 as $row) {
$listNames[] = $row['0'];
$freeGuestName = $row['0'];
$freeGuestType = $row['1'];
}
$merged = array_merge($filteredData, $result2);
$sortedGuests = usort($merged, "sortGuestNames");
so my problem lies, that when outputing array, I'm getting duplicate results,
[50] => Array
(
[0] => John Down
[1] => Best Ones
)
[51] => Array
(
[0] => John Down
[1] => Cool Ones
)
Dunno what's next - i want that if my queried name is same as in this first CSV file, then hide this one, and show mine.
i was trying to unset key with
foreach($merged[$i]['0'] as $key => $value) {
if (in_array($merged[$i]['0'], $value)) {
unset($merged[$i]['0'][$key]);
}
}
but no luck, still outputing duplicates.
You can suggest better approach.
I've thought - maybe open CSV, query SQL and find my manual names - look up in opened CSV fields, append my status there, merge and push them to SQL database or new CSV file, where it could be outputted.
Thanks a lot!
A few things,
The thing we need to do is merge both arrays, but control which one overwrites the other. I am not sure if what you have does that now (in a reliable way) but one way to do that is to build 2 arrays. Both with the same structure, and the key as your unique field so we want this:
$csv = ['John Down' => ['John Down','Best Ones']];
$db = ['John Down' => ['John Down','Cool Ones']];
Then when we do array merge, the second argument will overwrite the first. So if we do
$csv = ['John Down' => ['John Down','Best Ones']];
$db = ['John Down' => ['John Down','Cool Ones']];
print_r(array_merge($csv, $db));
echo "\n";
print_r(array_merge($db, $csv));
Output:
// print_r(array_merge($csv, $db));
Array
(
[John Down] => Array
(
[0] => John Down
[1] => Cool Ones
)
)
//print_r(array_merge($db, $csv))
Array
(
[John Down] => Array
(
[0] => John Down
[1] => Best Ones
)
)
Sandbox
As you can see we can control which array is overwritten by the order we send them to array_merge in. The second one (or right one) overwrites the one to the left. So simply it reads from left to right.
So now what's the easiest way to get that structure from the DB? In PDO we can use FETCH_GROUP which takes the first column in the query and uses it as the top level key.
$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = :eid GROUP BY guestName ORDER BY guestName");
//-- add `GROUP BY guestName` we don't want duplicates anyway
//-- no quotes see: ... ORDER BY 'guestName');
//-- use prepared statements
$sth->execute(['eid'=>$eid]);
$result2 = $sth->fetchAll(PDO::FETCH_NUM);
$result2 = array_column($result2, null, 0);
For the CSV you can build it that way when you read the file (by adding the key) and using fgetcsv or you can use this trick (also used above):
$csv = [['John Down','Best Ones']];
print_r(array_column($csv, null, 0));
Output
Array
(
[John Down] => Array
(
[0] => John Down
[1] => Best Ones
)
)
Sandbox
Which should give you basically what we need, then it's a simple matter of using array_merge.
One thing to mention is if your DB or CSV are not unique, you'll get some duplicate removal there too, you may have to account for.
Removing duplicates is fine, but you want to make sure to remove the correct duplicates in a repeatable and robust way. Using array_merge we can control that no mater the order the rows come in from the DB and the file.
Summery
So if we put this all together, this is all you should need:
$nameFile = "names/$eid.csv";
$content = array_map('str_getcsv', file($nameFile));
$filteredData = array_filter($content, function($v){
return $v['1'] === 'Cool Ones';
},ARRAY_FILTER_USE_BOTH); //because in this file there are also 'Not Cool Ones'
$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = :eid GROUP BY guestName ORDER BY guestName");
$sth->execute(['eid'=>$eid]);
$result2 = $sth->fetchAll(PDO::FETCH_NUM);
$listNames = array_column($result2, 0);
$merged = array_merge(array_column($filteredData, null, 0), array_column($result2, null, 0));
$sortedGuests = usort($merged, "sortGuestNames");
So instead of adding code in patching over an issue, we went to the root cause and fixed it there and reduced the code by a few lines. This will work provided your CSV is in the correct format. guestName, guestType
Cheers!
http://php.net/manual/en/function.array-column.php
array_column ( array $input , mixed $column_key [, mixed $index_key = NULL ] ) : array
array_column() returns the values from a single column of the input, identified by the column_key. Optionally, an index_key may be provided to index the values in the returned array by the values from the index_key column of the input array.
input A multi-dimensional array or an array of objects from which to pull a column of values from. If an array of objects is provided, then public properties can be directly pulled. In order for protected or private properties to be pulled, the class must implement both the __get() and __isset() magic methods.
column_key The column of values to return. This value may be an integer key of the column you wish to retrieve, or it may be a string key name for an associative array or property name. It may also be NULL to return complete arrays or objects (this is useful together with index_key to reindex the array).
index_key The column to use as the index/keys for the returned array. This value may be the integer key of the column, or it may be the string key name. The value is cast as usual for array keys (however, objects supporting conversion to string are also allowed).
Assuming that you need unique user name, following is the solution.
Create a new blank users array.
Loop over the users array.
Append the users to new users array.
The key should be user name.
Hence, every time the same user comes, he will overwrite the previous one, removing duplicate.
Code:
$users = [
['John Down', 'Best Ones'],
['John Down', 'Cool Ones']
];
$newUsers = [];
if (! empty($users)) {
foreach ($users as $user) {
$newUsers[$user[0]] = $user[1];
}
}
echo '<pre>';print_r($newUsers);echo '</pre>';
// Output:
Array
(
[John Down] => Cool Ones
)
I solved my case:
I removed second key from merged array, then unserialize it, and mapped only unique ones! Everything is now working!
$input = array_map("unserialize", array_unique(array_map("serialize", $merged)));
Sometimes i really enjoy asking help for you, because it makes me think! To think deeper than ussual.

Appending new data to object

I'm stuck trying to append new data to an stdClass object that I'm creating for an AMchart
I'm returning all the rows I want from the DB, then creating a new object and looping through the returned array, but rather than appending what I want to the end of the existing object, it just gets overwritten. PHP objects dont have an append or push method, so how do you accomplish this?
Here's what my code looks like. Am I missing something simple?
$sql = 'SELECT
count(*) as clients,
STR_TO_DATE(Appt_date, \'%m/%d/%Y\') AS date,
SUM(wait_time) as total_wait_time
FROM tb_by_client
WHERE status = #qualifier
GROUP BY Appt_date';
$rows = $db->fetchAll($sql);
$chartObject = new stdClass();
foreach($rows as $row){
$row->average = round($row->total_wait_time / $row->clients);
$chartObject->date = $row->date;
$chartObject->average = $row->average;
}
$chartArray[] = $chartObject;
return json_encode($chartArray);
So instead of getting something that looks like this
[{"date":"2018-10-01","average":12},{"date":"2018-10-02","average":-33},{"date":"2018-10-04","average":23},{"date":"2018-10-05","average":6}]
I get back just a single
[{"date":"2018-10-01","average":12}]
Because each loop overwrites the last key and value
How do you append instead?
Your problem is you overwrite the data without saving it
$chartObject = new stdClass();
foreach($rows as $row){
$row->average = round($row->total_wait_time / $row->clients);
$chartObject->date = $row->date;
$chartObject->average = $row->average;
}
$chartArray[] = $chartObject;
See on each iteration of foreach($rows as $row){ you change the data in $chartObject, but you never save in your $chartArray.
Do this instead
foreach($rows as $row){
$chartObject = new stdClass(); //new instance of stdClass, obj pass by refrence
$row->average = round($row->total_wait_time / $row->clients);
$chartObject->date = $row->date;
$chartObject->average = $row->average;
$chartArray[] = $chartObject;
}
Personally I wouldn't even bother with using an object:
foreach($rows as $row){
$average = round($row->total_wait_time / $row->clients);
$chartArray[] = ['date'=>$row->date,'average'=>$average];
}
When you JSON Encode an array with string keys, it will make it the correct Javascript Object structure. So there really is no need to keep all those objects in memory and the code is much smaller, cleaner, and easier to read.
One last thing I hinted at in the code, is that objects are pass by reference in PHP (now), and if you don't create a new instance of the object for each iteration, you will actually update all references to the object. This can be illustrated like this:
$obj = new stdClass;
$objects = [];
for($i=0;$i<3;++$i){
$obj->foo = $i;
$objects[] = $obj;
print_r($objects);
}
Output:
Array
(
[0] => stdClass Object
(
[foo] => 0
)
)
Array
(
[0] => stdClass Object
(
[foo] => 1
)
[1] => stdClass Object
(
[foo] => 1
)
)
Array
(
[0] => stdClass Object
(
[foo] => 2
)
[1] => stdClass Object
(
[foo] => 2
)
[2] => stdClass Object
(
[foo] => 2
)
)
Sanbox
Each array is a single iteration of the for loop, this is the same array with another row added after each iteration.
As you can see each copy (its not really a copy) is updated by reference in the array. Basically we have stored the same object (instance ,will call him Bob) 3 times, instead of 3 separate objects (Bob, Alice, John).
If the data you stored was the color of a persons shirt, when Bob puts on a red shirt, he has a red shirt on, but Alice and John don't.
Because of this you need to create a new instance of the object for each iteration and store that.
Hope that helps!
You can do the maths in the SQL and it cuts out the loop altogether...
$sql = 'SELECT STR_TO_DATE(Appt_date, \'%m/%d/%Y\') AS date,
round(SUM(wait_time)/count(*)) as average
FROM tb_by_client
WHERE status = #qualifier
GROUP BY Appt_date';
return json_encode($db->fetchAll($sql));
You're misunderstanding what should be in the loop and what shouldn't.
This should be fine:
$sql = 'SELECT
count(*) as clients,
STR_TO_DATE(Appt_date, \'%m/%d/%Y\') AS date,
SUM(wait_time) as total_wait_time
FROM tb_by_client
WHERE status = #qualifier
GROUP BY Appt_date';
$rows = $db->fetchAll($sql);
$chartArray = [];
foreach($rows as $row){
$row->average = round($row->total_wait_time / $row->clients);
$chartObject = new stdClass();
$chartObject->date = $row->date;
$chartObject->average = $row->average;
$chartArray[] = $chartObject;
}
return json_encode($chartArray);

Print specific array key

I need to use a key from an array for a check.
The array comes from a PDO query like this
function getProject($proj_id) {
$database = new Database();
$database->query( "SELECT * FROM projects WHERE proj_id = '$proj_id' LIMIT 1" );
$project = $database->resultSet();
return $project;
}
Then I print the array which works like it should.
$project = getProject(1);
print_r($project);
Array ( [0] => Array ( [proj_id] => 73 [proj_name] => Cake )
But when I try to print a specific key from the array like this:
print_r($project['proj_name'];
Nothing gets printed on the screen. Why not?
You have two arrays:
Array ( [0] => Array ( [proj_id] => 73 [proj_name] => Cake )
^--this one ^--and this one
You need to do:
print_r($project[0]['proj_name']);
Probably the ideal situation would actually be to change it here:
function getProject($proj_id) {
$database = new Database();
$database->query( "SELECT * FROM projects WHERE proj_id = '$proj_id' LIMIT 1" );
$project = $database->resultSet();
return $project[0]; //<---added the [0] this line
}
since you know it will always return one
If you look carefully, you'll see that you have two arrays nested one inside the other. Try print_r($project[0]['proj_name'];
You're missing a close-paren ) at the end of your print_r call.
You're seeing nothing on the screen because this means the file cannot be parsed, and errors are being logged to a file rather than displayed on screen. See How do I get PHP errors to display? for how to fix that.

Array ( [0] => Array ... problems extracting array values

I am trying to run a function that gets information from a DB and returns an array of the values, so I can then extract it on the page.
Inside the function, after my query I have the following code:
$example_array = array();
while ($row = mysql_fetch_assoc($query) {
$example_array[] = $row;
}
return $example_array;
And there ends my function. Outside of it, I have this:
extract($example_array);
And I would assume I could then directly echo any of the variables that were previously in $example_array, e.g. <?= $example_var ?> but they do not contain any data.
Running print_r($example_array); gives an array that looks like this:
Array ( [0] => Array ( [example_var] => Example String ) )
The start of that code makes me think my array is somehow "lost" inside another array's first ([0]) value, and as such is not extracting correctly.
Have I gone about adding data to that initial $example_array incorrectly?
When you do $example_array[] = $row;, you assign the current row to a new index of $example_array. If you want to access it like $example_array['row_name'], you'd have to assign it like this:
$example_array = $row;
But when you do this, $example_array will be overwritten until it has reached the last row (which means that $example_array will always contain the last row from the query). If you just want the first row, you can do this and skip the whole while loop:
$example_array = mysql_fetch_assoc($query);
Maybe :
$example_array = array();
while ($row = mysql_fetch_assoc($query) {
array_push($example_array, $row['exemple_var']);
}
return $example_array;
The issue is that mysql_fetch_array would have meant $row['row_name'] was valid.
As you added $row to the array $example_array, you now need to access it via it's array id too, such as;
$example_array[0]['row_name'], $example_array[1]['row_name'] etc.
What exactly are you trying to achieve? May be easier to offer assistance if we know.

Writing PHPUnit Test for a function returning an array

now a days I am playing with PHPUnit. I have gone through its documentation but I am unable to understand it well. Let me explain my case.
I have a function in a class which takes three parameters 1 array, 2 some string, 3 a class object.
This function returns the array by putting second parameter as an index of the array and result as object of that index. My function is as below
public function construct($testArray, $test,$analysisResult) {
$postedTest = explode('_', $test);
$testName = end($postedTest);
$postedTest = implode("_", array_slice($postedTest, 0, -1));
if (in_array($postedTest, array_keys($testArray))) {
$testArray[$postedTest][$testName] = $analysisResult;
} else {
$testArray[$postedTest] = array($testName => $analysisResult);
}
return $testArray;
}
If I call this function like
$constructObj = new Application_Model_ConstructTree();
$test=$this->getMockForAbstractClass('Abstract_Result');
$test->level = "Error";
$test->infoText = "Not Immplemented";
$testArray = Array('databaseschema' => Array('Database' => $test));
$result = $constructObj->construct($testArray,"Database",$test);
The function returns the array like
Array
(
[databaseschema] => Array
(
[Database] => AnalysisResult Object
(
[isRepairable] => 1
[level] => Error
[infoText] => Not Implemented
)
)
)
Now I want to write a PHPUnit Test to check that the attributes of object like isRepairable, level and infoText exists and not empty. I have gone an idea that assertNotEmpty and assertAttributeEmpty can do some thing But I am unable to understand how to do it.
My test looks like
public function testcontruct() {
$constructObj = new Application_Model_ConstructTree();
$test=$this->getMockForAbstractClass('Abstract_Result');
$test->level = "Error";
$test->infoText = "Not Immplemented";
$testArray = Array('databaseschema' => Array('Database' => $test));
$result = $constructObj->construct($testArray,"Database",$test);
$this->assertNotCount(0, $result);
$this->assertNotContains('databaseschema', $result);
}
Can anyone please guide :-)
The last line should be assertContains instead assertNotContains. The next steps in your test would be:
$this->assertContains('Database', $result['databaseschema']);
$this->assertAttributeNotEmpty('isRepairable', $result['databaseschema']['Database']);
$this->assertAttributeNotEmpty('level', $result['databaseschema']['Database']);
$this->assertAttributeNotEmpty('infoText', $result['databaseschema']['Database']);
assertAttributeNotEmpty takes the attribute name and the object as parameters, just as assertContains takes the array key and the array.
I'd use assertArrayHasKey ie:
$this->assertArrayHasKey($key, $array);
Because you need to test a complex structure, what I'd do is going to each one of the expected elements and assert that they are there, and they are not empty with assertNotEmpty()
I found this a good example, similar to your problem:
http://opensourceame.com/asserting-that-an-array-contains-another-array-in-phpunit/

Categories