get all nodes from multi level hash in perl - html

I want all nodes of each key sorted by key in hash ref or array or something like so that I can iterate that according to my need since I have to display each key with its all children.
following is my data structure:
$hash1 = {
'3' => {
'title' => 'Parent-3',
'parentid' => '-1'
},
'1' => {
'children' => {
'11' => {
'title' => 'child-1',
},
'5' => {
'children' => {
'8' => {
'title' => 'first child of child-2',
},
'13' => {
'title' => 'second child of child-2',
}
},
'title' => 'child-2',
}
},
'title' => 'Parent-1',
'parentid' => '-1'
},
'2' => {
'title' => 'Parent-2',
'parentid' => '-1'
},
'4' => {
'title' => 'Parent-4',
'parentid' => '-1'
},
};
I have used following functions :
sub Options {
my $hash = shift;
my $options = '';
my $iter; $iter = sub {
my $hash = shift;
my $indent = shift || '';
foreach my $k (sort {$a <=> $b} keys %{$hash}) {
my $v = $hash->{$k};
if($v->{parentid} eq '-1'){
$options .= $v->{title} ."-parent\n";
}else{
$options .= $v->{title} . "," ;
}
if ($v->{children}){
$iter->($v->{children}, $indent . "");
}
}
chop($options);
$options .= "\n";
};
$iter->($hash);
return $options;
}
here it returns a string with comma separated but I need some kind of data structure so that I can able to find all children for each key (in the form of hash ref or array) like:
Parent-1 -> [child-1,child-2, first child of child-2, second child of child-2]
Parent-2
Parent-3
Parent-4
any one can help me out? thanks in advance.

If your only goal is to display the hash contents, you should use the Data::Dumper module. It can be used to print data structures of arbitrary complexity with a good format.

You may also find brian d foy's answer on checking key existence useful
The code for with code for walking a data structure and Data::Diver may give you all the help you need.

Related

Is my logic to check data in database efficient?

I use laravel 5.6
I have a json file containing 500 thousand records. I want to create a logic to check whether the id of each record already exists or not in the database. If it doesn't already exist, then there will be a data insert process. If it already exists, there will be a data update process. Before updating the data, it will check whether last_modified_date in json file and database is the same or different. If it's different then it will update
I have made logic. I just want to make sure whether my logic is effective or not
My logic code like this :
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
$last_modified_date = \Carbon\Carbon::parse($value['Last_Modified_Date']);
$data = \DB::table('details')->where('id', '=', $value['Code'])->get();
if ($data->isEmpty()) {
\DB::table('details')->insert(
[
'id' => $value['Code'],
'number' => $value['Number'],
'last_modified_at' => $last_modified_date,
...
]
);
}
else {
\DB::table('details')
->where('id', '=', $value['Code'])
->where('last_modified_at', '<>', $last_modified_date)
->update([
'id' => $value['Code'],
'number' => $value['Number'],
'last_modified_at' => $last_modified_date,
...
]);
}
}
The code is working. But the process seems really long
Do you have another solution that is better?
Update
I find another solution use updateOrCreate
I try like this :
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
Details::updateOrCreate(
[ 'id' => $value['Code'] ],
[ 'number' => $value['Number'], 'last_modified_at' => $last_modified_date, ... ]
);
}
What do you think?
you can not use <> in updateOrCreate
i hope this code could help you:
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
$detail = Details::firstOrCreate(
[ 'id' => $value['Code'] ],
[ 'number' => $value['Number'], 'last_modified_at' => $last_modified_date, ... ]
);
if($detail->last_modified_at != $last_modified_date) {
$detail->update([
'number' => $value['Number'],
'last_modified_at' => $last_modified_date,
...
]);
}
}

Remove HTML code from JSON response

I'm trying to get a response in JSON format, but CakePHP also includes in the response the html code of the page.
The function is this:
public function register() {
if ($this->request->is('get')) {
$dataToSave = array(
'User' => array(
'username' => $this->request->data['User']['username'],
'email' => $this->request->data['User']['email'],
'password' => $this->request->data['User']['password'],
'name' => $this->request->data['User']['name'],
'surname' => $this->request->data['User']['surname'],
'image_url' => "",
),
'Filter' => array(
'Filter' => $this->request->data['Filter']['Filter']
)
);
parent::uploadImageUser();
$this->User->create();
$dataToSave['User']['image_url'] = $this->image_path;
$agent = $this->request->header('User-Agent');
if ($this->User->saveAll($dataToSave)) {
$this->set(compact("response", "success"));
$this->set("_serialize", array("response"));
$this->Session->setFlash(__('The user has been saved'));
if ($agent != "FoodAdvisor client/Android"){
$this->redirect($this->Auth->redirect(array('controller' => 'users', 'action'=>'index')));
}
}
else {
$this->set("response", "error");
$this->set("_serialize", array("response"));
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
else {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect(array('action'=>'index')));
}
}
}
The response I get is this:
How can I remove the html code from my response?
You need to ensure that 'User' index is defined on lines from 27 to 31 and that 'Filter' index is defined on line 35 of your file. Probably, $this->request->data does not contain User and Filter arrays.
Why not this way: $dataToSave = $this->request->data; ?
after if ($this->request->is('get')) line,
try to print the contents of $this->request->data i.e pr($this->request->data). And check if you have 'User' index in the array. The error you got is probably due to missing the 'User' index in the array.

Select in Laravel

I have a stupid little question.
As I already know a select query in Laravel will always return an array of results,
I have this query:
$id = DB::select(
'select id from users where username = ?', array(Session::get('theuser')));
by inserting this id into my table
DB::table('characters')->insert(array(
'id' => $id,
'char_name' => $charname,
'char_dynasty' => $dynastyname,
'picture' => 'Male1.png'
));
I will get the error: ksort() expects parameter 1 to be array, string given.
How can I get rid of this? Thanks in advance!
At least one of $id, $charname or $dynastyname is an array and should not be.
You are using it wrong.
Below is a POC proving this.
The output is "Warning: ksort() expects parameter 1 to be array, integer given on line 13"
It runs as expected when providing 'id' => 'a'.
function insert(array $values)
{
if ( ! is_array(reset($values)))
{
$values = array($values);
}
else
{
foreach ($values as $key => $value)
{
ksort($value); $values[$key] = $value;
}
}
var_dump($values);
}
insert(array(
'id' => array('a'),
'char_name' => 2,
'char_dynasty' => 3,
'picture' => 'Male1.png'
));

Perl dereferencing individual elements in array of hash of hash

I have a structure as below which contains array of hash of hash of hash. I am getting error while dereferencing the values from the hash.
$VAR1 = \{
'2001' => {
'Arunachal Pradesh' => {
'CHANGLANG' => [
{
'wheat' => '2',
'cotton' => '',
'rice' => '1'
}
],
'SUBANSIRI UPPER' => [
{
'wheat' => '',
'cotton' => '1',
'rice' => '2'
}
],
},
'Andhra Pradesh' => {
'CHITTOOR' => [
{
'wheat' => '34',
'cotton' => '14',
'rice' => '27'
}
],
'VIZIANAGARAM' => [
{
'wheat' => '2',
'cotton' => '',
'rice' => '8'
}
],
}
}
};
I am trying to dereferencing individual values such that I can fill these values to a mysql database. But I getting error "Use of uninitialized value $state in concatenation (.) or string" while derefrencing individual value itself. The code is as follows:
while (my ($key, $href) = each(%$stat) ) {
my $state = $stat->{$state_name}; #where the first value is the state name & the second value is the district
print "$state\n";
}
The state name code is as follows:
if ($line =~ m/^State:,(\w+\s\w+),/){
$state_name = $1;
$stat->{$year}->{$state_name} = {};
}
Any other way via which I can get individual values or I need to assign it to another hash and so forth. Thank you.
To step through your structure properly, you need a loop more like this:
while (my ($year, $year_ref) = each(%$stat) )
{
while (my ($state, $state_ref) = each(%$year_ref) )
{
print "year = $year, state = $state\n";
}
}
You can add additional levels of loop below that if you want to iterate through the entire structure to flatten it.
For example, since you have five levels in your structure, and the level just below the last is an array reference:
while (my ($year, $year_ref) = each(%$stat) )
{
while (my ($state, $state_ref) = each(%$year_ref) )
{
while (my ($city, $city_ref) = each(%$state_ref) )
{
foreach my $prod_rec ( #$city_ref )
{
while (my ($prod, $qty) = each(%$prod_rec) )
{
print "year = $year, state = $state, city = $city, prod = $prod, qty = $qty\n";
}
}
}
}
}
(Please forgive me if I guessed wrong naming the level under $state as $city. It is just a guess.)
Learn how to "walk" through the nested hashes/array. Check below code.
#!/usr/bin/perl
use warnings;
use strict;
my $VAR1 = {
'2001' => {
'Arunachal Pradesh' => {
'CHANGLANG' => [
{
'wheat' => '2',
'cotton' => '',
'rice' => '1'
}
],
'SUBANSIRI UPPER' => [
{
'wheat' => '',
'cotton' => '1',
'rice' => '2'
}
],
},
'Andhra Pradesh' => {
'CHITTOOR' => [
{
'wheat' => '34',
'cotton' => '14',
'rice' => '27'
}
],
'VIZIANAGARAM' => [
{
'wheat' => '2',
'cotton' => '',
'rice' => '8'
}
],
}
}
};
foreach my $a (keys %{ $VAR1->{2001} })
{
print $a."\n";
foreach my $b (keys %{ $VAR1->{2001}->{$a} })
{
print "\t".$b."\n";
foreach my $c ( #{ $VAR1->{2001}->{$a}->{$b} })
{
#print $c."\n";
foreach my $d ( keys %{ $c })
{
print "\t\t $d ===> $c->{$d} \n";
}
}
}
}
OutPut:
Arunachal Pradesh
CHANGLANG
rice ===> 1
wheat ===> 2
cotton ===>
SUBANSIRI UPPER
rice ===> 2
wheat ===>
cotton ===> 1
Andhra Pradesh
CHITTOOR
rice ===> 27
wheat ===> 34
cotton ===> 14
VIZIANAGARAM
rice ===> 8
wheat ===> 2
cotton ===>
In above code, I am hitting each and every element of the hash and printing it manually. This way you can capture any element in the hash and then use it later.

Adding comments to columns in codeigniter migrations

I am writing a lot of migration scripts for the database for my application. I would like to add comments for the columns so that others can easily recognize the column's content. One option is to write normal SQL query and add the comment. But is there a way I can add these comments inside the Migration scipt?
$this->dbforge->add_field(array(
'post_id' => array(
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'Unique post id'
),
'user_id' => array(
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
),
'group_id' => array(
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
),
'source' => array(
'type' => 'VARCHAR',
'constraint' => 20
),
'data' => array(
'type' => 'TEXT',
),
'created' => array(
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
),
'updated' => array(
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
),
'status' => array(
'type' => 'INT',
'constraint' => 1,
'unsigned' => true,
)
));
This is the basic code that I have written. May have some syntax error. But I just copy pasted it.
Can anyone please help.
CodeIgniter added this ability with version 3.0. You can add comments using the 'comment' key:
'first_name' => [
'type' => 'VARCHAR',
'constraint' => 45,
'null' => false,
'comment' => 'Put the field comment here',
]
Looking at the CodeIgniter core, specifically system/database/drivers/mysql/mysql_forge.php, it looks like the COMMENT field isn't supported.
For reference, here is the function that parses the fields array out:
function _process_fields($fields)
{
$current_field_count = 0;
$sql = '';
foreach ($fields as $field=>$attributes)
{
// Numeric field names aren't allowed in databases, so if the key is
// numeric, we know it was assigned by PHP and the developer manually
// entered the field information, so we'll simply add it to the list
if (is_numeric($field))
{
$sql .= "\n\t$attributes";
}
else
{
$attributes = array_change_key_case($attributes, CASE_UPPER);
$sql .= "\n\t".$this->db->_protect_identifiers($field);
if (array_key_exists('NAME', $attributes))
{
$sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' ';
}
if (array_key_exists('TYPE', $attributes))
{
$sql .= ' '.$attributes['TYPE'];
if (array_key_exists('CONSTRAINT', $attributes))
{
switch ($attributes['TYPE'])
{
case 'decimal':
case 'float':
case 'numeric':
$sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
break;
case 'enum':
case 'set':
$sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
break;
default:
$sql .= '('.$attributes['CONSTRAINT'].')';
}
}
}
if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
{
$sql .= ' UNSIGNED';
}
if (array_key_exists('DEFAULT', $attributes))
{
$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
}
if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
{
$sql .= ' NULL';
}
else
{
$sql .= ' NOT NULL';
}
if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
{
$sql .= ' AUTO_INCREMENT';
}
}
// don't add a comma on the end of the last field
if (++$current_field_count < count($fields))
{
$sql .= ',';
}
}
return $sql;
}
What you can do is the following in the up method just before the closing tag of it:
$this->db->query("ALTER TABLE `" . $this->db->dbprefix . $this->table_name . "` CHANGE `post_id` `post_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique post id'");
Is there any other way to do it without including the column definition in MySQL? No
Note:
Altering a comment will cause a full resconstruction of the table. So you may choose to live without it on very big table.
The Best solution would be to create, extend or copy the mysql or mysqli and reimplementing the _process_fields to handle the comment of the fields. This link can help get you started and this is the advanced.