637 lines
25 KiB
PHP
637 lines
25 KiB
PHP
<?php
|
|
|
|
namespace App\Lib\Helpers;
|
|
|
|
use App\Enums\Discount\DiscountType;
|
|
use App\Enums\GeneralConfigType;
|
|
use App\Enums\Product\TaxRate;
|
|
use App\Models\Merchandise\Product;
|
|
use App\Models\Shop\Order;
|
|
use App\Models\Site\GeneralConfig;
|
|
use Gloudemans\Shoppingcart\Cart;
|
|
use Gloudemans\Shoppingcart\CartItem;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Route;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
|
use Money\Money;
|
|
use Mpdf\Config\FontVariables;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
|
|
class ToolboxHelper
|
|
{
|
|
/**
|
|
* Update basket quantities using cart caluculator
|
|
*
|
|
* @param object $basket
|
|
* @param array $newQuantities Array of [id => qty] or [rowId => qty].
|
|
* @return object
|
|
* @throws \Illuminate\Validation\ValidationException If a product from the basket is not accessible anymore.
|
|
*/
|
|
public static function updateBasketAmounts(object $basket, array $newQuantities): object
|
|
{
|
|
$newQuantities = \collect($newQuantities);
|
|
// ! Ici on veux réutiliser le cart calculator.
|
|
$cart = self::createVirtualCart(\collect($basket)
|
|
->map(function (object $basketItem) {
|
|
$cartItem = self::basketItemObjectToCartItem($basketItem);
|
|
$cartItem->associate(Product::query()->where('id', $cartItem->id)->first());
|
|
return $cartItem;
|
|
})
|
|
// * Enlever les produits qui ne seront pas livrés.
|
|
->filter(function (CartItem $basketItem) {
|
|
return $basketItem->qty;
|
|
}));
|
|
|
|
// * Update virtual basket with actual content
|
|
\collect($basket)->each(function (object $basketItem) use ($newQuantities, $cart) {
|
|
/** @var \Gloudemans\Shoppingcart\CartItem $cartItem */
|
|
$cartItem = $cart->search(function (CartItem $cartItem) use ($basketItem) {
|
|
return $cartItem->id === $basketItem->id;
|
|
})->first();
|
|
$newQty = \intval(
|
|
$newQuantities->get($basketItem->id, $newQuantities->get($basketItem->rowId))
|
|
);
|
|
// * Update Qty or remove item from the cart.
|
|
if (!$newQty) {
|
|
$cart->remove($cartItem->rowId);
|
|
return;
|
|
}
|
|
$cartItem->setQuantity($newQty);
|
|
// ! https://github.com/bumbummen99/LaravelShoppingcart/pull/181
|
|
// * Note Lib is is actually refactoring for laravel 9 php8 only
|
|
// * https://github.com/bumbummen99/LaravelShoppingcart/pull/145
|
|
// ! These lines are required to prevent amount bug.
|
|
$cartItem->setTaxRate($basketItem->options->tax_rate / 100);
|
|
$cartItem->setDiscountRate($basketItem->options->discount_rate);
|
|
});
|
|
|
|
$virtualOrder = new Order();
|
|
$virtualOrder->assignBasket($cart);
|
|
|
|
return (object)$virtualOrder->basket;
|
|
}
|
|
|
|
/**
|
|
* Crete a virtual cart to use calculator
|
|
*
|
|
* @param \Illuminate\Support\Collection $cartItemList
|
|
* @return \Gloudemans\Shoppingcart\Cart
|
|
*/
|
|
public static function createVirtualCart(Collection $cartItemList): Cart
|
|
{
|
|
// * Get temp cart instance.
|
|
/** @var \Gloudemans\Shoppingcart\Cart */
|
|
$basket = app('basket');
|
|
$virtualCart = $basket->instance(\strval(\uniqid('_temp', true)));
|
|
|
|
$cartItemList->each(function (CartItem $cartItem) use ($virtualCart) {
|
|
if (!($cartItem instanceof CartItem)) {
|
|
throw new \RuntimeException('Cart item shall be a ' . CartItem::class);
|
|
}
|
|
$virtualCart->addCartItem($cartItem);
|
|
return $cartItem;
|
|
});
|
|
return $virtualCart;
|
|
}
|
|
|
|
/**
|
|
* Parse a basket item from DB to and actual BasketItem
|
|
*
|
|
* @param object $basketItem This should actually come from DB.
|
|
* @return \Gloudemans\Shoppingcart\CartItem
|
|
* @throws \RuntimeException If basketItem format is not valid.
|
|
*/
|
|
public static function basketItemObjectToCartItem(object $basketItem): CartItem
|
|
{
|
|
if (!self::basketObjectIsValid($basketItem)) {
|
|
throw new \RuntimeException('Cannot validate basket item');
|
|
}
|
|
$cartItem = CartItem::fromArray(\json_decode(\json_encode($basketItem), true));
|
|
$cartItem->setQuantity($basketItem->qty);
|
|
// ! https://github.com/bumbummen99/LaravelShoppingcart/pull/181
|
|
// * Note Lib is is actually refactoring for laravel 9 php8 only
|
|
// * https://github.com/bumbummen99/LaravelShoppingcart/pull/145
|
|
// ! These lines are required to prevent amount bug.
|
|
$cartItem->setTaxRate($basketItem->options->tax_rate / 100);
|
|
$cartItem->setDiscountRate($basketItem->options->discount_rate);
|
|
return $cartItem;
|
|
}
|
|
|
|
/**
|
|
* Get basket as product list
|
|
*
|
|
* @param \Gloudemans\Shoppingcart\Cart $basket
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
public static function cartToList(Cart $basket): Collection
|
|
{
|
|
return $basket->content()->map(function (CartItem $cartItem) {
|
|
return \json_decode(\json_encode($cartItem->toArray()));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate Basket object
|
|
*
|
|
* ! This validation format should be equals to whats in
|
|
* index.d.ts bItem and also into Fo/BasketController::addToBasket
|
|
*
|
|
* ! This does report validation errors.
|
|
*
|
|
* @param object $basket
|
|
* @return boolean
|
|
*/
|
|
public static function basketObjectIsValid(object $basket): bool
|
|
{
|
|
$validator = Validator::make(\json_decode(\json_encode($basket), true), [
|
|
'rowId' => 'required|regex:/^[0-9a-z]{32}$/',
|
|
'id' => 'required|integer|min:1',
|
|
'name' => 'required|string|min:1|max:255',
|
|
'qty' => 'required|integer|min:1',
|
|
'price' => 'required|integer|min:1',
|
|
'weight' => 'required|integer|min:0',
|
|
'options.reference' => 'required|string|max:255',
|
|
'options.slug' => 'required|string|min:1|max:255',
|
|
'options.picture' => 'nullable|string|min:1|max:255',
|
|
'options.sell_unit' => 'required|string|min:1|max:255',
|
|
'options.weight_with_unit' => 'required|string|min:1|max:255',
|
|
'options.discount_type' => 'nullable|in:' . \collect(DiscountType::toValues())->implode(','),
|
|
'options.discount_rate' => 'required|numeric|min:0',
|
|
'options.price_ttc' => 'required|integer|min:1',
|
|
'options.undiscounted_price_ttc' => 'required|integer|min:1',
|
|
'options.tax_rate' => [
|
|
'required', 'numeric', Rule::in(\collect(TaxRate::toArray())
|
|
->map(function (TaxRate $taxRate) {
|
|
return $taxRate->rate;
|
|
}))
|
|
],
|
|
'discount' => 'required|integer|min:0',
|
|
'tax' => 'required|integer|min:0',
|
|
'subtotal' => 'required|integer|min:1'
|
|
]);
|
|
try {
|
|
$validator->validate();
|
|
return true;
|
|
} catch (ValidationException $e) {
|
|
\report(new \RuntimeException('Could not validate basket object ' .
|
|
\implode(',', collect($e->errors())->flatten()->all())));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get displayable price value
|
|
*
|
|
* @param mixed $value Amount in cents.
|
|
* @param string $suffix Append some text.
|
|
* @return string
|
|
*/
|
|
public static function fmtCurrency($value, string $suffix = 'TTC'): string
|
|
{
|
|
return \trim(sprintf(
|
|
'%s %s',
|
|
app('phpMoneyFormatter')->format(new Money($value, app('phpMoneyCurrency'))),
|
|
$suffix
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Get displayable price value
|
|
*
|
|
* @param mixed $value
|
|
* @return string
|
|
*/
|
|
public static function fmtSellUnit($value): string
|
|
{
|
|
return !empty($value) ? "/ {$value}" : '';
|
|
}
|
|
|
|
/**
|
|
* Generate an unique reference from model on reference column by default
|
|
*
|
|
* * The pattern is YYYYMMDDXXXXXXXXXX where X is 10 random numbers.
|
|
*
|
|
* @param string $modelClass The model to use for reference.
|
|
* @param integer $recursiveIncrement Used for internal only.
|
|
* @param string $column The column name where are stored references.
|
|
* @return string
|
|
* @throws \RuntimeException If $modelClass does not extends \Illuminate\Database\Eloquent\Model.
|
|
*/
|
|
public static function getUniqueReference(
|
|
string $modelClass,
|
|
int $recursiveIncrement = 0,
|
|
string $column = 'reference'
|
|
): string {
|
|
if (!\is_subclass_of($modelClass, Model::class)) {
|
|
throw new \RuntimeException("{$modelClass} have to extend " . Model::class);
|
|
}
|
|
/** @var \Illuminate\Database\Eloquent\Model */
|
|
$model = new $modelClass();
|
|
$counter = $model::query()->whereDate('created_at', Carbon::today())->count() + 1 + $recursiveIncrement;
|
|
$reference = Carbon::now()->isoFormat('YYYYMMDD') . str_pad(crc32(uniqid('', true)), 10, '0', STR_PAD_LEFT);
|
|
if ($model::query()->where($column, $reference)->exists()) {
|
|
// * Recursive counter to determinate reference unicity.
|
|
return self::getUniqueReference($model, $counter + 1);
|
|
}
|
|
return $reference;
|
|
}
|
|
|
|
/**
|
|
* Strip scheme (https) on oembed urls
|
|
* Only embed allowed are for MP4 self hosted videos right now
|
|
*
|
|
* https is force by ckeditor MediaElements which natively supports
|
|
* only cloud hosted medias (youtube, spotify etc..)
|
|
*
|
|
* @param string $input
|
|
* @return string
|
|
*/
|
|
public static function stripCkEditorSchemesOnMediaInputs(string $input): string
|
|
{
|
|
$input = \preg_replace('/(?<=<oembed url=")(https:\/\/)(?=.*?">)/m', '', $input);
|
|
return $input;
|
|
}
|
|
|
|
/**
|
|
* Assert That no Back Office url is present on txt
|
|
*
|
|
* @param string $field
|
|
* @param string $text
|
|
* @return string
|
|
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
|
|
*/
|
|
public static function assertNoInternalBoUrls(string $field, string $text): string
|
|
{
|
|
$routes = Route::getRoutes();
|
|
// * Url replace and email replace.
|
|
$text = preg_replace_callback(
|
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
|
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
|
|
function ($matches) use ($routes, $field) {
|
|
$match = collect($matches)->first() ?? '';
|
|
$url = $match;
|
|
try {
|
|
$request = Request::create($url);
|
|
// If a route is match then it do not throws exception.
|
|
if (
|
|
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
|
|
trim($routes->match($request)->getPrefix() ?? '', '/') === 'bo'
|
|
) {
|
|
// Removes the matched url.
|
|
throw ValidationException::withMessages([
|
|
$field => ':attribute : Il est interdit de coller une url du back office dans ce champ'
|
|
]);
|
|
}
|
|
return $match;
|
|
} catch (NotFoundHttpException $e) {
|
|
return $match;
|
|
}
|
|
},
|
|
$text
|
|
);
|
|
return $text;
|
|
}
|
|
|
|
/**
|
|
* Assert That only external url is present on txt
|
|
*
|
|
* @param string $field
|
|
* @param string $text
|
|
* @return string
|
|
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
|
|
*/
|
|
public static function assertNoInternalUrls(string $field, string $text): string
|
|
{
|
|
self::assertNoInternalBoUrls($field, $text);
|
|
$routes = Route::getRoutes();
|
|
// * Url replace and email replace.
|
|
$text = preg_replace_callback(
|
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
|
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
|
|
function ($matches) use ($routes, $field) {
|
|
$match = collect($matches)->first() ?? '';
|
|
$url = $match;
|
|
try {
|
|
$request = Request::create($url);
|
|
// If a route is match then it do not throws exception.
|
|
if (
|
|
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
|
|
$routes->match($request)
|
|
) {
|
|
// Removes the matched url.
|
|
throw ValidationException::withMessages([
|
|
$field => sprintf(
|
|
':attribute : Il est interdit de coller une url de %s dans ce champ',
|
|
config('app.name')
|
|
)
|
|
]);
|
|
}
|
|
return $match;
|
|
} catch (NotFoundHttpException $e) {
|
|
return $match;
|
|
}
|
|
},
|
|
$text
|
|
);
|
|
return $text;
|
|
}
|
|
|
|
/**
|
|
* Mutltibyte string replace
|
|
* @param mixed $search
|
|
* @param mixed $replace
|
|
* @param mixed $subject
|
|
* @param integer $count
|
|
* @return mixed
|
|
*/
|
|
public static function mbReplace($search, $replace, $subject, int &$count = 0)
|
|
{
|
|
if (!is_array($search) && is_array($replace)) {
|
|
return false;
|
|
}
|
|
if (is_array($subject)) {
|
|
// Call mb_replace for each single string in $subject .
|
|
foreach ($subject as &$string) {
|
|
$string = &self::mbReplace($search, $replace, $string, $count);
|
|
}
|
|
} elseif (is_array($search)) {
|
|
if (!is_array($replace)) {
|
|
foreach ($search as &$string) {
|
|
$subject = self::mbReplace($string, $replace, $subject, $count);
|
|
}
|
|
} else {
|
|
$n = max(count($search), count($replace));
|
|
while ($n--) {
|
|
$subject = self::mbReplace(current($search), current($replace), $subject, $count);
|
|
next($search);
|
|
next($replace);
|
|
}
|
|
}
|
|
} else {
|
|
$parts = mb_split(preg_quote($search), $subject);
|
|
$count = count($parts) - 1;
|
|
$subject = implode($replace, $parts);
|
|
} //end if
|
|
return $subject;
|
|
}
|
|
|
|
/**
|
|
* Asserts that the field is unique
|
|
*
|
|
* @param string $table
|
|
* @param string $field
|
|
* @param mixed $value
|
|
* @param integer|null $id
|
|
* @param callable|null $query
|
|
* @return void
|
|
* @throws \Illuminate\Validation\ValidationException If the field is not unique.
|
|
*/
|
|
public static function assertFieldIsUnique(
|
|
string $table,
|
|
string $field,
|
|
$value,
|
|
?int $id = null,
|
|
?callable $query = null
|
|
) {
|
|
if (!$query) {
|
|
Validator::make([$field => $value], [
|
|
self::mbReplace('.', '\.', $field) => Rule::unique($table, $field)->ignore($id),
|
|
], [
|
|
self::mbReplace('.', '\.', "{$field}.unique")
|
|
=> trans('La valeur :value pour le champ :attribute est déjà utilisé', [
|
|
'attribute' => $field,
|
|
'value' => $value
|
|
])
|
|
])->validate();
|
|
return;
|
|
}
|
|
Validator::make([$field => $value], [
|
|
$field => Rule::unique($table)->where($query)->ignore($id),
|
|
], [
|
|
$field . '.unique' => trans('La valeur pour le champ :attribute est déjà utilisé', [
|
|
'attribute' => $field
|
|
])
|
|
])->validate();
|
|
}
|
|
|
|
/**
|
|
* Generate a unique reference
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getUniqueProductReference(): string
|
|
{
|
|
\mt_srand();
|
|
$ref = Str::padLeft(\mt_rand(1, 99999999), 8, '0');
|
|
if (Product::where('reference', $ref)->count()) {
|
|
return self::getUniqueProductReference();
|
|
}
|
|
return $ref;
|
|
}
|
|
|
|
/**
|
|
* Convert deeply an object to array
|
|
*
|
|
* @param array|object $input
|
|
* @return array
|
|
* @throws \RuntimeException If $input var is a scalar value.
|
|
*/
|
|
public static function objectToArray($input): array
|
|
{
|
|
// Only process if it's an object or array being passed to the function.
|
|
if (is_object($input) or is_array($input)) {
|
|
$ret = (array)$input;
|
|
foreach ($ret as &$item) {
|
|
// Recursively process EACH element only if not scalar.
|
|
$item = (is_object($item) or is_array($item)) ?
|
|
self::objectToArray($item) : $item;
|
|
}
|
|
return $ret;
|
|
} else {
|
|
throw new \RuntimeException('cannot handle $input of type ' . \gettype($input));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert deeply an array to object
|
|
*
|
|
* @param array|object $input
|
|
* @return object
|
|
* @throws \RuntimeException If $input var is a scalar value.
|
|
*/
|
|
public static function arrayToObject($input): object
|
|
{
|
|
// Only process if it's an object or array being passed to the function.
|
|
if (is_object($input) or is_array($input)) {
|
|
$ret = (object)$input;
|
|
foreach ($ret as &$item) {
|
|
// Recursively process EACH element only if not scalar.
|
|
$item = (is_object($item) or is_array($item)) ?
|
|
self::arrayToObject($item) : $item;
|
|
}
|
|
return $ret;
|
|
} else {
|
|
throw new \RuntimeException('cannot handle $input of type ' . \gettype($input));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate recaptcha
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @param boolean $isV3
|
|
* @return void
|
|
*/
|
|
public static function validateRecaptcha(Request $request, bool $isV3 = true)
|
|
{
|
|
Validator::validate($request->all(), [
|
|
'g-recaptcha-response' => [
|
|
'required', 'string',
|
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed, Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
|
function ($attribute, $value, $fail) use ($isV3) {
|
|
try {
|
|
$response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
|
|
'secret' => config('services.google.recaptcha.private'),
|
|
'response' => \strval($value),
|
|
'remoteip' => app('clientIp')
|
|
]);
|
|
if ($e = $response->toException()) {
|
|
throw $e;
|
|
}
|
|
if ($isV3) {
|
|
if (
|
|
!$response->json('success') or
|
|
!$response->json('challenge_ts') or
|
|
Carbon::parse($response->json('challenge_ts'))->lessThan(\now('utc')->subMinutes(5)) or
|
|
$response->json('hostname') !== \parse_url(config('app.url'), \PHP_URL_HOST) or
|
|
!$response->json('score')
|
|
) {
|
|
throw new \RuntimeException();
|
|
}
|
|
if (\floatval($response->json('score')) < 0.8) {
|
|
$fail("Vous n'avez pas obtenu un score assez élevé lors de la validation du recaptcha");
|
|
}
|
|
return;
|
|
}
|
|
if (
|
|
!$response->json('success') or
|
|
!$response->json('challenge_ts') or
|
|
Carbon::parse($response->json('challenge_ts'))->lessThan(\now('utc')->subMinutes(5)) or
|
|
$response->json('hostname') !== \parse_url(config('app.url'), \PHP_URL_HOST)
|
|
) {
|
|
throw new \RuntimeException();
|
|
}
|
|
} catch (\Exception $e) {
|
|
$fail('Erreur lors de la validation du formulaire veuillez réssayer');
|
|
} //end try
|
|
}
|
|
]
|
|
], [], ['g-recaptcha-response' => 'reCaptcha']);
|
|
}
|
|
|
|
/**
|
|
* Generate Invoice
|
|
*
|
|
* @param \App\Models\Shop\Order $order
|
|
* @param \Illuminate\Support\Carbon $date
|
|
* @param string $title
|
|
* @param string $documentType
|
|
* @param object $items
|
|
* @param string $transactionReference
|
|
* @return \Mccarlosen\LaravelMpdf\LaravelMpdf
|
|
*/
|
|
public static function generateInvoice(
|
|
Order $order,
|
|
Carbon $date,
|
|
string $title,
|
|
string $documentType,
|
|
object $items,
|
|
string $transactionReference
|
|
): LaravelMpdf {
|
|
/** @var \App\Models\Site\GeneralConfig */
|
|
$config = GeneralConfig::getCached()->where('type', GeneralConfigType::global())->firstOrFail();
|
|
|
|
$additionalData = $config->data;
|
|
|
|
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdfWrapper */
|
|
$mpdf = app('laravel-mpdf');
|
|
|
|
$defaultFontConfig = (new FontVariables())->getDefaults();
|
|
$fontData = $defaultFontConfig['fontdata'];
|
|
|
|
$invoiceBasketItems = \collect($items);
|
|
|
|
/**
|
|
* 7.5pt 10px
|
|
* 9pt 12px
|
|
* 10.5pt 14px
|
|
* 12pt 16px
|
|
* 13.5pt 18px
|
|
*/
|
|
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf */
|
|
$pdf = $mpdf->loadView(
|
|
'back::documents.order-invoice',
|
|
[
|
|
'title' => $title,
|
|
'billing' => !empty($order->billing->firstname) ? $order->billing : $order->shipping,
|
|
'shipping' => $order->shipping,
|
|
'logo' => \public_path(resize($additionalData->logo->value ?? '', 'BoutiqueLogo')),
|
|
'introLines' => \collect($additionalData)->map(function (object $input, string $inputName) {
|
|
return Str::substr($inputName, 0, -1) === 'invoice_line_' ? $input->value : null;
|
|
})->filter()->all(),
|
|
'orderReference' => $order->reference,
|
|
'transactionReference' => $transactionReference,
|
|
'date' => $date,
|
|
'documentType' => $documentType,
|
|
'basket' => $invoiceBasketItems,
|
|
'totalTtc' => $invoiceBasketItems->sum('subtotal'),
|
|
'totalTaxes' => $invoiceBasketItems->sum('tax')
|
|
],
|
|
[],
|
|
[
|
|
'mode' => 'utf-8',
|
|
'format' => 'A4',
|
|
// * 10.5pt = 14px
|
|
'default_font_size' => 10.5,
|
|
'default_font' => 'roboto',
|
|
'margin_left' => 5,
|
|
'margin_right' => 5,
|
|
'margin_top' => 5,
|
|
'margin_bottom' => 5,
|
|
'margin_header' => 0,
|
|
'margin_footer' => 5,
|
|
'orientation' => 'P',
|
|
'title' => $title,
|
|
'author' => \config('app.name'),
|
|
'watermark' => '',
|
|
'show_watermark' => false,
|
|
'watermark_font' => 'sans-serif',
|
|
'display_mode' => 'fullpage',
|
|
'watermark_text_alpha' => 0.1,
|
|
'custom_font_dir' => '',
|
|
'custom_font_data' => [],
|
|
'auto_language_detection' => false,
|
|
'temp_dir' => rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR),
|
|
'pdfa' => false,
|
|
'pdfaauto' => false,
|
|
'fontdata' => $fontData + [
|
|
'roboto' => [
|
|
'R' => \resource_path('assets/fonts/bo/roboto/RobotoMono-Regular.ttf'),
|
|
'B' => \resource_path('assets/fonts/bo/roboto/RobotoMono-Bold.ttf'),
|
|
'I' => \resource_path('assets/fonts/bo/roboto/RobotoMono-Italic.ttf'),
|
|
'BI' => \resource_path('assets/fonts/bo/roboto/RobotoMono-BoldItalic.ttf')
|
|
]
|
|
]
|
|
]
|
|
);
|
|
return $pdf;
|
|
}
|
|
}
|