perl catalyst relationship has_many - mysql

working code is
sub category :Local {
my ( $self, $c, $path ) = #_;
my #cat_obj = $c->model('SQL::LasercalibrationCategory')->search({ category_id => $path } );
my #nav; my $loop = 0; foreach my $r (#cat_obj) {$nav[$loop] = $r->id; $loop++;}
my $result = $c->model("SQL::Lasercalibration")->search({ id => {-in => [#nav]} }, { rows => 10 });
my $page = $c->request->param('page') || 1;
$page = 1 if ($page !~ /^\d+$/);
my $rresult = $result->page($page);
return $c->forward('default') if $rresult == 0;
$c->stash->{items} = [ $rresult->all ];
$c->stash->{page} = $page;
$c->stash->{pager} = $rresult->pager;
$c->stash->{template} = 'index.tt';
}
Here is database st on mysql, table is lasercalibration and lasercalibration_category.
lasercalibration_category contains all id from table lasercalibration and row category_id wich is contains category relation.
for example on Catalyst when click on http://lasercalibration/category/2
it collect first in array #cat_obj catagory relation. for example category/2 relation is id 9735 18388 18946 19203 etc. and then parse all that ids from my $result = $c->model("SQL::Lasercalibration")->search({ id => {-in => [#nav]} }, { rows => 10 });
How may i make it through has_many or has_many_to_many dbxi relationship?
Schema:
Lasercalibration.pm
package lasercalibration::Schema::Lasercalibration;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("Core");
__PACKAGE__->table("lasercalibration");
__PACKAGE__->add_columns(
"id",
{ data_type => "INT", default_value => undef, is_nullable => 0, size => 10 },
"price",
{ data_type => "FLOAT", default_value => undef, is_nullable => 0, size => 32 },
"title",
{
data_type => "VARCHAR",
default_value => undef,
is_nullable => 0,
size => 255,
},
"description",
{
data_type => "TEXT",
default_value => undef,
is_nullable => 0,
size => 65535,
},
"autoinc",
{ data_type => "INT", default_value => undef, is_nullable => 0, size => 11 },
);
__PACKAGE__->set_primary_key("id");
# Created by DBIx::Class::Schema::Loader v0.04006 # 2015-02-10 05:55:18
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:uyxHW0E8P7HwFd4a0Zf0lw
# You can replace this text with custom content, and it will be preserved on regeneration
1;
LasercalibrationCategory.pm
package lasercalibration::Schema::LasercalibrationCategory;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("Core");
__PACKAGE__->table("lasercalibration_category");
__PACKAGE__->add_columns(
"id",
{ data_type => "INT", default_value => undef, is_nullable => 0, size => 10 },
"category_id",
{ data_type => "INT", default_value => undef, is_nullable => 0, size => 11 },
);
__PACKAGE__->set_primary_key("id");
# Created by DBIx::Class::Schema::Loader v0.04006 # 2015-02-10 05:55:18
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:QFvxaRhTcV7FX13vV4lq7w
# You can replace this text with custom content, and it will be preserved on regeneration
1;

Related

Looping Array of Json to Database Laravel?

I have Json Data like this :
$data = '[
{
"OrderId": "1038806370",
"qtty": "1",
"Item": "Strawberry 250 gr",
"SKU": "20091"
},
{
"OrderId": "1038806370",
"qtty": "2",
"Item": "Strawberry 130 gr",
"SKU": "20092"
},
{
"OrderId": "1038806370",
"qtty": "1",
"Item": "Strawberry 130 gr",
"SKU": "20092"
}
]';
and I want to Save in my database MySql using PHP Laravel,...
I Want To save data from json to my table, there are table Order values [orderID,...] and OrderDetail values [orderID, SKU, Qty]
This is my code in controller
$order = json_decode($data, true);
foreach ($order as $ord) {
$check = Order::where('orderid', $ord['OrderId'])->get();
if (count($data) > 0) {
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
} else {
Order::create([
'orderid'=> $ord['OrderId'],
]);
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
}
}
but i dont get what i want, I get QTY of SKU 20091 is 2 but actual json data is 3
I'm not sure why you're counting the $data instead of $check variable. You don't really need the $check variable either though. I'll rewrite your code below.
$order = json_decode($data, true);
foreach ($order as $ord) {
// use EXIST query to check if Order exists or not.
if (Order::where('orderid', $ord['OrderId'])->exists())
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
} else {
Order::create([
'orderid'=> $ord['OrderId'],
]);
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
}
}
But your if/else could also be removed by using the firstOrCreate() method.
$orders = json_decode($data, true);
foreach ($orders as $order) {
// Get Order Model with orderid = $order['OrderId'] or create it if it doesn't exist
$model = Order::firstOrCreate([
'orderid'=> $order['OrderId']
]);
// Get OrderDetail with provided SKU, qtty and orderid or create it if it doesn't exist.
OrderDetail::firstOrCreate([
'order_id' => $model->orderid
'sku_id' => $order['SKU'],
'qty' => $order['qtty']
]);
}
You could also do it inline.
$orders = json_decode($data, true);
foreach ($orders as $order) {
OrderDetail::firstOrCreate([
'order_id' => Order::firstOrCreate(['orderid'=> $order['OrderId']])->orderid,
'sku_id' => $order['SKU'],
'qty' => $order['qtty'],
]);
}

cakephp query find_in_set on single column with multiple searched keywords not working

I want to find all the records from column who have any keyword match with column data:
It works fine if searching single search keyword in column having comma separated values like below code: Cakephp 3.4 version
$posts = TableRegistry::get('Posts');
$search_keywords = array_filter(explode(' ', $search_string));
$option = [
'contain' => false,
'conditions' => [
"find_in_set('New', Posts.title)",
],
'order' => ['Posts.created DESC']
];
$allpost = $posts->find('all',$option)->toArray();
Note: i want all the words from string should be search with column title, its not mandatory to have comma separated records:
$search_keyword = "New car in new delhi";
so i want code to be like below :
$search_keyword = "New car in new delhi";
$search_keywords = array_filter(explode(' ', $search_string));
$option = [
'contain' => false,
'conditions' => [
"find_in_set({$search_keywords}, `Posts`.title)",
],
'order' => ['Posts.created DESC']
];
$allpost = $posts->find('all',$option)->toArray();
Great Thanks in advance!!!
I found the solution:
First make column fulltext index then add below code:
$search_string = "New car in new delhi";
$option = [
'contain' => false,
'conditions' => [
"MATCH (title) AGAINST ('$search_string')"
],
'order' => ['Posts.created DESC']
];
$allpost = $posts->find('all',$option)->toArray();

Laravel - Eloquent overwriting a custom timestamp... WHY?

I am making an inventory management system.
When a product is out of stock, I make an entry in a table and note the "oos_at" field with the date/time.
later, when it is back in stock, i find that entry and update the "restocked_at" timestamp field.
However, when I do the second action, my "oos_at" field is overwritten with the timestamp of the query ('updated_at') field...
I had to keep track of this "oos_at" field on another entity so it wouldn't get overwritten and then use that field to update the "oos_at" field a second time when updating that table...
Below is my code....
class Pusher extends Model {
/**
*
*
* #param Carbon $oos_at
* #return bool
*/
public function setAsOutOfStock(Carbon $oos_at)
{
Log::info([
'FILE' => get_class($this),
'method' => 'setAsOutOfStock',
'pusher' => $this->id,
'param:oos_at' => $oos_at->toDateTimeString(),
]);
$this->pusherOutOfStocks()->create([
'location_id' => $this->location_id,
'product_id' => $this->product_id,
'oos_at' => $oos_at->toDateTimeString(),
]);
$this->oos = true;
$this->oos_at = $oos_at;
return $this->save();
}
/**
* Clear the PusherOutOfStocks attached to $this Pusher
* (This Pusher has been restocked!)
*
* #param Carbon $time
* #return bool
*/
public function setAsInStock(Carbon $time)
{
Log::info([
'FILE' => get_class($this),
'method' => 'setAsInStock',
'pusher' => $this->id,
'param:time' => $time->toDateTimeString(),
]);
$this->pusherOutOfStocks()->where('restocked_at', null)
->update(['restocked_at' => $time->toDateTimeString()]);
$this->oos = false;
$this->oos_at = null;
return $this->save();
}
}
When I die and dump the PusherOutOfStocks BEFORE the pusher is restocked, then the "oos_at" is set appropriately.
Illuminate\Database\Eloquent\Collection {#340
#items: array:1 [
0 => Newave\Engineering\PusherOutOfStock {#343
#fillable: array:5 [
0 => "pusher_id"
1 => "location_id"
2 => "product_id"
3 => "oos_at"
4 => "restocked_at"
]
#dates: array:2 [
0 => "oos_at"
1 => "restocked_at"
]
#connection: null
#table: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:9 [
"id" => 246
"pusher_id" => 216
"location_id" => 634
"product_id" => 378
"oos_at" => "2016-03-11 03:00:00"
"restocked_at" => null
"created_at" => "2016-03-11 12:12:01"
"updated_at" => "2016-03-11 12:12:01"
"deleted_at" => null
]
#original: array:9 [
"id" => 246
"pusher_id" => 216
"location_id" => 634
"product_id" => 378
"oos_at" => "2016-03-11 03:00:00"
"restocked_at" => null
"created_at" => "2016-03-11 12:12:01"
"updated_at" => "2016-03-11 12:12:01"
"deleted_at" => null
]
#relations: []
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [
0 => "*"
]
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
#forceDeleting: false
}
]
}
When I die and dump the PusherOutOfStocks AFTER the pusher is restocked, then the "oos_at" is the same as "updated_at"
Illuminate\Database\Eloquent\Collection {#408
#items: array:1 [
0 => Newave\Engineering\PusherOutOfStock {#775
#fillable: array:5 [
0 => "pusher_id"
1 => "location_id"
2 => "product_id"
3 => "oos_at"
4 => "restocked_at"
]
#dates: array:2 [
0 => "oos_at"
1 => "restocked_at"
]
#connection: null
#table: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:9 [
"id" => 244
"pusher_id" => 214
"location_id" => 626
"product_id" => 374
"oos_at" => "2016-03-11 12:10:23"
"restocked_at" => "2016-03-11 04:00:00"
"created_at" => "2016-03-11 12:10:22"
"updated_at" => "2016-03-11 12:10:23"
"deleted_at" => null
]
#original: array:9 [
"id" => 244
"pusher_id" => 214
"location_id" => 626
"product_id" => 374
"oos_at" => "2016-03-11 12:10:23"
"restocked_at" => "2016-03-11 04:00:00"
"created_at" => "2016-03-11 12:10:22"
"updated_at" => "2016-03-11 12:10:23"
"deleted_at" => null
]
#relations: []
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [
0 => "*"
]
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
#forceDeleting: false
}
]
}
I have even used DB::getQueryLog() and saw NOWHERE that 'oos_at' was being explicitly set/updated....
Nowhere else in my code is this table modified...
Does anyone understand what is happening here????
Thank you!!
=============
Extra Code Snippets
Table Migration::
Schema::create('pusher_out_of_stocks', function (Blueprint $table) {
$table->increments('id');
$table->integer('pusher_id');
$table->integer('location_id');
$table->integer('product_id');
$table->timestamp('oos_at');
$table->timestamp('restocked_at')->nullable();
$table->timestamps();
$table->softDeletes();
});
PusherOutOfStock Class
class PusherOutOfStock extends Model
{
use SoftDeletes;
protected $fillable = [
'pusher_id',
'location_id',
'product_id',
'oos_at',
'restocked_at',
];
protected $dates = [
'oos_at',
'restocked_at'
];
/**
* A PusherOutOfStock belongsTo a Product
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function product()
{
return $this->belongsTo(Product::class);
}
/**
* A PusherOutOfStock belongsTo a Pusher
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function pusher()
{
return $this->belongsTo(Pusher::class);
}
/**
* A PusherOutOfStock belongsTo a Location
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function location()
{
return $this->belongsTo(Location::class);
}
}
Below is the sequence the code goes through to hit that update method
First, it hits my InventoryController in my API namespace
public function upload(Request $request)
{
$data = $request->all();
$header = $this->getHeader($data);
$body = $this->getBody($data);
$reader = $this->getReaderFromHeader($header);
if ( ! $this->guardAgainstNoReader($reader))
return (new Response("Reader with mac-address: ". $header['reader_mac'] . " does not exist.", 409));
$result = $this->inventoryRepository->uploadPusherData($reader, $header, $body);
return $result;
}
Then it sends the request to the InventoryRepository
public function uploadPusherData(Reader $reader, $header, $body)
{
foreach ($body as $pusherData)
{
$result[] = $this->processPusherData($pusher, $header['timestamp'], $pusherData);
}
return $result;
}
Then, inside the repository, it processes one line at a time (in my test, there is only one line)
private function processPusherData(Pusher $pusher, $timestamp, $pusherData)
{
$latestInventory = $pusher->latestInventory;
if (! $latestInventory)
return $this->updatePusher($pusher, $timestamp, $pusherData);
if ($latestInventory->tags_blocked == $pusherData['data_TAGSBLKED'])
return $this->noChangeRecorded($pusher, $latestInventory, $timestamp);
return $this->updatePusher($pusher, $timestamp, $pusherData);
}
Then the pusher is updated...
public function updatePusher($pusher, $timestamp, $pusherData)
{
// See if there are any existing already
$prevInv = $pusher->latestInventory;
// Create the new data
$inventory = Inventory::create([
'pusher_id' => $pusher->id,
'product_id' => $pusher->product_id,
'reader_id' => $pusher->reader->id,
'tags_blocked' => $pusherData['data_TAGSBLKED'],
'paddle_exposed'=> $pusherData['paddle_exposed'],
'created_at' => Carbon::createFromTimestamp($timestamp)
->toDateTimeString(),
]);
if ( !$prevInv || $prevInv->id == $inventory->id )
{
return "first-data" . $timestamp;
}
return $this->checkForEvents($inventory, $prevInv);
}
We check if any events should be triggered... In this case, previous inventory had 9 items in stock... now there are 0.
private function checkForEvents(Inventory $currentInventory, Inventory $previousInventory)
{
if ( ! $previousInventory->oos && $currentInventory->oos && $previousInventory->pusher->oos_notified == 0)
{
$currentInventory->pusher->oos_notified = true;
$currentInventory->pusher->save();
return Event::fire(new InventoryOutOfStock($currentInventory));
}
if ( ( $previousInventory->oos || $previousInventory->status == "RESTOCK" )
&& $currentInventory->tags_blocked > 2 )
{
return Event::fire(new PusherWasRestocked($currentInventory));
}
if ( $currentInventory->status == "RESTOCK" && $previousInventory->pusher->low_stock_notified == 0)
{
$currentInventory->pusher->low_stock_notified = true;
$currentInventory->pusher->save();
return Event::fire(new LowStockAlert($currentInventory));
}
return "no-events";
}
This then fires the event InventoryOutOfStock
That triggers 3 events... 2 are related to notifications being sent etc..
'App\Events\InventoryOutOfStock' => [
'App\Listeners\InventoryOutOfStockUpdater',
'App\Listeners\EmailInventoryOutOfStockNotification',
'App\Listeners\SMSInventoryOutOfStockNotification',
// 'App\Listeners\OutOfStocksUpdater',
],
Which leads us to ...
public function handle(InventoryOutOfStock $event)
{
$pusher = $event->pusher;
$inventory = $event->inventory;
$product = $pusher->product;
$oos = $pusher->setAsOutOfStock($inventory->created_at);
$locationPushers = $product->getPushersByLocation($pusher->location);
$isInStock = false;
foreach ($locationPushers as $pusher)
if ($pusher->oos == 0)
$isInStock = true;
if (! $isInStock)
$product->productOutOfStocks()->create([
'location_id' => $pusher->location_id,
'oos_at' => $event->inventory->created_at,
]);
}
I think that you do not have to use the timestamp method to create your fields, but you should use the dateTime method:
Schema::create('pusher_out_of_stocks', function (Blueprint $table) {
$table->increments('id');
$table->integer('pusher_id');
$table->integer('location_id');
$table->integer('product_id');
$table->dateTime('oos_at');
$table->dateTime('restocked_at')->nullable();
$table->timestamps();
$table->softDeletes();
});
This should work :)
Hope it helped!

How to transform this array in a json?

I have this relation CompanyhasMany Branch
And using $this->Company->find('all') output this:
(int) 1 => array(
'Company' => array(
'id' => '4',
'nome' => 'Somov',
'diretores' => 'Marcelo, Carl'
),
'Branch' => array(
(int) 0 => array(
'id' => '3',
'nome' => 'Serra',
'rua' => 'Rua teste 2 exttttt',
'numero' => '22',
'estado' => 'ES',
'cidade' => 'Etc',
'cep' => '',
'responsavel' => '',
'company_id' => '4',
'cnpj' => ''
)
)
),
(int) 2 => array(
'Company' => array(
'id' => '5',
'nome' => 'Soimpex',
'diretores' => ''
),
'Branch' => array()
)
)
I want to transform this in a json like this to use with Highchart:
[{
name: NAME OF COMPANY (nome),
data: NUMBER OF BRANCHS
}, {
name: NAME OF COMPANY (nome),
data: NUMBER OF BRANCHS
}]
How I do this convertion? Thanks
This will return a json object with only one result.
If we use previous example, can be done like this:
$arr = $this->Company->find('all'); // fetch the array
$arr1 = array();
foreach ($arr as $value) {
$tmp = array();
$tmp['name'] = $value['Company']['nome'];
$tmp['data'] = count($value['Branch']);
$arr1[] = $tmp;
}
return json_encode($arr1);
<?php
$sql=mysql_query("select * from Posts limit 20");
$response = array();
$posts = array();
while($row=mysql_fetch_array($sql))
{
$title=$row['title'];
$url=$row['url'];
$posts[] = array('title'=> $title, 'url'=> $url);
}
$response['posts'] = $posts;
$fp = fopen('results.json', 'w');
fwrite($fp, json_encode($response));
fclose($fp);
?>
This will generate a file called results.json file where your php file is stored on your online server, taking url and title variables from your MySQL db, you can change the variable names to what you want to fetch.
The whole idea is about like this
$arr=$this->Company->find('all'); // fetch the array
$arr1=array();
foreach ($arr as $value) {
$arr1['name']=$value['Company']['nome'];
//some more manual transform to desire format
}
return json_encode($arr1);

Perl DBI fetchall_hashref

Consider the following table:
mysql> select * from vCountryStatus;
+-------------+------------+------+---------+--------+-----------------+
| CountryName | CountryISO | Code | Status | Symbol | CurrencyName |
+-------------+------------+------+---------+--------+-----------------+
| Brazil | BR | 55 | LIVE | BRL | Brazilian Real |
| France | FR | 33 | offline | EUR | Euro |
| Philippines | PH | 63 | LIVE | PHP | Philippino Peso |
+-------------+------------+------+---------+--------+-----------------+
3 rows in set (0.00 sec)
I am trying to construct a hash based on this table. For this I do the following:
#!/usr/bin/perl
use DBI;
use Data::Dumper;
my $dbh = DBI->connect("dbi:mysql:database=db", "user", "password", {RaiseError => 1, AutoCommit => 0, FetchHashKeyName => "NAME_lc"}) || die "DB open error: $DBI::errstr";
my $sth = $dbh->prepare("select * from vCountryStatus");
$sth->execute;
my $hash = $sth->fetchall_hashref('countryiso');
print Dumper($hash);
Here is the output this generates:
$VAR1 = {
'PH' => {
'symbol' => 'PHP',
'status' => 'LIVE',
'countryname' => 'Philippines',
'countryiso' => 'PH',
'currencyname' => 'Philippino Peso',
'code' => '63'
},
'BR' => {
'symbol' => 'BRL',
'status' => 'LIVE',
'countryname' => 'Brazil',
'countryiso' => 'BR',
'currencyname' => 'Brazilian Real',
'code' => '55'
},
'FR' => {
'symbol' => 'EUR',
'status' => 'offline',
'countryname' => 'France',
'countryiso' => 'FR',
'currencyname' => 'Euro',
'code' => '33'
}
};
The question is: why is the key of the hash (countryiso) repeated in the values inside the hash?
What I would prefer is the following output:
$VAR1 = {
'PH' => {
'symbol' => 'PHP',
'status' => 'LIVE',
'countryname' => 'Philippines',
'currencyname' => 'Philippino Peso',
'code' => '63'
},
'BR' => {
'symbol' => 'BRL',
'status' => 'LIVE',
'countryname' => 'Brazil',
'currencyname' => 'Brazilian Real',
'code' => '55'
},
'FR' => {
'symbol' => 'EUR',
'status' => 'offline',
'countryname' => 'France',
'currencyname' => 'Euro',
'code' => '33'
}
};
Is it possible using fetchall_hashref DBI method? Or do I have to go the traditional way, looping through each row and constructing the hash on the fly?
No, it cannot be done using fetchall_hashref. But you can iterate over the hash values and delete the key:
delete $_->{countryiso} for values %$hash;
I had this same problem but was using multiple keys on fetchall_hashref, so I had to go deeper in the hash references. Not exactly rocket science, but here it is:
(...)
my #keys=('key1','key2','key3');
my $result_ref=$sth->fetchall_hashref(\#keys);
remove_key_values($result_ref,\#keys);
(...)
sub remove_key_values {
my ($href_values,$aref_keys) = (#_);
foreach my $hk (keys %$href_values) {
foreach my $ak (#$aref_keys) {
if ($ak eq $hk) {
delete $href_values->{$hk};
}
}
if (exists $href_values->{$hk} and ref($href_values->{$hk}) eq 'HASH') {
remove_key_values($href_values->{$hk},$aref_keys);
}
}
}