Skip to content

Commit fc4d535

Browse files
committed
[TASK] Add initial code from internal project
1 parent b126306 commit fc4d535

File tree

10 files changed

+393
-22
lines changed

10 files changed

+393
-22
lines changed

.gitignore

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
1-
/vendor/
2-
node_modules/
3-
npm-debug.log
4-
yarn-error.log
5-
6-
# Laravel 4 specific
7-
bootstrap/compiled.php
8-
app/storage/
9-
10-
# Laravel 5 & Lumen specific
11-
public/storage
12-
public/hot
13-
14-
# Laravel 5 & Lumen specific with changed public path
15-
public_html/storage
16-
public_html/hot
17-
18-
storage/*.key
19-
.env
20-
Homestead.yaml
21-
Homestead.json
22-
/.vagrant
1+
/.idea
2+
/vendor
3+
/node_modules
4+
package-lock.json
5+
composer.phar
6+
composer.lock
7+
phpunit.xml
238
.phpunit.result.cache
9+
.DS_Store
10+
Thumbs.db

composer.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "eur-rsm/database-view-export",
3+
"description": "A Laravel Nova package for exporting configured database views.",
4+
"keywords": [
5+
"laravel",
6+
"nova",
7+
"exports",
8+
"database-views",
9+
"actions"
10+
],
11+
"license": "MIT",
12+
"require": {
13+
"php": ">=7.3.0",
14+
"laravel/nova": "*",
15+
"maatwebsite/excel": "^3.1"
16+
},
17+
"autoload": {
18+
"psr-4": {
19+
"EUR\\RSM\\DatabaseViewExport\\": "src/"
20+
}
21+
},
22+
"extra": {
23+
"laravel": {
24+
"providers": [
25+
"EUR\\RSM\\DatabaseViewExport\\DatabaseViewExportServiceProvider"
26+
]
27+
}
28+
}
29+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateDatabaseViewExportsTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('database_view_exports', function (Blueprint $table) {
17+
$table->id();
18+
$table->string('name');
19+
$table->string('view_name');
20+
});
21+
}
22+
23+
/**
24+
* Reverse the migrations.
25+
*
26+
* @return void
27+
*/
28+
public function down()
29+
{
30+
Schema::dropIfExists('database_view_exports');
31+
}
32+
}

readme.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Laravel Nova: Export database views
2+
> Export manually created database views
3+
4+
## Installation
5+
1) Override the Nova layout through creating `resources/views/vendor/nova/layout.blade.php` in your project route.
6+
2) Add `@include('database-view-export::exports-dropdown')` to your desired location
7+
- Example:
8+
```html
9+
<!-- Content -->
10+
<div class="content">
11+
<div class="flex items-center relative shadow h-header bg-white z-20 px-view">
12+
<a v-if="@json(\Laravel\Nova\Nova::name() !== null)" href="{{ \Illuminate\Support\Facades\Config::get('nova.url') }}" class="no-underline dim font-bold text-90 mr-6">
13+
{{ \Laravel\Nova\Nova::name() }}
14+
</a>
15+
16+
@if (count(\Laravel\Nova\Nova::globallySearchableResources(request())) > 0)
17+
<global-search dusk="global-search-component"></global-search>
18+
@endif
19+
20+
{{-- Add dropdown menu for exports package --}}
21+
<div class="ml-auto flex items-center dropdown-right">
22+
@include('database-view-export::exports-dropdown')
23+
</div>
24+
25+
<dropdown class="ml-8 h-9 flex items-center dropdown-right">
26+
@include('nova::partials.user')
27+
</dropdown>
28+
</div>
29+
30+
<div data-testid="content" class="px-view py-view mx-auto">
31+
@yield('content')
32+
33+
@include('nova::partials.footer')
34+
</div>
35+
</div>
36+
```
37+
3) Add the displayed key & the specific name of the view database for it to render in the dropdown.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php $exportService = app(\EUR\RSM\DatabaseViewExport\Services\BackofficeExportService::class); ?>
2+
3+
<dropdown>
4+
<dropdown-trigger class="h-9 flex items-center">
5+
<span class="text-90">Export</span>
6+
</dropdown-trigger>
7+
8+
<dropdown-menu dusk="exports-list" slot="menu" width="200" direction="rtl">
9+
<ul class="list-reset">
10+
@if($exportService->all()->count() === 0)
11+
<li>
12+
<a href="javascript:void(0)" class="block no-underline text-70 p-3 cursor-default">
13+
No exports available
14+
</a>
15+
</li>
16+
@else
17+
@foreach($exportService->all() as $export)
18+
<li>
19+
<a href="{{ $export->url() }}" class="block no-underline text-90 hover:bg-30 p-3">
20+
{{ $export->label() }}
21+
</a>
22+
</li>
23+
@endforeach
24+
@endif
25+
</ul>
26+
</dropdown-menu>
27+
</dropdown>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace EUR\RSM\DatabaseViewExport;
4+
5+
use EUR\RSM\DatabaseViewExport\Http\Controllers\ExportController;
6+
use Illuminate\Support\Facades\Route;
7+
use Illuminate\Support\ServiceProvider;
8+
9+
class DatabaseViewExportServiceProvider extends ServiceProvider
10+
{
11+
/**
12+
* @return void
13+
*/
14+
public function boot(): void
15+
{
16+
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'database-view-export');
17+
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
18+
19+
$this->app->booted(function (): void {
20+
$this->routes();
21+
});
22+
}
23+
24+
/**
25+
* @return void
26+
*/
27+
protected function routes(): void
28+
{
29+
if ($this->app->routesAreCached()) {
30+
return;
31+
}
32+
33+
Route::middleware('nova')
34+
->prefix('nova-vendor/database-view-export')
35+
->group(function (): void {
36+
Route::get('/export/{key}', [ExportController::class, 'export'])
37+
->name('database-view-export.export');
38+
});
39+
}
40+
}

src/Exports/ViewExport.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
namespace EUR\RSM\DatabaseViewExport\Exports;
4+
5+
use Carbon\Carbon;
6+
use Illuminate\Support\Collection;
7+
use Illuminate\Support\Facades\DB;
8+
use Illuminate\Support\Str;
9+
use Maatwebsite\Excel\Concerns\Exportable;
10+
use Maatwebsite\Excel\Concerns\FromCollection;
11+
use Maatwebsite\Excel\Concerns\WithHeadings;
12+
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
13+
use Maatwebsite\Excel\Excel;
14+
15+
/**
16+
* Represents a database view that can be exported to Excel.
17+
*/
18+
final class ViewExport implements FromCollection, WithHeadings, WithStrictNullComparison
19+
{
20+
use Exportable;
21+
22+
/** @var string */
23+
private $label;
24+
25+
/**
26+
* Name of the view (table) to base the export on.
27+
*
28+
* @var string
29+
*/
30+
private $viewName;
31+
32+
/**
33+
* @see \Maatwebsite\Excel\Excel::XLSX
34+
* @see \Maatwebsite\Excel\Excel::CSV
35+
* @var string
36+
*/
37+
private $exportType = Excel::XLSX;
38+
39+
/**
40+
* @param string $label
41+
* @param string $viewName
42+
*/
43+
public function __construct(string $label, string $viewName)
44+
{
45+
$this->label = $label;
46+
$this->viewName = $viewName;
47+
}
48+
49+
/**
50+
* Key (unique) that identifies the export.
51+
*
52+
* @return string
53+
*/
54+
public function key(): string
55+
{
56+
return Str::snake($this->label(), '-');
57+
}
58+
59+
/**
60+
* Human-friendly label for this export, displayed in the dropdown menu.
61+
*
62+
* @return string
63+
*/
64+
public function label(): string
65+
{
66+
return $this->label;
67+
}
68+
69+
/**
70+
* URL to access this export, used in the dropdown menu.
71+
*
72+
* @return string
73+
*/
74+
public function url(): string
75+
{
76+
return route('database-view-export.export', $this->key());
77+
}
78+
79+
/**
80+
* Collect the data that need to be exported.
81+
*
82+
* @return \Illuminate\Support\Collection
83+
*/
84+
public function collection(): Collection
85+
{
86+
return DB::table($this->viewName)->select()->get();
87+
}
88+
89+
/**
90+
* Get the headings (columns) that are inserted as the first row.
91+
*
92+
* @return array
93+
*/
94+
public function headings(): array
95+
{
96+
return DB::getSchemaBuilder()->getColumnListing($this->viewName);
97+
}
98+
99+
/**
100+
* Determine the filename for the exported file.
101+
*
102+
* @param string $extension
103+
* @return string
104+
*/
105+
public function filename(): string
106+
{
107+
return $this->key() . '_' . Carbon::now()->toDateTimeString() . '.' . strtolower($this->exportType);
108+
}
109+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace EUR\RSM\DatabaseViewExport\Http\Controllers;
4+
5+
use EUR\RSM\DatabaseViewExport\Services\BackofficeExportService;
6+
use Symfony\Component\HttpFoundation\Response;
7+
8+
final class ExportController
9+
{
10+
/**
11+
* @param string $exportKey
12+
* @param \EUR\RSM\DatabaseViewExport\Services\BackofficeExportService $exportService
13+
* @return \Symfony\Component\HttpFoundation\Response
14+
*/
15+
public function export(string $exportKey, BackofficeExportService $exportService): Response
16+
{
17+
$export = $exportService->findByKey($exportKey);
18+
19+
return rescue(
20+
function () use ($export, $exportService): Response {
21+
return $exportService->runExport($export);
22+
},
23+
function (): void {
24+
abort(500, 'Unable to run the requested export. An exception was thrown (see logs).');
25+
}
26+
);
27+
}
28+
}

src/Models/Export.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace EUR\RSM\DatabaseViewExport\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
final class Export extends Model
8+
{
9+
/** @var string */
10+
protected $table = 'database_view_exports';
11+
12+
/** @var bool */
13+
public $incrementing = false;
14+
15+
/** @var bool */
16+
public $timestamps = false;
17+
18+
/** @var string */
19+
protected $primaryKey = 'name';
20+
21+
/** @var string */
22+
protected $keyType = 'string';
23+
}

0 commit comments

Comments
 (0)