Laravel API resource (Problem with creating exact API) - mysql

I want to create an API in the below format. But I am unable to do it. I am using the API resource. I have tried using different queries but I am not getting the exact solution.Please help me.
Thank you
what I have tried
$marks = StudentMarksResource::collection(StudentsMark::whereIn('academic_id',$ids)->whereIn('student_id',$studentid)->get());
my API resource file
public function toArray($request)
{
return [
'exam_type' => $this->exam_type,
'details' => [
/* 'class_id' => Course::find($this->class_id),
'batch_id' => Batch::find($this->batch_id),
'student_id' => Student::find($this->student_id), */
'subject' => $this->subject,
'marks' => $this->marks,
'marksgrade' => $this->marksgrade,
'total' => $this->total,
'grade' => $this->grade,
'percentage' => $this->percentage,
'year' => $this->year,
],
];
}
what I want is this
data": [
{
"exam_type": "Unit Test 1",
"details": {
//subject1 details
},
{
//subject2 details
},
{
//subject3 details
},
"exam_type": "Unit Test 2",
"details": {
//subject1 details
},
{
//subject2 details
},
{
//subject3 details
},
},
what I am getting for the above code
"data": [
{
"exam_type": "Unit Test 1",
"details": {
//subject1 marks details
}
},
{
"exam_type": "Unit Test 1",
"details": {
//subject2 marks details
}
},

Here is something you can try:
First get exam types
$exam_types = StudentsMark::select('exam_type', 'student_id', 'academic_id')->whereIn('academic_id',$ids)->whereIn('student_id',$studentid)->get();
$marks = StudentMarksResource::collection($exam_types);
Now inside resource that's when you can retrieve the details
#do not forget to import StudentsMark
#and you can make a resource for details, just to make clean code
return [
'exam_type' => $this->exam_type,
'details' => StudentsMark::where('academic_id', $this->academic_id)
->where('student_id', $this->student_id)
->get();
];

Related

Laravel: Resources with json field

I am on Laravel 7.x and I have two models (CustomerOrder composed of many CustomerOrderLines) with parent - child relationship. Parent (CustomerOrder) model has a json type field among its fields.
CustomerOrderResource.php:
return [
'id' => $this->id,
'wfx_oc_no' => $this->wfx_oc_no,
'qty_json' => json_decode($this->qty_json)
];
CustomerOrderLineResource.php:
return [
'id' => $this->id,
'description' => $this->description,
'customer-order' => $this->customerOrder
];
CustomerOrder->GET request returns properly formatted data as:
"data": {
"id": 11,
"wfx_oc_no": 12,
"qty_json": {
"L": "20",
"M": "30",
"S": "20",
"XL": "100"
}
}
But for CustomerOrderLine->GET, the response is as:
"data": {
"id": 15,
"description": "test desc",
"customer-order": {
"id": 11,
"wfx_oc_no": 12,
"qty_json": "{\"L\": \"20\", \"M\": \"30\", \"S\": \"20\", \"XL\": \"100\"}"
}
}
json field is not properly formatted. It seems it doesn't go through Resource class. Please let me know, how can I get this fixed?
FYI
CustomerOrderLine.php:
public function parent()
{
return $this->belongsTo(CustomerOrder::class);
}
Finally managed to get it solved using json cast. The field was included in $casts array in the model.

Access nested JSON in React table

I want to display nested JSON data in a react-table.
I tried it like this:
render() {
const columns = [{
//Not Displaying
Header: 'Owner ID',
id: 'ownerid',
accessor: '_links.customer.href.ownerid', // <- i think this is wrong
Cell: this.renderEditable
},
{
//Displaying
Header: 'Price',
accessor: 'price',
Cell: this.renderEditable
}, {
The data i am getting back and have bound to the table is structured as follows:
[
{
"id": 1,
"date": "20.07.2019",
"price": 3.2,
"customer": {
"ownerid": 1,
"firstname": "John",
"lastname": "Johnson"
}
}
]
Here i am using the columns array:
import ReactTable from "react-table";
<ReactTable data={this.state.offers} columns={columns}
filterable={true} pageSize={10}/>
Binding the data:
fetchOffers = () => {
const token = sessionStorage.getItem("jwt");
fetch(SERVER_URL + 'api/offers',
{
headers : {'Authorization':token}
})
.then((response) => response.json())
.then((responsteData) => {
this.setState({
offers: responsteData._embedded.offers,
});
console.log(this.state);
})
.catch(err=> console.error(err));
}
The data i am using after binding:
Check the Accessors documentation. It has several examples for complex data structure.
I don't see _links or href in your sample data. So I think that you need just:
accessor: 'customer.ownerid'
The data structure from the console screenshot doesn't match your sample data. And it doesn't seem to contain ownerid. Try accessor: '_links.customer.href' to check whether it outputs anything to the table.
I figured it out.
I called the endpoint "localhost:8080/api/offers" and saved the following response:
"offers": [
{
"date": "20.07.2019",
"price": 3.2,
"_links": {
"self": {
"href": "http://localhost:8080/api/offers/1"
},
"offer": {
"href": "http://localhost:8080/api/offers/1"
},
"customer": {
"href": "http://localhost:8080/api/offers/1/customer"
}
}
}
]
there is no customer object
But when i call "localhost:8080/offers" i get:
[
{
"id": 1,
"date": "20.07.2019",
"price": 3.2,
"customer": {
"ownerid": 1,
"firstname": "John",
"lastname": "Johnson"
}
}
]
i changed the URI in my project and now the number is displaying.
I still don't know why i get data from "../api/offers" but i will research.
I had to access a nested object and display it with some styling, and this ended up working for me:
(Note: I was using typescript, so some of the typing might not be necessary)
{
Header: 'Thing To Display',
accessor: 'nested.thing.to.display',
Cell: ({ row }: { row: Row }) => (
<p>{row.values['nested.thing.to.display']}</p>
),
}

REST API: how to post a manytomany relationship with fosrestbundle

In my Symfony 4 project, I have 2 entities: Question and PossibleAnswer. A question can have many possible answers and an answer can be used in many different questions.
I want to POST a question, I use FOSRestBundle. This is how I would format the body of my request:
{
"title": "my question",
"possibleAnswers": [
{
"id": 1,
"title": "my first answer"
}
]
}
At least this is how FOSRestBundle formats the answer when I create the data directly in the database and GET the question.
But I keep getting the same error:
Validation Failed, possibleAnswers This value is not valid
I use Symfony forms to validate my POST and the fieldType I use for the possibleAnswers field of Question is an EntityType with the option multiple set to true. Maybe that's where the error comes from.
So my question is: How do I format the body of my request to add a valid possibleAnswers field ? and if I am doing it right then, which form type should I use for it to work ?
Sorry for not adding any code, the context is actually quite more complex but I'm pretty sure either the JSON Format of my field or the form type is wrong.
[edit]
here are all the form types I tried for the possibleanswers field
//->add('possibleAnswers', EntityType::class, array('data' => [], 'required' => false, 'multiple' => true, 'class' => PossibleAnswer::class))
->add('possibleAnswers', CollectionType::class, array('required' => false, 'entry_type' => EntityType::class, 'entry_options' => array('class' => PossibleAnswer::class)))
//->add('possibleAnswers', CollectionType::class, array('required' => false, 'entry_type' => PossibleAnswerType::class))
//->add('possibleAnswers', CollectionType::class, array('required' => false, 'entry_type' => PossibleAnswerType::class, 'entry_options' => array('class' => PossibleAnswer::class)))
here are all the JSON formats I tried to select the possibleanswers:
{
"title": "a postman created question",
"answerConditions": [
{
"id": 1,
"title": "already existing question",
}
]
}
{
"title": "a postman created question",
"answerConditions": [
{
"possibleanswer_id": 1
}
]
}
{
"title": "a postman created question",
"answerConditions": [
{
"id": 1
}
]
}
{
"title": "a postman created question",
"answerConditions": [
1
]
}
If you want to create the PossibleAnswer when posting the Question, you need to replace in your form the EntityType by a CollectionType.
I often use it in my POST request when I want to post the sub-object (here the PossibleAnswer) when I post the parent (Question) :
Question form
$builder
->add('possibleAnswers', CollectionType::class, array(
'entry_type' => PossibleAnswerType::class,
'allow_add' => true,
))
;
PossibleAnswer form :
$builder
->add('title')
;
And the json looks like :
{
"title": "my question",
"possibleAnswers": [
{
"title": "my first answer"
}
]
}
Hope it can help.
Edit :
If you want to link a PossibleAnswer to a Question while creating you Question you can use this :
Question form :
$builder
->add('possibleAnswer', EntityType::class, array(
'class' => YOUR_ENTITY::class,
'multiple' => true
));
And you json should only contains the id of the entity you want to link to. It should be like this :
{
"title": "a postman created question",
"answerConditions": [
1
]
}

Laravel Array & JSON Casting to Algolia

I am trying to send some data along to Algolia through the toSearchableArray. Any strings I have stored in my DB are sending along fine, but I hit a roadblock when trying to push nested JSON data along—the information is being sent as a string with characters escaped.
This is a sample of the nested object that I am storing in my table (MySQL with a JSON data type):
[
{
"id": 19,
"name": "Mathematics",
"short": "Math"
},
{
"id": 23,
"name": "Science",
"short": "Science"
},
{
"id": 14,
"name": "Health and Life Skills",
"short": "Health"
}
]
My model looks like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Resource extends Model
{
use Searchable;
protected $primaryKey = 'objectID';
public function toSearchableArray()
{
$data = $this->toArray();
$data['grades'] = explode(';', $data['grades']);
$data['units'] = explode(';', $data['units']);
return $data;
}
}
I get an output that looks like this:
array:22 [
"objectID" => 1
"name" => "Resource #1"
"slug" => "resource-1"
"write_up" => """
This is an example write up.
"""
"author" => "johnny"
"type_name" => "Lesson Plan"
"language" => "English"
"grades" => array:3 [
0 => "Kindergarten"
1 => "Grade 1"
2 => "Grade 4"
]
"subjects" => "[{"id": 19, "name": "Mathematics", "short": "Math"}, {"id": 23, "name": "Science", "short": "Science"}, {"id": 14, "name": "Health and Life Skills", "short": "Health"}]"
"units" => array:2 [
0 => "Unit A"
1 => "Unit B"
]
"main_image" => "https://dummyimage.com/250x325/000000/fff.png&text=Just+a+Test"
"loves" => 88
"downloads" => 280
"created_at" => "2018-01-01 13:26:47"
"updated_at" => "2018-01-02 10:10:32"
]
As you can see, the 'subjects' attribute is being stored as a string. I know there is attribute casting in 5.5 (I am running 5.5), but I am not too clear on how I would implement the example they have for Array & JSON Casting in my work above. https://laravel.com/docs/5.5/eloquent-mutators#attribute-casting
Would anyone be willing to show me an example?
I'd rely on Attribute Casting for this, add a $casts property in your model and it will be done automatically.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Resource extends Model
{
use Searchable;
protected $primaryKey = 'objectID';
protected $casts = [
'subjects' => 'array',
];
public function toSearchableArray()
{
// Same function as you posted
}
}
You can also do it manually in your toSearchableArray method with $data['subjects'] = json_decode($this->subjects, true);
I answered with more details on this other posts: https://discourse.algolia.com/t/laravel-array-json-casting-to-algolia/4125/2

Getting a selected property from a getter

I have an array of containers in my state and I'm trying to setup a getter that splits it into active and inactive containers.
containers: [{
id: '1',
name: 'test container',
image: 'some image',
state: 'running',
status: 'Running'
}, {
id: '2',
name: 'another test container',
image: 'some image',
state: 'stopped',
status: 'Running'
}]
I'm using this to get the array below.
export const x = state => _.partition(state.containers, c => c.state === 'running');
The problem with this is I want it split and assigned to activeContainers and stoppedContainers and then exported.
[
[
{
"id": "1",
"name": "test container",
"image": "some image",
"state": "running",
"status": "Running"
}
],
[
{
"id": "2",
"name": "another test container",
"image": "some image",
"state": "stopped",
"status": "Running"
}
]
]
I've tried using ES6's deconstruction but I think I'm missing something or putting the deconstruction in the wrong place for it to work with Vuex.
export const [activeContainers = [], stoppedContainers = []] = state => _.partition(state.containers, c => c.state === 'running');
Returning functions from a getter
As per the comments go by in the question, it is indeed true that you can't have two properties mapped by a getter. Reading more that you didn't want another getter for the activeContainers and stoppedContainers
After going through the link you shared, I found a way you could still have something very close to a parameterized getter.
Here you can see it in full effect.
getters = {
getContainer: (state) => {
const [activeContainer = [], inactiveContainer = []] = _.partition(state.containers, c => c.state === 'running')
return (container) => {
return (container === 'activeContainer') // returned function
? activeContainer
: inactiveContainer
}
}
}
Here in this getter, I am returning a function, which can accept parameters and get something very close to what you desire.