How to create object from arrays of row in laravel Elequent - mysql

Here I want to make the array inside "property" to an object where the key of the object will be the value of 'key_name' column of product_property table
[{
"sort_order": 1,
"name": "Samosas",
"visible": 1,
"description": null,
"property": [
{
"product_uuid": "95be9cf4-7121-492b-8725-762e6353ac51",
"key_name": "categories",
"key_value": "Starter"
},
{
"product_uuid": "95be9cf4-7121-492b-8725-762e6353ac51",
"key_name": "print_order",
"key_value": "1"
}
]
}]
This is what I want
[{
"sort_order": 1,
"name": "Samosas",
"visible": 1,
"description": null,
"property": {
"categories": "Starter",
"print_order": "1"
}
}]
I tried with Product::with('property')->get() and it results the first array.
Is there any Eloquent way to do that or raw sql or Query Builder?
Looping throw the result and make that object is possible but here i want something from SQL end
$products = Product::with('property')->get();
foreach ($products as $product) {
$array = [];
foreach ($product->property as $property) {
$array[$property['key_name']] = $property['key_value'];
}
$product->properties = $array;
}
This looping giving me the results but its from php end
public function property(){
return $this->hasMany(ProductProperty::class, 'product_uuid', 'uuid');
}
The Product model
Product table
"sort_order",
"name",
"visible",
"description",
Product Property table
"product_uuid",
"key_name",
"key_value"
Thanks in advance

$products = Product::with('property')->get();
foreach ($products as $product) {
$array = [];
foreach ($product->property as $property) {
$array[$property['key_name']] = $property['key_value'];
}
$product->properties = (object) $array;
}
Add object. It will convert this to a std object.

Related

How do I add names to objects in JSON using PowerShell?

I have the following situation below. I'd like to add a name to each item in the array.
First item needs to have a name instead of being an anonymous object. How do I do this?
Items need to have an name derived from the Technical Name, so 988 instead of N988AB1.
Structure of array is changed to an object in the result.
Current situation:
{
"Category": [{
"TechnicalName": "N988AB1",
"Name": "House"
},
{
"TechnicalName": "H181AG3",
"Name": "Apartment"
},
{
"TechnicalName": "X123XY5",
"Name": "Villa"
}
]
}
Desired situation:
{
"Data": {
"988": {
"TechnicalName": "N988AB1",
"Name": "House"
},
"181": {
"TechnicalName": "H181AG3",
"Name": "Apartment"
},
"0123": {
"TechnicalName": "X0123XY5",
"Name": "Villa"
}
}
}
One way of tackling this: (You can copy and paste the full contents of the code box to try it out. I've commented what various steps are doing)
$ExistingJson = #"
{
"Category": [{
"TechnicalName": "N988AB1",
"Name": "House"
},
{
"TechnicalName": "H181AG3",
"Name": "Apartment"
},
{
"TechnicalName": "X123XY5",
"Name": "Villa"
}
]
}
"#
# Convert the json string to an object we can manipulate.
$ExistingObj = $ExistingJson | ConvertFrom-Json
# Create an empty hashtable for the new items we are creating.
$HT = #{}
foreach ($Category in $ExistingObj.Category) {
# Match any digits, grouped as "name", after any character [A-Za-z] which are followed by [A-Za-z] - this is pretty basic and may need to be changed if your TechnicalName string changes, or you want different information from it.
[System.Void]($Category.TechnicalName -match "(?<=[A-Za-z])(?<name>\d+)(?=[A-Za-z])")
$NewItem = [PSCustomObject]#{
TechnicalName = $Category.TechnicalName
Name = $Category.Name
}
# Add a new entry to the hashtable with the discovered digits by it's group name "name" and the object created above with the existing information as it's value.
$HT.Add($Matches["name"], $NewItem)
}
# Create a new object with a Data property with the value as the hashtable.
$NewObj = [PSCustomObject]#{
Data = $HT
}
# Convert it back to Json
$NewObj | ConvertTo-Json
Results in:
{
"Data": {
"988": {
"TechnicalName": "N988AB1",
"Name": "House"
},
"181": {
"TechnicalName": "H181AG3",
"Name": "Apartment"
},
"123": {
"TechnicalName": "X123XY5",
"Name": "Villa"
}
}
}

how to group result with json key name in laravel

user table
id name age
1 TuTu 3
2 SuSu 4
3 YuYu 4
4 MoMo 4
I want to output json like this.
[
{
"age": 3,
"user": [
{
"id": 2,
"name": "TuTu"
}
]
},
{
"age": 4,
"user": [
{
"id": 2,
"name": "SuSu"
},
{
"id": 3,
"name": "YuYu"
},
{
"id": 4,
"name": "MoMo"
}
]
}
]
User::get()->groupBy("age") not working expected.
How could add json key age and user like above format in laravel?
The answer gives you the desired output, however consider using an API Resource for JSON Response.
$response = [];
User::get()->groupBy('age')->each(function ($item, $key) use (&$response) {
$temp = [];
$temp['age'] = $key;
$temp['user'] = $item->transform(function ($i, $k) {
unset($i['age']);
return $i;
})->all();
$response[] = $temp;
});
var_dump($response); // Your Output JSON

How to store and retrieve nested JSON array in laravel 6

I am trying to retrieve the data saved as json in mysql. My migration looks like below:
Schema::create('items', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->nullable();
$table->json('add_ons')->nullable();
$table->timestamps();
});
I have tried saving the below JSON from postman and it saved perfectly.
{
"itemName": "chicken",
"addons": {
"required": false,
"min": 2,
"max": 3,
"data": [
{
"name": "sauces",
"type": [
{
"name": "white sauce",
"type": [
{
"name": "whiteOne",
"price": 10
},
{
"name": "whiteTwo",
"price": 20
}
]
},
{
"name": "red sauce",
"price": 10
}
]
}
]
}
}
Now, I trying to retrieve the price of 'whiteOne' under 'white sauce' and getting nothing other than null or laravel error response.
I have tried
Item::whereJsonContains('add_ons->data->name','sauces')->get()
Item::whereJsonContains('add_ons->data->name','sauces')->find(16)
After saving the 'add_ons' column has below data:
{
"required": false,
"min": 2,
"max": 3,
"data": [
{
"name": "sauces",
"type": [
{
"name": "white sauce",
"type": [
{
"name": "whiteOne",
"price": 10
},
{
"name": "whiteTwo",
"price": 20
}
]
},
{
"name": "red sauce",
"price": 10
}
]
}
]
}
Can anyone help me ?
I used this function to get the value of the index.
public function search($array, $key, $value) {
// RecursiveArrayIterator to traverse an
// unknown amount of sub arrays within
// the outer array.
$arrIt = new \RecursiveArrayIterator($array);
// RecursiveIteratorIterator used to iterate
// through recursive iterators
$it = new \RecursiveIteratorIterator($arrIt);
foreach ($it as $sub) {
// Current active sub iterator
$subArray = $it->getSubIterator();
if ($subArray[$key] === $value) {
//$result[] = iterator_to_array($subArray);
$result = iterator_to_array($subArray);
}
}
return $result;
}
Now when I pass the values in the function I get the appropriate values.
$item = Item::where('id','=',16)->first();
$res = $this->search($item->add_ons['data'], 'name', 'whiteTwo');
echo $res["name"]." - ".$res['price'] ."<br>";

Access nested JSON object in AngularJS controller

I am new to AngularJS and trying to create a $scope for tracks for later usage
data.json (sample):
[
{
"album": "Album name",
"tracks": [
{
"id": "1",
"title": "songtitle1",
"lyric": "lyrics1"
},
{
"id": "2",
"title": "songtitle2",
"lyric": "lyrics2"
}
]
}
]
Controller
app.controller('lyricsCtrl', function($scope, $http) {
$http.get('data.json')
.then(function(result) {
$scope.albums = result.data;
$scope.tracks = result.data.tracks;
console.log($scope.tracks); //Undefined...
});
});
Why is $scope.tracks undefined?
If your json file is as is:
[
{
"album": "Album name",
"tracks": [
{
"id": "1",
"title": "songtitle1",
"lyric": "lyrics1"
},
{
"id": "2",
"title": "songtitle2",
"lyric": "lyrics2"
}
]
}
]
We have a response of:
data: Array[1]
0: Object
album: "Album name"
tracks: Array[2]
Since data is returned as an array you would handle like any other javascript array and access by index, so you could do a loop or if you know only 1 result is going to be returned you could use the zero index:
$http.get('data.json').then(function(result) {
console.log(result);
// Assign variables
$scope.album = result.data[0].album;
$scope.tracks = result.data[0].tracks;
for (var i = 0, l = $scope.tracks.length; i < l; i++) {
console.log($scope.tracks[i].title);
}
});
result.data is an array,So you must have to use index to access its child like:-
$scope.tracks = result.data[0].tracks;
It should be result.data[0].tracks as data is an array
$scope.tracks = result.data[0].tracks;

Render Doctrine entities including recursive relations as JSON

I am building a JSON-based REST API using Symfony2.4 with Doctrine2.
EDIT : with JsonNormalizer, I can disabled some attributes, but what if I would like to set them, without recursivity ?
Basically, what I have (working) now is :
{
"tasks": [
{
"id": 1,
"name": "first task"
},
{
"id": 2,
"name": "second task"
}
]
}
What I would like is :
{
"tasks": [
{
"id": 1,
"name": "first task",
"category": {
"id": 1,
"name": "first category"
}
},
{
"id": 2,
"name": "second task",
"category": {
"id": 1,
"name": "first category"
}
}
]
}
What was my initial problem is :
{
"tasks": [
{
"id": 1,
"name": "first task",
"category": {
"id": 1,
"name": "first category",
"tasks": [
{
"id": 1,
"name": "first task",
"category": {
"id": 1,
"name": "first category",
"tasks": [...] // infinite...
}
},
{
"id": 2,
"name": "second task",
"category": {
"id": 1,
"name": "first category",
"tasks": [...] // infinite...
}
}
]
}
},
{
"id": 2,
"name": "second task",
"category": {
"id": 1,
"name": "first category",
"tasks": [
{
"id": 1,
"name": "first task",
"category": {
"id": 1,
"name": "first category",
"tasks": [...]
}
},
{
"id": 2,
"name": "second task",
"category": {
"id": 1,
"name": "first category",
"tasks": [...]
}
}
]
}
}
]
}
I have a entity A with a manyToOne relation to another entity B.
I have implemented the reverse-side, to be able to retrieve the related A entities on the B one.
class Task
{
/**
* #ORM\ManyToOne(targetEntity="List", inversedBy="task")
* #ORM\JoinColumn(name="list_id", referencedColumnName="id")
*/
private $list;
public function toArray($recursive = false)
{
$entityAsArray = get_object_vars($this);
if ($recursive) {
foreach ($entityAsArray as &$var) {
if ((is_object($var)) && (method_exists($var, 'toArray'))) {
$var = $var->toArray($recursive);
}
}
}
return $entityAsArray;
}
}
use Doctrine\Common\Collections\ArrayCollection;
class List
{
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="list")
*/
private $tasks;
public function __construct()
{
$this->tasks = new ArrayCollection();
}
}
Then I am building the different API routes and controllers,
Rendering the output as JsonResponses,
And I would like to render, for a given list, the different tasks using the route :
/api/v1/lists/1/tasks
The task action of my controller :
public function tasksAction($id)
{
$em = $this->getDoctrine()->getManager();
$list = $em->getRepository('MyRestBundle:List')->findOneActive($id);
if (!$list) {
throw $this->createNotFoundException('List undefined');
}
$tasks = $list->getTasks()->toArray();
foreach ($tasks as &$task) {
// recursively format the tasks as array
$task = $task->toArray(true);
}
$serializer = $this->get('serializer');
return $this->generateJsonResponse($serializer->normalize($tasks), 200);
}
But unfortunately, I always get a memory leak, because the call of toArray() is recursive, so each task has a list property which has a tasks collection etc.
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 130968 bytes) in src/Symfony/Component/Serializer/Serializer.php on line 146
I am wondering what would be the cleanest way to render entities with relations as JSON objects with Symfony2 ?
Do I really have to loop on my tasks to execute the "toArray()" method ?
I have also tried without it, without more success, except that the leak in in the file : src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php...
I have also tried without the JMSSeralizer, and the memory leak is thrown in my own php file.
Of course, I could increase the memory limit, but as it is an infinite loop problem of toArray() calls, it will not solve my problem.
How to format it properly ?
I have a feeling that we might be overthinking this. Would that work for you?
// In your controller
$repo = $this->getDoctrine()->getRepository('MyRestBundle:List');
$list = $repo->findActiveOne($id);
$tasks = $list->getTasks()->toArray();
$serializer = $this->get('serializer');
$json = $serializer->serialize($tasks, 'json');
Why is Task Entity recursive? A task can not include another task. Only a List can include an array of Tasks. So basically all we should do is get this array from the List entity and serialize it. Unless I am missing something.
EDIT:
You can ask the serializer to ignore certain attributes as mentioned by the documentation:
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
$normalizer = new GetSetMethodNormalizer();
$normalizer->setIgnoredAttributes(array('age'));
$encoder = new JsonEncoder();
$serializer = new Serializer(array($normalizer), array($encoder));
$serializer->serialize($person, 'json'); // Output: {"name":"foo"}
Try to follow that example and just ignore the $list attribute in the Task entity.
EDIT2:
You don't need 'list' inside each task since it's the same. Your json should have 'list' and 'tasks' at the same level. then 'tasks' would be an array of tasks which will not contain 'list'. to achieve that you can have something like array('list' => $list, 'tasks' => $tasks) and serialize that.
EDIT
If I understand what your code is doing, I think the toArray($recursive) function goes into infinite recursion both directly (whenever $var = $this) and indirectly (i.e. by a sibling iterating through its own list and calling toArray of the original task again). Try keeping track of what's been processed to prevent infinite recursion:
/**
* #ORM\ManyToOne(targetEntity="List", inversedBy="task")
* #ORM\JoinColumn(name="list_id", referencedColumnName="id")
*/
private $list;
private $toArrayProcessed = array();
public function toArray($recursive = false)
{
$this->toArrayProcessed[$this->getId()] = 1;
$entityAsArray = get_object_vars($this);
if ($recursive) {
foreach ($entityAsArray as &$var) {
if ((is_object($var)) && (method_exists($var, 'toArray')) && !isset($this->toArrayProcessed[$var->getId()]) {
$var = $var->toArray($recursive);
}
}
}
return $entityAsArray;
}