Inserting JSON to DB Using Model in Laravel - json

I'm trying to use the model create option and this is my array:
$result = array(
'match_id' => $input['id'],
'score' => $input['score'],
'result' => $input['result'],
'headline' => NULL,
'article' => $input['report'],
'tries' => $input['try'],
'try_amount' => $input['tryquant'],
'conversions' => $input['conv'],
'conv_amount' => $input['convquant'],
'penalties' => $input['pens'],
'pen_amount' => $input['penquant'],
'dropgoals' => $input['dgs'],
'dg_amount' => $input['dgquant']
);
Result::create($result);
The contents of some of these are arrays themselves. eg:
$input['penquant'] = [
"4"
]
When I run my code, it saves the data to the DB simply as Array and throws up the following error:
ErrorException in helpers.php line 703: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array
Can someone tell me what I'm doing wrong and how to fix it?

Shouldn't have rushed, forgot to use json_encode.

The best is to use mutators and accessors in your model.
example of mutator
// convert pen_amount from snake case to studly case
// The set...attribute (the ... is you field name which is in studly case) helps transform the data before you save it
// into the database
public function setPenAmountAttribute($value)
{
$this->attributes['pen_amount'] = serialize($value);
}
example of an accessor is
// convert pen_amount from snake case to studly case
// the get...Attribute (the ... is you field name which is in studly case) helps you convert the data back to it original state
public function getPenAmountAttribute($value)
{
return unserialize($value);
}
You can use accessors and mutators for all your fields that you want to save as array. This is elegant. No need to manually use json_encode and decode in your controllers.

Related

Issues trying to access an associative array converted from JSON in Laravel

I'm working on a Laravel project that implements react-jsonschema-form and I need to convert the values saved in the database to an associative array so I can pluck certain values from it. However I am getting strange results when doing so.
Here is the code I use to grab the JSON data from the table and then convert to an array:
$form = Form::where('id', $formId)->get();
$converted = json_decode($form[0]->form_data, true);
$formArray = print_r($converted, 1);
return $formArray;
For testing purposes I am simply rendering the data in the browser.
The result from the above return is:
Array
(
[1] => Array
(
[1.1] => New
[1.2] => Ms
[1.3] => Isobel Fleming
[1.4] => Array
(
[uprn] => 52375918
[address_1] => Fake Street
[address_2] =>
[address_3] =>
[town_city] => BRISTOL
[postcode] => BS1 3KE
)
[1.5] => 0129711011
[1.6] => 0800999111
[1.7] => 0781100022
[1.8] => isobelfleming#jourrapide.com
)
)
which is great. However when I try and access anything from it like:
return $formData[1][1.1]
I get:
String offset cast occurred
If I try using a string:
return $formData[1]['1.1']
I get:
Illegal string offset '1.1'
So I am not sure what to do to access this data. The problem is, although it's not ideal to have the associate keys with decimals in them, this is the way the schema is set up and it's several thousand lines long - this is just a snippet of the form data.
Is there anything that can be done in order to get the data from this array?
I figured it out. It seems like the following line was the problem:
print_r($converted, 1);
It didn't need to be printed as an array, I should have just used the $converted variable to access the data like so:
return $converted[1]['1.1'];

DBIx to JSON - Wrong format

In a Catalyst application, I need to generate JSON from DBIx::Class:Core objects.
Such a class definition looks like this:
use utf8;
package My::Schema::Book;
use strict;
use warnings;
use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';
__PACKAGE__->load_components("InflateColumn::DateTime");
__PACKAGE__->table("books");
__PACKAGE__->add_columns(
"id",
{
data_type => "uuid",
default_value => \"uuid_generate_v4()",
is_nullable => 0,
size => 16,
},
"title"
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->meta->make_immutable;
sub TO_JSON {
my $self = shift;
{book => {
id => $self->id,
title => $self->title,
}}
}
1;
After queriyng the books from database I do the encoding of the blessed objects:
$c->stash(books_rs => $c->model('My::Schema::Book'));
$c->stash(books => [$c->stash->{books_rs}->search(
{},
{order_by => 'title ASC'})]
);
$c->stash(json => $json->convert_blessed->encode($c->stash->{books}));
$c->forward('View::JSON');
The JSON output of the query is this:
{"json":"[{\"book\":{\"id\":\"ae355346-8e19-46ee-88ee-773ac30938a9\",\"title\":\"TITLE1\"}},{\"book\":{\"id\":\"9a20f526-d4cd-4e7d-a726-55e78bc3c0ac\",\"title\":\"TITLE2\"}},{\"book\":{\"title\":\"TITLE3\",\"id\":\"1ddb2d27-3ec6-46c1-a1a7-0b151fe44597\"}}]"}
The value of the json key and each particular book key got double quotes what can not be parsed by jQuery. It complains about format exception.
$json->convert_blessed->encode($c->stash->{books}) returns a string. It looks like View::JSON also encodes json.
Try to pass your data as is: $c->stash(json => $c->stash->{books});. You may also need to configure expose_stash and json_encoder_args to handle the right keys from your stash and correctly convert your objects.
See
https://metacpan.org/pod/Catalyst::View::JSON#CONFIG-VARIABLES

What is the best means to get the unique hash data into a JSON object without using an array when cycling through a DB Dataset?

I need to get the data into a JSON object but because I'm using the %data hash and it has the same address I'm getting the same data repeatedly in my JSON object.
This is the code that produces the JSON.
while (my ($orderID, $possessorName, $itemDescription, $...) = $sth->fetchrow_array)
{
%data = (orderID => $orderID, possessorName => $possessorName, itemDescription => $itemDescription,...);
$query_results{"job$index"} = {"data" => \%data};
$index++;
}
return $json_obj->pretty->encode(\%query_results, {ascii => 1, pretty => 1});
The problem is that the last item in my data set is masking all the previous items so I end up with one large JSON of the same exact data. I could use an array of hashes I suppose but this seems really messy and sloppy. How do I write the cleanest code to get my data? If an array of hashes is the best way to go please let me know and I'll do it. I all ready know how or can figure it out on my own.
What happens when you try:
my $index = 0;
my %query_results;
while (my ($orderID, $possessorName, $itemDescription, $...) = $sth->fetchrow_array) {
my %data = (orderID => $orderID, possessorName => $possessorName, itemDescription => $itemDescription,...);
$query_results{"job$index"}{'data'} = \%data;
$index++;
}
Previously, you used a %data hash declared in an outside scope; or worse, you didn't use strict; use warnings so %data was in fact an implicit global. Now, we declare the %data inside the loop which makes all the hashes distinct.
You could also copy the hash into a new hashref by {%data}.
That said, you don't even need that variable:
$query_results{"job$index"}{data} = {
# anonymous hashref here
orderID => $orderId,
possessorName => $possessorName,
itemDescription => ...
};

How to do Kohana Validation of $_serialize_column inside ORM

The validation on Kohana ORM is done using rules
function rules()
{
return array(
'username' => array(
array('not_empty'),
array(array($this, 'availability')),
)
);
}
I'm struggling to validate a JSON encoded column using $_serialize_columns.
class Model_Admin extends ORM {
protected $_belongs_to = array();
protected $_has_many = array(
'plans' => array(),
'groups' => array(),
'transactions' => array(),
'logins' => array()
);
protected $_serialize_columns = array('data');
/**
* #param array $data
* #param Validation $validation
*
* #return bool
*/
public function data($data, $validation)
{
return
Validation::factory(json_decode($data, TRUE))
// ... rules ...
->check();
}
public function rules()
{
return array(
'data' => array(
array(array($this, 'data'), array(':value',':validation')
)
);
}
}
the array that gets encoded is:
array(
'name' => '',
'address' => '',
'phone' => '',
'postalcode' => ''
);
the data method receives the json encoded data, because the ORM runs the filters before doing the validation, so I need to convert it back to an associative array, then create a new validation object to check specifically for the content of that array. Because I can't merge Validation rules from another Validation instance
Updated Answer
The use of a second validation object is necessary since save() causes the internal model validation object to be checked. This means that rules added to the validation object being checked from a validation rule will be ignored (Validation->check() imports the rules into local scope before looping).
Since the data itself is technically another object (in the sense of object relationships, it has its own dataset that needs validation) the ideal solution would be to find a way to create a real model that saves the data.
There are numerous other benefits to saving data with proper database column definitions, not least if you need to perform data property lookups, make in-situ changes etc. (which would otherwise require unserializing the data column, potetnailly in all rows).
There are some alternatives, but they feel like kludges to me:
Create a model that represents the data object and add rules to it, using check() to validate the data (problem: will require a lot of maintenance, no real-world table means columns must be manually defined).
Set the data as real columns in the Admin model, and use a filter that will convert it into the data column on set (problem: again, must manually define the columns and exclude the additional columns from the save operation).
I hope this is of some use.
Original Answer
The Kohana ORM save() method permits the inclusion of an "extra" validation object, which is merged into the main ORM validation object namespace.
This is documented briefly here.
If I have understood correctly, I think you are looking to do something like this:
// another script, e.g., a controller
// Create the model
$admin = ORM::factory('Admin');
// $data = the data as an array, before serialization ...
$extra_validation = Validation::factory($data)
// add ->rule() calls here, but DO NOT chain ->check()
;
// Set $data in the model if it is going to be saved, e.g., $admin->data = $data;
// Set other data... e.g., $admin->foo = 'bar';
// Save the model
try {
$admin->save($extra_validation);
}
catch (ORM_Validation_Exception $e)
{
// Manipulate the exception result
}
While in this example you must still create another validation object, you are now able to catch all exceptions in a single block. I would recommend using var_dump() or similar on $e->errors() to check the namespace if you are using i18n messages to provide a human-readable error message. You should find that a namespace called "_external" has been created in the response.

Extract data from array in DB (rails)

I am trying to extract some data from an array with the following syntax:
#entries_from_db = XrEntry.find(:all, :conditions => [:FeedURI => uri ], :select => 'json')
The :FeedURI is the record that contains an array with uri's ["123456", "23345", "4453"]
The uri is the variable wich contains the current uri.
The statement I'm trying to make is 'select JSON from XrEntry where FeedURI contains uri'
Im stuck on the part to access the array and always get several error msg's when I'm trying different code.
Does anyone has an idea?
Thanks!
I solved it with this syntax
#entries_from_db = XrEntry.find(:all, :conditions => ["FeedURI like ?", "%#{uri}%"] , :select => 'json')
the "%#{your_rails_variable}%" is needed to read in an array
You seem to have switched the condition syntax. you chould start with the db attribute and then the variable.
#entries_from_db = XrEntry.find(:all,
:conditions => { :uri => FeedURI },
:select => 'json')
That will return an array of XrEntry objects with only the json attribute present. To get an array of only the json data you could map it like this:
#json_array = #entries_from_db.map(&:json)