File: D:/HostingSpaces/SBogers10/wingssprayer.komma.pro/app/Invoicing/AbstractInvoicingService.php
<?php declare(strict_types=1);
namespace App\Invoicing;
use App\Orders\Models\Order;
use Barryvdh\DomPDF\Facade as PDF;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
/**
* Class AbstractInvoicingService
*
* @package App\Invoicing
*/
abstract class AbstractInvoicingService
{
/** @var string the filesystem disk we use for storing invoices */
protected const DISK = 'local';
/** @var string the directory on the disk that contains the invoices */
protected const DIRECTORY = 'order_documents'.DIRECTORY_SEPARATOR.'abstract_invoices'.DIRECTORY_SEPARATOR;
/** @var string The name of the view that represents an invoice */
protected const VIEWNAME = 'shop.pages.abstract_invoice.invoiceShow';
/** @var string The column on an order that holds the number of the invoice */
protected const NUMBER_COLUMN = 'invoice_number';
/**
* InvoiceService constructor.
*/
public function __construct()
{
$this->initializeDisk();
}
/**
* @param Order $order
* @return View
*/
public function getForOrderAsView(Order $order): View
{
if(!$this->getDisk()->exists($this->getPDFPathFromOrder($order))) {
//Not yet created. Generate a pdf.
$this->generatePdfForOrder($order);
}
return view(static::VIEWNAME, $this->getViewData($order));
}
/**
* Returns a response that makes the browser open up the PDF so that it is displayed in the browser
*
* @param Order $order
* @return BinaryFileResponse
*/
public function getForOrderAsPDF(Order $order): BinaryFileResponse
{
if(!$this->getDisk()->exists($this->getPDFPathFromOrder($order))) {
//Not yet created. Generate a pdf.
$this->generatePdfForOrder($order);
}
return response()->file($this->getDisk()->path($this->getPDFPathFromOrder($order)));
}
/**
* Returns a response that forces the browser to download the PDF for the order given
*
* @param Order $order
* @return StreamedResponse
*/
public function getForOrderAsPDFDownload(Order $order): StreamedResponse
{
if(!$this->getDisk()->exists($this->getPDFPathFromOrder($order))) {
//Not yet created. Generate a pdf.
$this->generatePdfForOrder($order);
}
return Storage::download($this->getPDFPathFromOrder($order), $order->{static::NUMBER_COLUMN}.'.pdf');
}
/**
* @param Order $order
*/
protected function generatePdfForOrder(Order $order): void
{
$this->deleteOldForOrder($order);
$pdf = PDF::loadView(static::VIEWNAME, $this->getViewData($order));
if(!$this->getDisk()->put(static::getPDFPathFromOrder($order), $pdf->output())) throw new \RuntimeException('Could not save PDF for order with id: '.$order->id);
}
/**
* Returns the path to an invoice's pdf, that is relative to the disks directory
*
* @param Order $order
* @param bool $generatePdfIfNeeded
* @return string
*/
protected function getPDFPathFromOrder(Order $order, $generatePdfIfNeeded = false): string
{
if($generatePdfIfNeeded && !$this->getDisk()->exists($this->getPDFPathFromOrder($order))) {
$this->generatePdfForOrder($order);
}
return static::DIRECTORY.$order->{static::NUMBER_COLUMN}.'_'.$order->updated_at->timestamp.'.pdf';
}
/**
* Deletes old invoices for order, if there are any.
*
* @param Order $order
*/
protected function deleteOldForOrder(Order $order)
{
$oldInvoices = $this->findOldForOrder($order);
foreach($oldInvoices as $oldInvoice) {
$oldInvoicePath = static::DIRECTORY.DIRECTORY_SEPARATOR.$oldInvoice;
if(!$this->getDisk()->delete(static::DIRECTORY.DIRECTORY_SEPARATOR.$oldInvoice))
throw new \InvalidArgumentException('Could not delete old invoice: '.$oldInvoicePath);
}
}
/**
* Returns an array containing paths to old invoices
*
* @param Order $order
* @return array
*/
protected function findOldForOrder(Order $order): array
{
$allFiles = $this->getDisk()->allFiles(static::DIRECTORY);
$oldInvoices = [];
foreach($allFiles as $file)
{
$filename = basename($file);
$timestamp = (string) $order->updated_at->timestamp;
$number = (string) $order->{static::NUMBER_COLUMN};
//The preg_match returns 1 if the filename starts with the invoice number but is not followed by the current updated_at timestamp. And finaly ending with .pdf.
if(preg_match('/^'.preg_quote($number).'.+(?<!preg_quote('.$timestamp.'))\.pdf$/', $filename) === 1) {
$oldInvoices[] = $filename;
}
}
return $oldInvoices;
}
/**
* @param Order $order
* @return array
*/
abstract protected function getViewData(Order $order):array;
/**
* @return Filesystem
*/
protected function getDisk(): FileSystem
{
return Storage::disk(static::DISK);
}
/**
* Initialize storage disk. Making sure there is a directory where to save invoices
*/
private function initializeDisk(): void
{
if(!$this->getDisk()->exists(static::DIRECTORY)) {
if (!$this->getDisk()->makeDirectory(static::DIRECTORY)) {
throw new \RuntimeException('Could not create the document directory.');
}
}
}
}