Avoiding repeated data in laravel querybuilder result - laravel

I am trying to write code to return the number of diseases diagnosed in a clinic after a given period either weekly, monthly or daily using jimmyjs laravel-report-generator using the code bellow,
$fromDate = $request->fromDate;
$toDate = $request->toDate;
$sortBy = 'updated_at';
$title = 'CHATTHE GROUP'; // Report title
$subTitle = 'Mobidity Report';
$total = 0;
$meta = [ // For displaying filters description on header
''=> $subTitle,
'From' => $fromDate . ' To: ' . $toDate,
'Generated By' => Auth::user()->name
];
$queryBuilder = Diagnosis::select(['diagnosis', 'updated_at']) // Do some querying..
->whereBetween('updated_at', [$fromDate, $toDate])
->distinct('diagnosis')
->orderBy($sortBy, 'ASC');
$columns = [ // Set Column to be displayed
'DISEASE' => 'diagnosis',
'NO OF CASES' => function($result){
return Diagnosis::where('diagnosis',$result->diagnosis)->count();
}, // if no column_name specified, this will automatically seach for snake_case of column name (will be registered_at) column from query result
'% TOTAL' => function($result){
return (Diagnosis::where('diagnosis',$result->diagnosis)->count()/$result->count()*100);
}
];
return ExcelReport::of($title, $meta, $queryBuilder, $columns)
->editColumns(['DISEASE', '% TOTAL'], [ // Mass edit column
'class' => 'right bold'
])
->showHeader(true)
->simple()
->download('mobidityReport');
This produces the following excel file
Which has the diseases repeated just as they repeat in the table, is there anyway to avoid this? I tried using distinct() but that gave an error.

Related

How to show multiple columns under one column at Laravel-excel? But that one column will take take multiple columns area at a time

I need to show multiple columns under one column at Laravel-excel. And that one column will take multiple columns area at a time in excel. like - 1st row 1st column name is "Tissue" under that column I need to show "Super Gold,Pink,White Butterfly,White Panpata". And "Tissue" column will take four rows in excel file and under "tissue" column show that four names of tissue. and 1st row 2nd column is "Facial Tissue ". It takes one row cause under "Facial Tissue" has "120 Sheet X 2 Ply" column.
Again 1st row 3rd column is "Napkin Tissue" and it contains three columns . Cause I need to show " 13" x 13",100 Sht/Pkt, Economy Pkt," these in 3 columns.
$excel_dynamic_data_array = array();
$index=0;
$excel_dynamic_data_array_sur_name = array();
foreach ($productGroup as $gKey => $group )
{
$col_[$gKey] = false;
foreach($all_product as $pkey => $product)
{
if($productGroup[$gKey]["id"] == $product->product_group_id)
{
$col_[$gKey] = true;
}
}
if($col_[$gKey])
{
$product_Names_with_keys = $productGroup[$gKey]["t_product"].$productGroup[$gKey]['gorupName'];
$excel_dynamic_data_array[$index][] = $productGroup[$gKey]['gorupName'];
$index++;
}
}
$item = $excel_dynamic_data_array; //------------- Get type of Product name
$item_name = implode(', ', array_map(function ($entry) {
return ($entry[key($entry)]);
}, $item));
foreach($all_product as $key => $product)
{
if(empty($product->product_sur_name))
{ echo ( "N/A ");
}else{
$excel_dynamic_data_array_sur_name[$index][] =$product->product_sur_name;
$index++;
}
}
$sur_names = $excel_dynamic_data_array_sur_name; //------------- Get Product names
$sur_name = implode(', ', array_map(function ($entry) {
return ($entry[key($entry)]);
}, $sur_names));
if ($customer_type == 2)
{
$excel_data_attribute_array_column = array(
array_merge(
array('SL','Order No','Order Date','Challan No','Challan Date','Bill No','Party Name','Area'),explode(',',$item_name),array('Total')
)
);
$excel_data_attribute_array_2nd_column = array(
array_merge(
array('','','','','','','',''),explode(',',$sur_name)
)
);
}
}
$total_final_array = array_merge($excel_data_attribute,$excel_data_attribute_array,$excel_data_attribute_array_column,$excel_data_attribute_array_2nd_column);
}
return collect($total_final_array);
The only way I can think of is to use export using View and using colspan attributes.
Laravel-Excel Export from view
<td colspan=4>Tissues over four cells</td>

Call to a member function storeAs() on null

I want to store images with id to table and save them to a folder.
I have two tables catalogs and images.Images table has img_id which is a foreign key to id in catalogs table, code in my controller is:
$catalog = new Katalog();
$catalog->name = $name;
$catalog->picturePath = $name . '/';
$catalog->description = $desc;
$catalog->address = $request->input('address');
$catalog->phone_number = $request->input('phone_number');
$catalog->email = $request->input('e_mail');
$catalog->info_holder = $request->input('type');
$catalog->partner_logo = $logo_img_name;
$catalog->short_news = $request->input('short_news');
$catalog->updated_at = Carbon::now();
$catalog->site = $request->input('site');
$catalog->creator_id = Auth::user()->id;
$catalog->save();
$id = Katalog::where('name', $name)->first()->id;
if ($request->hasFile('images')) {
foreach ($request->file('images') as $image) {
$img_name = $image->getClientOriginalName();
$request->image->storeAs(('/images/' . $name), $img_name, 'images');
Image::creat([
'img_id' => $id,
'img_name' => $img_name
]);
}
}
After storing data to the catalogs table it returns a new id but I want to store images to images table with returned id but can not do this.Error shows here $request->image->storeAs(('/images/' . $name), $img_name, 'images');
Help me please thanks in advance.
You can get the ID from the just created object (Katalog) without a query
$id = $catalog->id;
instead of
$id = Katalog::where('name', $name)->first()->id;
Because if there are other Katalog records with the same name, you may not get the one you want
PS: you may have a typo here, add an "e" at the end
Image::create([
'img_id' => $id,
'img_name' => $img_name
]);
Hope this helps

Laravel : How can i get old and new value by updateOrCreate

I want update or create in data base
but i want get the old value and updated value because i want to compare between these two value
for example
this item in table user
name = Alex and Order = 10
so now i want update this person by
name = Alex and Order = 8
Now After updating or creating if not exist
just for update i want get
Old order 10 | And new Order 8
I want compare between these order
i have tryin getChange() and getOriginal() but two the function give me just the new value.
Please Help
You can get the old value using getOriginal if you have the object already loaded.
For example :
$user = User::find(1);
$user->first_name = 'newname';
// Dumps `oldname`
dd($user->getOriginal('first_name'));
$user->save();
However in case of updateOrCreate, you just have the data. I am not sure about a way to do it using updateOrCreate but you can do simply do :
$user = User::where('name', 'Alex')->first();
$newOrder = 10;
if($user){
$oldOrder = $user->getOriginal('order');
$user->order = $newOrder;
$user->save();
}
Is the name unique in the table? Because if it is not you will have updates on multiple rows with the same data.
So the best approach is to use the unique column which is probably the ID.
User::updateOrCreate(
[ 'id' => $request->get('id') ], // if the $id is null, it will create new row
[ 'name' => $request->get('name'), 'order' => $request->get('order') ]
);
Solution
$model = Trend::where('name', $trend->name)->first();
if ($model) {
$model->old_order = $model->getOriginal('order');
$model->order = $key + 1;
$model->save();
} else {
Trend::where('order', $key + 1)->delete();
$new = new Trend();
$new->name = $trend->name;
$new->old_order = $key + 1;
$new->order = $key + 1;
$new->tweet_volume = $trend->tweet_volume;
$new->save();
}

laravel retrieve json and save into database

I am getting cinema title + times using API from Cinelist, I then want to save these values into a database.
At the moment, it does save but only 1 record, the last one. However, I want it to save each one.
Also each time it is run I want to update existing records instead of creating new ones unless there are more results.
So usually there are 5 records, each time I run the function I want to update the database with the new 5 records, however, if it's a different day and there are 6 records I want to update 5 records and insert 1 extra one so there is 6.
My code so far:
function odeon(){
$data= file_get_contents('https://api.cinelist.co.uk/get/times/cinema/10565');
$data = json_decode($data);
foreach($data->listings as $listing){
$title = $listing->title;
$time = implode(', ', $listing->times);
$id = + 1;
$films = Film::where('id', $id)->first();
if (!$films) {
$films = new Film();
}
$films->title = $title;
$films->times = $time;
$films->save();
}
}
You may use eloquent's updateOrCreate method to insert non-existent data and update existing data.
function odeon(){
$data= file_get_contents('https://api.cinelist.co.uk/get/times/cinema/10565');
$data = json_decode($data);
foreach($data->listings as $listing){
$title = $listing->title;
$time = implode(', ', $listing->times);
Films::updateOrCreate([
'title' => $title,
'$times' => $time
]);
}
}

Laravel Bulk UPDATE

I'm trying to update a table containing a slug value with random slugs for each record.
$vouchers = Voucher->get(); // assume 10K for example
foreach ($vouchers as $voucher) {
$q .= "UPDATE vouchers set slug = '" . Str::random(32) . "' WHERE id = " . $voucher->id . ";";
}
DB::statement($q);
There are about 2 million records so I need to perform this as a bulk. Doing it as separate records is taking way too long. I can't seem to find a way to bulk run them, say in groups of 10K or something.
Tried a bunch of variations of ->update() and DB::statement but can't seem to get it to go.
In case someone land in this page like me, laravel allows a bulk update as:
$affectedRows = Voucher::where('id', '=', $voucher->id)->update(array('slug' => Str::random(32)));
See "Updating A Retrieved Model" under http://laravel.com/docs/4.2/eloquent#insert-update-delete
I have created My Custom function for Multiple Update like update_batch in CodeIgniter.
Just place this function in any of your model or you can create helper class and place this function in that class:
//test data
/*
$multipleData = array(
array(
'title' => 'My title' ,
'name' => 'My Name 2' ,
'date' => 'My date 2'
),
array(
'title' => 'Another title' ,
'name' => 'Another Name 2' ,
'date' => 'Another date 2'
)
)
*/
/*
* ----------------------------------
* update batch
* ----------------------------------
*
* multiple update in one query
*
* tablename( required | string )
* multipleData ( required | array of array )
*/
static function updateBatch($tableName = "", $multipleData = array()){
if( $tableName && !empty($multipleData) ) {
// column or fields to update
$updateColumn = array_keys($multipleData[0]);
$referenceColumn = $updateColumn[0]; //e.g id
unset($updateColumn[0]);
$whereIn = "";
$q = "UPDATE ".$tableName." SET ";
foreach ( $updateColumn as $uColumn ) {
$q .= $uColumn." = CASE ";
foreach( $multipleData as $data ) {
$q .= "WHEN ".$referenceColumn." = ".$data[$referenceColumn]." THEN '".$data[$uColumn]."' ";
}
$q .= "ELSE ".$uColumn." END, ";
}
foreach( $multipleData as $data ) {
$whereIn .= "'".$data[$referenceColumn]."', ";
}
$q = rtrim($q, ", ")." WHERE ".$referenceColumn." IN (". rtrim($whereIn, ', ').")";
// Update
return DB::update(DB::raw($q));
} else {
return false;
}
}
It will Produces:
UPDATE `mytable` SET `name` = CASE
WHEN `title` = 'My title' THEN 'My Name 2'
WHEN `title` = 'Another title' THEN 'Another Name 2'
ELSE `name` END,
`date` = CASE
WHEN `title` = 'My title' THEN 'My date 2'
WHEN `title` = 'Another title' THEN 'Another date 2'
ELSE `date` END
WHERE `title` IN ('My title','Another title')
Chunking results is the best way to do this kind of stuff without eating all of your RAM and Laravel support chunking results out of the box.
For example:
Voucher::chunk(2000, function($vouchers)
{
foreach ($vouchers as $voucher)
{
//
}
});
I made a bulk update function to use in my Laravel projects. It may be useful for anyone who wants to use the batch update query in Laravel. Its first parameter is the table name string, second is the key name string based on which you want to update the row or rows and most of the times it will be the 'id' and the third parameter is a data array in the following format:
array(
array(
'id' => 1,
'col_1_name' => 'col_1_val',
'col_2_name' => 'col_2_val',
//...
),
array(
'id' => 2,
'col_1_name' => 'col_1_val',
'col_2_name' => 'col_2_val',
//...
),
//...
);
The function will return the number of affected rows. Function definition:
private function custom_batch_update(string $table_name = '', string $key = '', Array $update_arr = array()) {
if(!$table_name || !$key || !$update_arr){
return false;
}
$update_keys = array_keys($update_arr[0]);
$update_keys_count = count($update_keys);
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} = $key_name . ' = CASE';
}
$length = count($update_arr);
$index = 0;
$query_str = 'UPDATE ' . $table_name . ' SET ';
$when_str = '';
$where_str = ' WHERE ' . $key . ' IN(';
while ($index < $length) {
$when_str = " WHEN $key = '{$update_arr[$index][$key]}' THEN";
$where_str .= "'{$update_arr[$index][$key]}',";
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} .= $when_str . " '{$update_arr[$index][$key_name]}'";
}
$index++;
}
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} .= ' ELSE ' . $key_name . ' END, ';
$query_str .= $when_{$key_name};
}
$query_str = rtrim($query_str, ', ');
$where_str = rtrim($where_str, ',') . ')';
$query_str .= $where_str;
$affected = DB::update($query_str);
return $affected;
}
It will produce and execute the query string like this:
UPDATE table_name SET col_1_name = CASE
WHEN id = '1' THEN 'col_1_value'
WHEN id = '2' THEN 'col_1_value'
ELSE col_1_name END,
col_2_name = CASE
WHEN id = '1' THEN 'col_2_value'
WHEN id = '2' THEN 'col_2_value'
ELSE col_2_name END
WHERE id IN('1','2')

Resources