How do I propagate variables of an instance of an object from mySQL data using php?
Here is my object in pseudo code:
exam:{
questions:[
question:{
questionID: string
questionTest: string
categoryID: string
correctAnswerID: string
chosenAnswerID: string
answers:[
answer:{
answerID = string
answerText = string
isTrue = bool
}
answer:{}
]
}
question:{}
]
categoryID: string
}
Here are the corespondant clases (there is a big chance that the syntax is wrong, I am new to php):
class ExamClass
{
// property declaration
public $questions = 'a default value';
public $categoryID = 'a default value';
}
class QuestionClass
{
// property declaration
public $questionID = 'a default value';
public $questionTest = 'a default value';
public $categoryID = 'a default value';
public $correctAnswerID = 'a default value';
public $chosenAnswerID = 'a default value';
public $answers = 'a default value';
}
class AnswersClass
{
// property declaration
public $answerID = 'a default value';
public $answerText = 'a default value';
public $isTrue = 'a default value';
}
And here is the php code that extracts the data from the data base:
<html>
<body>
<?php
/*
exam:{
questions:[
question:{
questionID: string
questionTest: string
categoryID: string
correctAnswerID: string
chosenAnswerID: string
answers:[
answer:{
answerID = string
answerText = string
isTrue = bool
}
answer:{}
]
}
question:{}
]
categoryID: string
}
*/
class ExamClass
{
// property declaration
public $questions = 'a default value';
public $categoryID = 'a default value';
}
class QuestionClass
{
// property declaration
public $questionID = 'a default value';
public $questionTest = 'a default value';
public $categoryID = 'a default value';
public $correctAnswerID = 'a default value';
public $chosenAnswerID = 'a default value';
public $answers = 'a default value';
}
class AnswersClass
{
// property declaration
public $answerID = 'a default value';
public $answerText = 'a default value';
public $isTrue = 'a default value';
}
header('Content-Type: text/html; charset=utf-8');
$con=mysqli_connect("localhost","root","root","Theory");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$result = mysqli_query($con,"SELECT `questions`.`questionID` AS questionID,
`questions`.`questionText` AS questionText,
`questions`.`categoryID` AS categoryID,
`answers`.`answerID` AS answerID,
`answers`.`answerText` AS answerText,
`answers`.`isTrue` AS isTrue
FROM `questions`,`answers`
WHERE `questions`.`questionID` = `answers`.`questionID`
AND `questions`.`categoryID` = 2");
if (!$result)
{
die('Error: ' . mysqli_error($con));
}
$rows = array();
while($r = mysqli_fetch_assoc($result)) {
$rows[] = $r;
}
print json_encode($rows);
mysqli_close($con);
?>
</body>
</head>
And this is how the currently extracted data looks:
[
{
"questionID": "2",
"questionText": "question text 2",
"categoryID": "2",
"answerID": "1",
"answerText": "answer text 1",
"isTrue": "0"
},
{
"questionID": "2",
"questionText": "question text 2",
"categoryID": "2",
"answerID": "2",
"answerText": "answer text 2",
"isTrue": "1"
},
{
"questionID": "2",
"questionText": "question text 2",
"categoryID": "2",
"answerID": "3",
"answerText": "answer text 3",
"isTrue": "0"
},
{
"questionID": "2",
"questionText": "question text 2",
"categoryID": "2",
"answerID": "4",
"answerText": "answer text 4",
"isTrue": "0"
}
]
From your comments, it seems as though you asking how to hydrate these objects with data with the database. Instead of going to from the database, to JSON, into an object, take a look at mysqli_fetch_object.
With mysqli_fetch_object() you can specify a class to initialize with data from the query. In your case:
$result = mysqli_query('SELECT * FROM Answers;');
while ($answer = mysqli_fetch_object($result, 'AnswersClass')) {
var_dump($answer);
}
Note: I answered one of your other questions already today and it seems like you are starting out with some of these things. I would encourage you to read about Data Mapper and Active Record Patterns.
This should give you some ideas on how to map your data source to your classes.
class Exam
{
// property declaration
public $questions = array();
public $categoryID;
}
class Question
{
// property declaration
public $questionID;
public $questionTest;
public $categoryID;
public $correctAnswerID;
public $chosenAnswerID;
public $answers = array();
}
class Answer
{
// property declaration
public $answerID;
public $answerText;
public $isTrue;
}
class ExamBuilder{
public function buildExam($data){
$e = new Exam();
$e->categoryID = $data->categoryID;
$this->addQuestions($data->questions, $e);
return $e;
}
protected function addQuestions ($questions, Exam $exam){
foreach ($questions as $question){
$q = new Question();
$q->questionID = $question->questionID;
$q->questionTest = $question->questionTest;
$q->categoryID = $question->categoryID;
$q->correctAnswerID = $question->correctAnswerID;
$q->chosenAnswerID = $question->chosenAnswerID;
$this->addAnswers($question->answers, $q);
$exam->questions[] = $q;
}
}
protected function addAnswer($answer, Question $question){
$a = new Answer();
$a->answerID = $a->anwerID;
$a->answerText = $answer->answerText;
$a->isTrue = $answer->isTrue;
}
}
To use
$builder = new ExamBuilder();
$exam = $builder->buildExam($data);
Related
Whats the best way to output a json like an organization chart? Seems my loop is not good. Can't really get whats the empUnd for every employees. How to make a good loop for this type of chart like get every empUnd over and over until its empty
Create endpoint that shows the organization structure.
/test/chart
Response Format:
{
"empNo: "123",
"name": "Jennifer Sy",
"jobDesc": "CEO",
"empUnd: [
{
"empNo": "456",
"name": "Mike Tolomia",
"jobDesc": "VP",
"empUnd": [{}]
}
]
}
Here's my controller:
public function chart() {
$employeeDetails = $this->api_model->fetch_employees();
foreach ($employeeDetails as $employeeDetail) {
$test = $this->api_model->checkEmployeeUnder($employeeDetail['employeeNumber']);
$result[] = [
'empNo' => $employeeDetail['employeeNumber'],
'name' => $employeeDetail['firstName'],
'empUnd' => $test
];
}
return $this->output->set_content_type('application/json')->set_output(json_encode($result));
}
My Model:
public function fetch_employees()
{
$qry = $this->db->get('employees');
$result = $qry->result_array();
return $result;
}
public function checkEmployeeUnder($reportsTo)
{
$this->db->select('empNo, CONCAT(firstName, '.' , " ", lastName) AS name');
$this->db->from('employees');
$this->db->where('reportsTo', $reportsTo);
$qry = $this->db->get();
$result = $qry->result_array();
return $result;
}
I am trying to create a dynamic endpoint for a API I am creating in order to include some data but only if it is required so I can use it in multiple places.
The idea is to have api.domain.com/vehicle to bring back basic vehicle information but if I did api.domain.com/vehicle?with=owners,history then the idea is to have a function which maps the owners and history to a class which will return data but only if it is required.
This is what I currently have.
public static function vehicle()
{
$with = isset($_GET['with']) ? $_GET['with'] : null;
$properties = explode(',', $with);
$result = ['vehicle' => Vehicle::data($id)];
foreach ($properties as $property) {
array_push($result, static::getPropertyResponse($property));
}
echo json_encode($result);
}
Which will then call this function.
protected static function getPropertyResponse($property)
{
$propertyMap = [
'owners' => Vehicle::owner($id),
'history' => Vehicle::history($id)
];
if (array_key_exists($property, $propertyMap)) {
return $propertyMap[$property];
}
return null;
}
However, the response I'm getting is being nested within a index, which I don't want it to be. The format I want is...
{
"vehicle": {
"make": "vehicle make"
},
"owners": {
"name": "owner name"
},
"history": {
"year": "26/01/2018"
}
}
But the format I am getting is this...
{
"vehicle": {
"make": "vehicle make"
},
"0": {
"owners": {
"name": "owner name"
}
},
"1": {
"history": {
"year": "26/01/2018"
}
}
}
How would I do this so it doesn't return with the index?
Vehicle::history($id) seems to return ['history'=>['year' => '26/01/2018']], ...etc.
foreach ($properties as $property) {
$out = static::getPropertyResponse($property) ;
$result[$property] = $out[$property] ;
}
Or your methods should returns something like ['year' => '26/01/2018'] and use :
foreach ($properties as $property) {
$result[$property] = static::getPropertyResponse($property) ;
}
I have a laravel query builder result that looks like this
{
"data": [
{
"id": "",
"awardID": 2,
"title": "Dummy title",
"status": "active",
"raceStart":"",
"raceEnd:":""
}
]
}
What i want to output is something like this
{
"data": [
{
"id": "",
"awardID": 2,
"title": "Dummy title",
"status": "active",
"period": {
"raceStart":"",
"raceEnd:":""
}
}
]
}
This would have been much easier if the period was a table with a 1 to 1 relationship with parent table but this is not the case here.
How can this be achieved?
Check if this will work. I haven't tried though but according to documentation we can add accessor and mutators. But it will change every response you are doing with the model.
Using Eloquent
// Your Model
class Race extends Model
{
{...}
protected $appends = ['period'];
// accessor
public function getPeriodAttribute($value)
{
$this->attributes['period'] = (object)[];
$this->attributes['period']['raceStart'] = $this->attributes['raceStart'];
$this->attributes['period']['raceEnd'] = $this->attributes['raceEnd'];
unset($this->attributes['raceStart']); = $value;
unset($this->attributes['raceEnd']);
return $this->attributes['period'];
}
}
Now when you will access $race->period will give the raceStart and raceEnd value.
Ref: https://laravel.com/docs/5.4/eloquent-mutators#accessors-and-mutators
else another option is after query, do a map
{...}
->map(function($data) {
$data->period = (object)[];
$data->period['raceStart'] = $data->raceStart;
$data->period['raceEnd'] = $data->raceEnd;
unset($data->raceStart);
unset($data->raceEnd);
return $data;
});
Ref: https://laravel.com/docs/5.4/eloquent-collections#introduction
Using QueryBuilder
$races = DB::table('races')->get();
$races = array_map(function ($data) {
$data->period = (object)[
"raceStart" => $data->raceStart,
"raceEnd" => $data->raceEnd
];
unset($data->raceStart);
unset($data->raceEnd);
return $data;
}, $races->data);
I have the following model (object) which contains some normal fields and a nested array.
I'm trying to convert the model to a complete array, I've come across some tricks such as the following.
public function getMessageArray()
{
return (array) $this->message;
}
But that's giving the following result
Another trick is to use the json_encode and decode as following:
$result= json_decode(json_encode($this->message), true);
But that's returning an empty array.
App\Mailer\Models\Message {#505
-subject: "You bought products 3 days ago"
-fromEmail: "no-reply#test.be"
-fromName: "Webshop"
-replyTo: "no-reply#test.be"
-toEmail: "test#gmail.com"
-toName: "Myself"
-mergeVars: array:2 [
"rcpt" => "test#gmail.com"
"vars" => array:2 [
0 => array:2 [
"name" => "fname"
"content" => "My"
]
1 => array:2 [
"name" => "lname"
"content" => "Self"
]
]
]
}
This is a print_r() of $this->message
I cannot convert $this->message to an array to get access to all the properties. Any idea what I might be doing wrong?
When attributes are private, they cannot be accessed directly. json_encode() does not encode them.
The PublicMaker class below provides access to all the attributes of an object: private and public.
<?php
/*
* Make all the attributes of a class public
*/
class PublicMaker {
public $matches;
function __construct($obj) {
// explode object attribute and values
$print_r = print_r($obj, true);
preg_match_all('/\[(\w*).*\] => (.*)/', $print_r, $matches);
$this->matches = $matches;
}
function getArray() {
foreach($this->matches[1] as $key=>$match) {
$arr[$match] = $this->matches[2][$key];
}
return $arr;
}
// magic method to get any attribute of the object passed in the contructor
function __get($attribute) {
$match = array_search($attribute, $this->matches[1]);
if ($match !== FALSE) {
return $this->matches[2][$match];
} else {
return NULL;
}
}
}
// test values
class Message {
private $subject = 'You bought products 3 days ago';
private $fromEmail = "no-reply#test.be";
public $fromName = "Webshop";
}
// usage demonstration
$message = new Message();
$publicMessage = new PublicMaker($message);
$array = $publicMessage->getArray();
$subject = $publicMessage->subject;
echo '<pre> getArray: ';
print_r($array);
echo "\n Subject: $subject \n";
// other test values
echo "
Other test values:";
print_r((array) $message);
print_r($publicMessage->matches); // debug
echo "\n subject: ", $publicMessage->subject; // string(30) "You bought products 3 days ago"
echo "\n fromEmail: ", $publicMessage->fromEmail;
echo "\n fromName: ", $publicMessage->fromName;
echo "\n notExist ", $publicMessage->notExist;
var_dump($publicMessage->notExist); // NULL
The regex can be tested and refined here: http://www.phpliveregex.com/p/gje
I have a page that pulls information about TV shows from the TMDB as a json array with the help of the TMDB-API Wrapper. I am trying to get the page to display information on a tv shows's ['network'].
I have written a function for this that loops through the network array but I can't get it to work. Can anyone tell me what I'm doing wrong? Thanks.
This is my function that does not work.
//Get networks
public function getNetworks() {
$networks = array();
foreach($this->_data['networks'] as $data){
$networks[] = new Network($data, $this->getName());
}
return $networks;
}
Display.php
//Call the function and loop though results
echo ' <li>Networks: <ul>';
$networks = $tvShow->getNetworks();
foreach($networks as $network){
echo '<li>'. $network->getID() .'</li>';
}
This does work (written in the wrapper not me)
public function getSeasons() {
$seasons = array();
foreach($this->_data['seasons'] as $data){
$seasons[] = new Season($data, $this->getID());
}
return $seasons;
}
This does work
//Get Network
public function getNetworks() {
return $this->_data['networks'][0]['name'];
}
And then on display.php
echo '<b>'. $tvShow->getNetworks() .'</b>';
This is the json array
{
"backdrop_path": "/c8A5IYqIT1ez15sqA8wX5tCDTmF.jpg",
"created_by": [
{
"id": 1187819,
"name": "Matthew Weiner",
"profile_path": null
}
],
"episode_run_time": [
47,
45
],
"first_air_date": "2007-07-19",
"genres": [
{
"id": 18,
"name": "Drama"
}
],
"homepage": "http://www.amc.com/shows/mad-men",
"id": 1104,
"in_production": false,
"languages": [
"en"
],
"last_air_date": "2015-05-17",
"name": "Mad Men",
"networks": [
{
"id": 174,
"name": "AMC"
}
],
Tvshow Class
class TVShow{
//------------------------------------------------------------------------------
// Class Variables
//------------------------------------------------------------------------------
private $_data;
/**
* Construct Class
*
* #param array $data An array with the data of the TVShow
*/
public function __construct($data) {
$this->_data = $data;
}