I use code below for import all models at the same time from different excel files.
It works well on Laravel 7.
But when I move it to Laravel 8, I always get error PDOException There is no active transaction
I see in DB that only one import of News model is done.
I cannot understand the reason of this problem. Documentation seems the same and there is no help in guthub.
App\Admin\routes.php
$router->get('seed', 'SeedController#index')->name('admin.seed');
App\Admin\Controllers\SeedController.php
<?php
namespace App\Admin\Controllers;
use Illuminate\Support\Facades\DB;
use App\Imports\Feedback\FeedbackImport;
use App\Imports\News\NewsImport;
use App\Imports\Menu\MenuImport;
use Maatwebsite\Excel\Facades\Excel;
class SeedController extends BaseAdminController
{
public $feedback;
public $news;
public $menu;
public function __construct()
{
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
$this->feedback = new FeedbackImport();
$this->news = new NewsImport();
$this->menu = new MenuImport();
}
public function index(Content $content)
{
$this->import();
$feedback = $this->feedback;
$news = $this->news;
$menu = $this->menu;
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
return $content
->title('Import & Export')
->description('Laravel excel')
->view('admin.seed', compact('menu', 'news', 'feedback'))
->withSuccess('Import succesfully finished');
}
public function import()
{
Excel::import($this->feedback, 'import/feedback.xlsm');
Excel::import($this->news, 'import/news.xlsm');
Excel::import($this->menu, 'import/menu.xlsm');
}
}
App\Imports\Feedback\FeedbackImport.php
<?php
namespace App\Imports\Feedback;
use App\Models\Feedback;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;
class FeedbackImport implements ToModel, WithHeadingRow, WithEvents
{
use RegistersEventListeners;
public $rows = 0;
public function model(array $row)
{
++$this->rows;
return new Feedback([
'name' => $row['name'],
'rate' => $row['rate'],
'text' => $row['text'],
]);
}
public function getRowCount(): int
{
return $this->rows;
}
public static function beforeSheet(BeforeSheet $event)
{
app('log')->info('Feedback import started');
Feedback::truncate();
}
public static function afterSheet(AfterSheet $event)
{
app('log')->info('Feedback import finished');
}
}
App\Imports\News\NewsImport.php
<?php
namespace App\Imports\News;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\AfterImport;
class NewsImport implements WithMultipleSheets, WithEvents
{
use RegistersEventListeners;
public $category;
public $post;
public function __construct()
{
$this->category = new NewsImportCategory();
$this->post = new NewsImportPost();
}
public function sheets(): array
{
return [
'news_categories' => $this->category,
'news_posts' => $this->post,
];
}
public static function beforeImport(BeforeImport $event)
{
app('log')->info('News import started');
}
public static function afterImport(AfterImport $event)
{
app('log')->info('News import finished');
}
}
App\Imports\News\NewsImportCategory.php
<?php
namespace App\Imports\News;
use App\Models\NewsCategory;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;
class NewsImportCategory implements ToModel, WithHeadingRow, WithEvents
{
use RegistersEventListeners;
public $rows = 0;
public function model(array $row)
{
if (empty($row['id'])) { return null; }
++$this->rows;
return new NewsCategory([
'id' => $row['id'],
'parent_id' => $row['parent_id'],
'title' => $row['title'],
'description' => $row['description'],
]);
}
public function getRowCount(): int
{
return $this->rows;
}
public static function beforeSheet(BeforeSheet $event)
{
app('log')->info('NewsCategory import started');
NewsCategory::truncate();
}
public static function afterSheet(AfterSheet $event)
{
app('log')->info('NewsCategory import finished');
}
}
App\Imports\News\NewsImportPost.php
<?php
namespace App\Imports\News;
use App\Models\NewsPost;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;
class NewsImportPost implements ToModel, WithHeadingRow, WithEvents
{
use RegistersEventListeners;
public $rows = 0;
public function model(array $row)
{
if (empty($row['category_id'])) { return null; }
++$this->rows;
return new NewsPost([
'category_id' => $row['category_id'],
'title' => $row['title'],
'fulltext' => $row['fulltext'],
'image' => $row['image'],
]);
}
public function getRowCount(): int
{
return $this->rows;
}
public static function beforeSheet(BeforeSheet $event)
{
app('log')->info('NewsPost import started');
NewsPost::truncate();
}
public static function afterSheet(AfterSheet $event)
{
app('log')->info('NewsPost import finished');
}
}
Menu is almost same as News import.
Related
I'm building livewire components that shares 50% of public properties and almost 90% of submit function logic.
each component using this trait has its own rules according to its html-form fields. and also each component perform some custom logic after validating the data. other that that they are all the same.
<?php
namespace App\Traits;
trait ParentServiceComponent
{
public $desc = '';
public function rules()
{
return [
'desc' => 'required|max:2000'
];
}
public abstract function componentCustomLogic(array $data);
public function submit()
{
$data = $this->validate();
$performCusomLogic = $this->componentCustomLogic($data);
// save to db and show success message
}
}
here an example of two components that uses this trait.
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Traits\ParentServiceComponent;
class RequestService extends Component
{
public $type = '';
use ParentServiceComponent { rules as traitRules; }
public function rules()
{
return array_merge($this->traitRules, [
'type' => 'required|max:200'
]);
}
public function componentCustomLogic(array $data)
{
// do the logic of this component here
}
public function render()
{
return view('livewire.request-service');
}
}
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Traits\ParentServiceComponent;
class ReplyService extends Component
{
public $body = '';
use ParentServiceComponent { rules as traitRules; }
public function rules()
{
return array_merge($this->traitRules, [
'body' => 'required|max:200'
]);
}
public function componentCustomLogic(array $data)
{
// do the logic of this component here
}
public function render()
{
return view('livewire.reply-service');
}
}
so my question is: am I doing it right?
I am beginner webdeveloper,
I use in my project Laravel 7 and maatwebsite/excel
I have this code:
namespace App\Models;
use App\Models\Reservation;
use Maatwebsite\Excel\Excel;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\Exportable;
class ReservationExport implements FromCollection, WithHeadings
{
use Exportable;
protected $date;
public function __construct(string $date)
{
$this->date = $date;
}
public function headings(): array
{
return [
'LP',
'ID Rezerwacji',
'Adres email',
'Token',
'Data',
'Godzina',
'Tor',
'Płeć',
];
}
public function collection()
{
$res = Reservation::select('id', 'id', 'email', 'token', 'date', 'hour', 'track', 'sex')->where('date', $this->date)->orderBy('time', 'ASC')->orderBy('track', 'ASC')->get();
foreach ($res as $val) {
$val->sex = ($val->sex == 1) ? 'kobieta' : 'mężczyzna';
}
return $res;
}
}
public function export(Request $request)
{
return Excel::download(new ReservationExport($request->input('query')), 'reservation-'.$request->input('query').'.xlsx');
}
This code generates an Excel document. It works fine. I would like to add a sequence number in 1 column (1,2,3 etc).
How can I do this?
My model:
class Reservation extends Model
{
protected $quarded = ['id'];
protected $fillable = ['email', 'token', 'date', 'hour', 'track', 'sex', 'time', 'people'];
public $timestamps = true;
protected $table = 'reservations';
}
Please help
try this
basically u need to add sn to heading then in your collection u need to a new key sn with calculated sequence number
hope it will work if not please tell me what error u r getting
<?php
use App\Models\Reservation;
use Maatwebsite\Excel\Excel;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\Exportable;
class ReservationExport implements FromCollection, WithHeadings
{
use Exportable;
protected $date;
public function __construct(string $date)
{
$this->date = $date;
}
public function headings(): array
{
return [
'SN', // sn new key adding
'LP',
'ID Rezerwacji',
'Adres email',
'Token',
'Data',
'Godzina',
'Tor',
'Płeć',
];
}
public function collection()
{
$res = Reservation::select('id', 'id', 'email', 'token', 'date', 'hour', 'track', 'sex')->where('date', $this->date)->orderBy('time', 'ASC')->orderBy('track', 'ASC')->get();
foreach ($res as $val) {
$val->sex = ($val->sex == 1) ? 'kobieta' : 'mężczyzna';
}
$res->map(function ($row,$key) {
return $row['sn'] = $key; // sn key added to collection
});
return $res;
}
}
I am generating a Excel Export, I want to change the timestamps format in excel file from 2020-07-29 13:56:09 to just DD:MM:YYYY.
How can I change my Export Class to Format the timestamp Column in my Excel File, BTW Date is in 'E' column in Excel file.
My Export Class:
use App\outbound_detail;
use App\outbound_temp;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromView;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Events\AfterSheet;
class ReleaseExportView implements FromCollection, WithHeadings, ShouldAutoSize, WithEvents
{
protected $reference;
function __construct($reference)
{
$this->reference = $reference;
}
public function collection()
{
return outbound_detail::where('reference', $this->reference)->get([
'reference', 'sku_parent', 'sku_child', 'cases', 'updated_at'
]);
}
public function headings(): array
{
return [
'Reference',
'SKU Parent',
'SKU Child',
'Cases Released',
'Date Created'
];
}
// ...
/**
* #return array
*/
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
$cellRange = 'A1:W1'; // All headers
$event->sheet->getDelegate()->getStyle($cellRange)->getFont()->setSize(14);
},
];
}
}
On your Reference Model, add this :
public function getUpdatedAtAttribute($date)
{
return Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $date)->format('d:m:Y');
}
You can use it's column formatting.
Try this:
// ...
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
class ReleaseExportView implements FromCollection, WithHeadings, ShouldAutoSize, WithEvents, WithColumnFormatting
{
// ...
public function map($reference): array
{
return [
$reference->reference,
$reference->sku_parent,
$reference->sku_child,
$reference->cases,
Date::dateTimeToExcel($reference->updated_at)
];
}
public function columnFormats(): array
{
return [
'E' => NumberFormat::FORMAT_DATE_DDMMYYYY
];
}
}
I am trying to allow users to download Excel, using Laravel Excel files with product information. My current web route looks like this:
Route::get('/excel/release', 'ExcelController#create')->name('Create Excel');
My current Export looks like this:
class ProductExport implements FromQuery
{
use Exportable;
public function __construct(int $id)
{
$this->id = $id;
}
public function query()
{
return ProductList::query()->where('id', $this->id);
}
}
My current controller looks like this:
public function create(Request $request) {
# Only alowed tables
$alias = [
'product_list' => ProductExport::class
];
# Ensure request has properties
if(!$request->has('alias') || !$request->has('id'))
return Redirect::back()->withErrors(['Please fill in the required fields.'])->withInput();
# Ensure they can use this
if(!in_array($request->alias, array_keys($alias)))
return Redirect::back()->withErrors(['Alias ' . $request->alias . ' is not supported'])->withInput();
# Download
return (new ProductExport((int) $request->id))->download('iezon_solutions_' . $request->alias . '_' . $request->id . '.xlsx');
}
When I head over to https://example.com/excel/release?alias=product_list&id=1 this executes correctly and returns an excel file. However, there is no column headers for the rows. The data comes out like so:
1 150 1 3 2019-01-16 16:37:25 2019-01-16 16:37:25 10
However, this should contain column headers like ID, cost etc... How can I include the column headers in this output?
According to documentation you can change your class to use the WithHeadings interface, and then define the headings function to return an array of column headers:
<?php
namespace App;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductExport implements FromQuery, WithHeadings
{
use Exportable;
public function __construct(int $id)
{
$this->id = $id;
}
public function query()
{
return ProductList::query()->where('id', $this->id);
}
public function headings(): array
{
return ["your", "headings", "here"];
}
}
This works with all export types (FromQuery, FromCollection, etc.)
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use DB;
class LocationTypeExport implements FromCollection,WithHeadings
{
public function collection()
{
$type = DB::table('location_type')->select('id','name')->get();
return $type ;
}
public function headings(): array
{
return [
'id',
'name',
];
}
}
You can combine this with array_keys to dynamically get your column headers:
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductExport implements FromQuery, WithHeadings
{
use Exportable;
public function __construct(int $id)
{
$this->id = $id;
}
public function query()
{
return ProductList::query()->where('id', $this->id);
}
public function headings(): array
{
return array_keys($this->query()->first()->toArray());
}
}
If you're using it with a collection, you can do so like the following:
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductExport implements FromCollection, WithHeadings
{
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
// for selecting specific fields
//return ProductList::select('id', 'product_name', 'product_price')->get();
// for selecting all fields
return ProductList::all();
}
public function headings(): array
{
return $this->collection()->first()->keys()->toArray();
}
}
<?php
namespace App\Exports;
use App\Models\UserDetails;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class CustomerExport implements FromCollection, WithHeadings
{
public function collection()
{
return UserDetails::whereNull('business_name')
->select('first_name','last_name','mobile_number','dob','gender')
->get();
}
public function headings() :array
{
return ["First Name", "Last Name", "Mobile","DOB", "Gender"];
}
}
<?php
namespace App\Exports;
use App\Models\StudentRegister;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class StudentExport implements FromCollection, WithHeadings
{
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
return StudentRegister::select('name','fname','mname','gender','language','address')->get();
}
public function headings(): array
{
//Put Here Header Name That you want in your excel sheet
return [
'Name',
'Father Name',
'Mother Name',
'Gender',
'Opted Language',
'Corresponding Address'
];
}
}
I am exporting from Collections and I wanted to generate headings automatically from the column names. The following code worked for me!
public function headings(): array
{
return array_keys($this->collection()->first()->toArray());
}
If you want to manually write the column names return an array with the column names.
And don't forget to impliment WithHeadings Interface
Thanks #Ric's comment.
This code works for me
use App\Newsletter;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class NewsletterExport implements FromCollection, WithHeadings
{
public function headings(): array
{
return [
'Subscriber Id',
'Name',
'Email',
'Created_at',
];
}
public function collection()
{
return Newsletter::where('isSubscribed', true)->get(['id','name','email','created_at']);
}
}
My controller is like this :
public function add($param)
{
...
$message = Message::create([
...
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
Notification::send($notify_to, new MessageInsert($message));
dd($message);
return $message;
}
My MessageInsert is like this :
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageInsert extends Notification implements ShouldBroadcast, ShouldQueue
{
use Queueable;
private $data;
public function __construct($data)
{
$this->data = $data;
}
public function via($notifiable)
{
return ['broadcast','database','mail'];
}
public function toArray($notifiable)
{
return [
'id' => $this->data->id,
...
];
}
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Hello!')
->line('...')
->action('...')
->line('Thank you!');
}
}
If like this :
return ['broadcast','database','mail'];
The result of dd($message); is error
But if like this :
return ['database','mail'];
The result of dd($message); is array of $message
Why there is error when I use broadcast?
Did you try adding the toBroadcast function?
public function toBroadcast($notifiable) {
return new BroadcastMessage([ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]);
}