Yeah thanks. but still weird why my casts is not converting to xml. any idea?
Casting not working please help!
i'am saving json to my database. and i wrote a code to coverting the table to xml. it dosn't covert the casts table to xml why?
here is my show here i convert the json to xml
public function show(Configuration $configuration)
{
$data = Configuration::query()
->withCasts(['config' => 'json'])
->get()
->mapWithKeys(function ($configuration) {
// to wrap each config object: <config>...</config>
return ['config' => $configuration];
});
$result = ArrayToXml::convert(
$data->jsonSerialize(), // convert collection to array
'root', // root element name
true, // replace spaces by underscore in element's names
'UTF-8' // encoding
);
return response()->make($result, 200, ['Content-Type' => 'text/xml']);
}
here is my. model
protected $casts = [
// if its name was different you could use:
// 'another_column' => 'json',
'config' => 'json',
];
here is the output
<root>
<config>
<id>1</id>
<mac_address>1000</mac_address>
<config>{ "config": { "version": 2.1, "general": { "test": "testdata", "testl": [ "test" ], "flood": } } }
</config>
<created_at>2020-11-05T09:44:38.000000Z</created_at>
<updated_at>2020-11-05T09:44:38.000000Z</updated_at>
</config>
</root>
here is my store controller
public function store(Request $request)
{
$configuration = new Configuration();
$configuration->config = $request->config;
$configuration->mac_address = $request->mac_address;
$configurationSaved = $configuration->save();
if ($configurationSaved) {
$response = ApiHelpers::apiResponse(false, 200, 'record saved successfully', null);
return response()->json($response, 200);
} else {
$response = ApiHelpers::apiResponse(true, 400, 'record saving failed', null);
return response()->json($response, 400);
}
}
@laradoel what are you trying do? convert the inners of:
<config>{ "config": { "version": 2.1, "general": { "test": "testdata", "testl": [ "test" ], "flood": } } }
</config>
to xml too?
yes. i want all the array attribute to xml so
<version>2.1<version>
<test> teststdata<test>
etc , this should work with casting i thought
@laradoel but in your $casts you are telling Laravel to use json?
BTW I think you want to have a look at the xml you are producing. Currently you have a config which has a nested config.
You would be better to change the outer wrapper so you get:
<root>
<configuration>
<id>1</id>
<mac_address>1000</mac_address>
<config>
<version>2.1</version>
<test> teststdata</test>
</config>
<created_at>2020-11-05T09:44:38.000000Z</created_at>
<updated_at>2020-11-05T09:44:38.000000Z</updated_at>
</configuration>
</root>
Ok thanks, but it doesn't matter if i change the cast to array stil the same output
protected $casts = [
// if its name was different you could use:
// 'another_column' => 'json',
'config' => 'array',
];
<root>
<configuration>
<id>1</id>
<mac_address>40099</mac_address>
<config>{
"config": {
"version": 2.1,
"general": {
"test": "true",
}</config>
<created_at>2020-11-05T13:09:47.000000Z</created_at>
<updated_at>2020-11-05T13:09:47.000000Z</updated_at>
</configuration>
</root>
config is the table in the database saved as json
$table->json('config');
$table->string('mac_address');
@laradoel you are fine to keep storing the config as json. you only need it as xml when you render the configuration. We can work that bit out next.
@laradoel BTW can you manually edit below and get the xml to exactly how you want it and then we'll look at how to convert the json to match that.
<root>
<configuration>
<id>1</id>
<mac_address>1000</mac_address>
<config>
<version>2.1</version>
<test> teststdata</test>
// need to add extra bits here
</config>
<created_at>2020-11-05T09:44:38.000000Z</created_at>
<updated_at>2020-11-05T09:44:38.000000Z</updated_at>
</configuration>
</root>
Thankyou for you respond!
so here is a better example. here is what i save in the database doing a dd($data)
Illuminate\Database\Eloquent\Collection {#1212 ▼
#items: array:1 [▼
"config" => App\Models\Configuration {#1230 ▼
#fillable: array:2 [▶]
#casts: array:1 [▼
"json" => "json"
]
#connection: "mysql"
#table: "configurations"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:5 [▼
"id" => 1
"mac_address" => "10000"
"json" => ""{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse
kicking
asses since 1940\",\n \"password\": \"noneed\"\n} ▶"
"created_at" => "2020-11-06 09:25:40"
"updated_at" => "2020-11-06 09:25:40"
]
Here is the xml output now.
<root>
<config>
<id>1</id>
<mac_address>10000</mac_address>
<json>{ "firstName": "Chuck", "lastName": "Norris", "age": 75, "bio": "Roundhouse kicking asses since
1940",
"password": "noneed" }</json>
<created_at>2020-11-06T09:25:40.000000Z</created_at>
<updated_at>2020-11-06T09:25:40.000000Z</updated_at>
</config>
</root>
This how i actually want the xml to look like
<configuration>
<id>1</id>
<mac_address>10000</mac_address>
<config>
<firstname>Chuck</firstname>
<lastname>Chuck</lastname>
<age>75</age>
<bio>Roundhouse kicking asses since
1940</bio>
<password>noneed</password>
</config>
<created_at>2020-11-06T09:25:40.000000Z</created_at>
<updated_at>2020-11-06T09:25:40.000000Z</updated_at>
</configuration>
So with json i save ( $table->json('json'); ). i want the input data separated elements in de xml. in my model i use
protected $casts = [ 'json' => 'json', ];
Here is my show controller converting it to xml.
public function show(Configuration $configuration)
{
$data = Configuration::query()
->withCasts(['json' => 'json'])
->get()
->mapWithKeys(function ($configuration) {
// replace config with the element you want
// to wrap each config object: <config>...</config>
return ['config' => $configuration];
});
$result = ArrayToXml::convert(
$data->jsonSerialize(), // convert collection to array
'root', // root element name
true, // replace spaces by underscore in element's names
'UTF-8' // encoding
);
return response()->make($result, 200, ['Content-Type' => 'text/xml']);
}
@laradoel ok. so if you adjust to this:
public function show(Configuration $configuration)
{
$data = Configuration::query()
->withCasts(['json' => 'array'])
->get()
->mapWithKeys(function ($configuration) {
// replace config with the element you want
// to wrap each config object: <config>...</config>
return ['configuration' => $configuration];
});
dd($data);
$result = ArrayToXml::convert(
$data->jsonSerialize(), // convert collection to array
'root', // root element name
true, // replace spaces by underscore in element's names
'UTF-8' // encoding
);
return response()->make($result, 200, ['Content-Type' => 'text/xml']);
}
show me what is returned by dd();
NB I changed this to be array
->withCasts(['json' => 'array'])
also, I think it would wise to rename the column to desctribe whats in it, eg 'settings' or 'data' rather than naming it based on the type of content eg 'json'.
Here is a dd($result)
<root>
<configuration>
<id>1</id>
<mac_address>10000</mac_address>
<json>{
"firstName": "Chuck",
"lastName": "Norris",
"age": 75,
"bio": "Roundhouse kicking asses since 1940",
"password": "noneed"
}
</json>
<created_at>2020-11-06T09:25:40.000000Z</created_at>
<updated_at>2020-11-06T09:25:40.000000Z</updated_at>
</configuration>
</root>
So the edited configuration element worked fine! but 'json' is still in array instead of xml and also how to get rid of the root element?
@laradoel I want dd($data) not dd($result). See my updated answer above.
Okay, thanks,
I have renamed the column 'data' and changed ->withCasts(['data' => 'array'])
Here is de dd($data)
#items: array:1 [▼
"configuration" => App\Models\Configuration {#1230 ▼
#fillable: array:2 [▶]
#casts: array:1 [▼
"data" => "array"
]
#connection: "mysql"
#table: "configurations"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:5 [▼
"id" => 1
"mac_address" => "10000"
"data" => ""{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse
kicking asses since 1940\",\n \"password\": \"noneed\"\n} ▶"
"created_at" => "2020-11-06 10:41:18"
"updated_at" => "2020-11-06 10:41:18"
]
#original: array:5 [▼
"id" => 1
"mac_address" => "10000"
"data" => ""{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse
kicking asses since 1940\",\n \"password\": \"noneed\"\n} ▶"
"created_at" => "2020-11-06 10:41:18"
"updated_at" => "2020-11-06 10:41:18"
]
@laradoel ok in your model can you add or update
$casts = ['data' => 'array'];
and show dd(data) again?
Sure after updating the casts in model to 'data' => 'array',
Illuminate\Database\Eloquent\Collection {#1212 ▼
#items: array:1 [▼
"configuration" => App\Models\Configuration {#1230 ▼
#fillable: array:2 [▼
0 => "data"
1 => "mac_address"
]
#casts: array:1 [▼
"data" => "array"
]
#connection: "mysql"
#table: "configurations"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:5 [▼
"id" => 1
"mac_address" => "10000"
"data" => ""{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse kicking asses since 1940\",\n \"password\": \"noneed\"\n} ▶"
"created_at" => "2020-11-06 10:41:18"
"updated_at" => "2020-11-06 10:41:18"
]
#original: array:5 [▼
"id" => 1
"mac_address" => "10000"
"data" => ""{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse kicking asses since 1940\",\n \"password\": \"noneed\"\n} ▶"
"created_at" => "2020-11-06 10:41:18"
"updated_at" => "2020-11-06 10:41:18"
]
@laradoel ah. I think you also need to adjust your migration to switch 'data' column to json.
$table->json('data')->nullable();
Ok already had $table->json('data')->nullable();
But i just discoverd something weird.
i use postman for the post request.
<data>{
"firstName": "Chuck",
"lastName": "Norris",
"age": 75,
"bio": "Roundhouse kicking asses since 1940",
"password": "noneed"
}
</data>
But i just tried manually inserting the data in the database just with the same array. and it worked!
<root>
<configuration>
<id>2</id>
<mac_address>20000</mac_address>
<data>
<age>75</age>
<bio>Roundhouse kicking asses since 1940</bio>
<lastName>Norris</lastName>
<password>noneed</password>
<firstName>Chuck</firstName>
</data>
so i think maybe something is wrong with my store function here it is. in postman i just use post request with key and the value for the formdata
public function store(Request $request)
{
$configuration = new Configuration();
$configuration->data= $request->data;
$configuration->mac_address = $request->mac_address;
$configurationSaved = $configuration->save();
if ($configurationSaved) {
$response = ApiHelpers::apiResponse(false, 201, 'record saved successfully', null);
return response()->json($response, 201);
} else {
$response = ApiHelpers::apiResponse(true, 400, 'record saving failed', null);
return response()->json($response, 400);
}
}
@laradoel can you export the request you are sending from postman so I can see if its a postman issue or with your store?
do you mean this?
{
"info": {
"_postman_id": "7944364a-119b-4351-91a3-e8921fe4eae1",
"name": "config",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "http://127.0.0.1:8000/api/configurations",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "mac_address",
"value": "10000",
"type": "text"
},
{
"key": "data",
"value": "{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse kicking asses since 1940\",\n \"password\": \"noneed\"\n}",
"type": "text"
}
]
},
"url": {
"raw": "http://127.0.0.1:8000/api/configurations",
"protocol": "http",
"host": [
"127",
"0",
"0",
"1"
],
"port": "8000",
"path": [
"api",
"configurations"
]
},
"description": "posting new configration"
},
"response": []
},
{
"name": "http://127.0.0.1:8000/api/configurations",
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"auth": {
"type": "apikey"
},
"method": "GET",
"header": [],
"body": {
"mode": "urlencoded",
"urlencoded": []
},
"url": {
"raw": "http://127.0.0.1:8000/api/configurations",
"protocol": "http",
"host": [
"127",
"0",
"0",
"1"
],
"port": "8000",
"path": [
"api",
"configurations"
]
},
"description": "get all configurations"
},
"response": []
}
],
"variable": [
{
"id": "baseUrl",
"key": "baseUrl",
"value": "http://localhost:3000",
"type": "string"
}
],
"protocolProfileBehavior": {}
}
@automica this is for only the post request
{
"info": {
"_postman_id": "7944364a-119b-4351-91a3-e8921fe4eae1",
"name": "config",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "http://127.0.0.1:8000/api/configurations",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "mac_address",
"value": "10000",
"type": "text"
},
{
"key": "data",
"value": "{\n \"firstName\": \"Chuck\",\n \"lastName\": \"Norris\",\n \"age\": 75,\n \"bio\": \"Roundhouse kicking asses since 1940\",\n \"password\": \"noneed\"\n}",
"type": "text"
}
]
},
"url": {
"raw": "http://127.0.0.1:8000/api/configurations",
"protocol": "http",
"host": [
"127",
"0",
"0",
"1"
],
"port": "8000",
"path": [
"api",
"configurations"
]
},
"description": "posting new configration"
},
"response": []
}
],
"variable": [
{
"id": "baseUrl",
"key": "baseUrl",
"value": "http://localhost:3000",
"type": "string"
}
],
"protocolProfileBehavior": {}
}
@laradoel looks like you just need to tweak your data
$configuration->data = json_decode($request->data);
Finally!!!!!! THANKYOU SO much! is it possible to get rid of the root element or just keep it?
<root>
< configuration>
<id>2</id>
<mac_address>200000</mac_address>
<data>
<age>75</age>
<bio>Roundhouse kicking asses since 1940</bio>
<lastName>Norris</lastName>
<password>noneed</password>
<firstName>Chuck</firstName>
</data>
<created_at>2020-11-06T12:12:29.000000Z</created_at>
<updated_at>2020-11-06T12:12:29.000000Z</updated_at>
</configuration>
</root>
@laradoel you do need a root element but it doesn't need to be root. Removing the mapWithKeys and renaming root to 'configuration' should do it.
public function show(Configuration $configuration)
{
$data = Configuration::query()
->withCasts(['json' => 'array'])
->get()
->mapWithKeys(function ($configuration) {
return ['configuration' => $configuration];
});
$result = ArrayToXml::convert(
$data->jsonSerialize(), // convert collection to array
'configuration', // root element name
true, // replace spaces by underscore in element's names
'UTF-8' // encoding
);
return response()->make($result, 200, ['Content-Type' => 'text/xml']);
}
Thanks!
I think i need the mapping because i recieved back the error DOMException Invalid Character Error
from the array to xml package
if ($this->isArrayAllKeySequential($array) && ! empty($array)) {
throw new DOMException('Invalid Character Error');
}
highlighting below in the show function
'UTF-8' // encoding
);
@laradoel ah. ok. I updated my comment above.
Ok thanks, almost there!! recieve this back
<configuration>
<incrementing>1</incrementing>
<exists>1</exists>
<wasRecentlyCreated/>
<timestamps>1</timestamps>
</configuration>
@laradoel I guess we're back to having
->mapWithKeys(function ($configuration) {
// replace config with the element you want
// to wrap each config object: <config>...</config>
return ['configuration' => $configuration];
});
BTW as withCasts didn't seem to do anything, do you get an object if you do:
$data = Configuration::query() ->get();
but then we've already got the object, so can we reduce your method down to:
public function show(Configuration $configuration)
{
$result = ArrayToXml::convert(
$configuration->jsonSerialize(), // convert collection to array
'configuration', // root element name
true, // replace spaces by underscore in element's names
'UTF-8' // encoding
);
return response()->make($result, 200, ['Content-Type' => 'text/xml']);
worked! Yes thats it! Thakyou very much for helpen me. have a good day!
@laradoel good stuff. took a bit of time to work this out glad we got there.
Yes! I learned a lot!
Hello, i have a new probleme. esay but can't figure it out. i use pluck but i got this error. Invalid Character Error
i want to convert json to xml but only the table 'data' iam saving json in 'data' table. but i only want the the 'data' to convert to xml
public function show(Configuration $configuration)
{
$result = ArrayToXml::convert(
$configuration::all()->pluck('data')->jsonSerialize(), // convert collection to array
'config', // root element name
true, // replace spaces by underscore in element's names
'UTF-8' // encoding
);
return response()->make($result, 200, ['Content-Type' => 'text/xml']);
}
Here is my model
class Configuration extends Model
{
use HasFactory;
protected $fillable = [
'data'
];
public $timestamps = false;
protected $casts = [
'data' => 'array',
];
public function getLinkAttribute()
{
return '/api/configurations/' . $this->id;
}
}
Here is my migration
public function up()
{
Schema::create('configurations', function (Blueprint $table) {
$table->id();
$table->json('data')->nullable();
});
}
Please or to participate in this conversation.