vendor and env first commit
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Ignition\Config;
|
||||
|
||||
use Spatie\Ignition\Contracts\ConfigManager;
|
||||
use Throwable;
|
||||
|
||||
class FileConfigManager implements ConfigManager
|
||||
{
|
||||
private const SETTINGS_FILE_NAME = '.ignition.json';
|
||||
|
||||
private string $path;
|
||||
|
||||
private string $file;
|
||||
|
||||
public function __construct(string $path = '')
|
||||
{
|
||||
$this->path = $this->initPath($path);
|
||||
$this->file = $this->initFile();
|
||||
}
|
||||
|
||||
protected function initPath(string $path): string
|
||||
{
|
||||
$path = $this->retrievePath($path);
|
||||
|
||||
if (! $this->isValidWritablePath($path)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->preparePath($path);
|
||||
}
|
||||
|
||||
protected function retrievePath(string $path): string
|
||||
{
|
||||
if ($path !== '') {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return $this->initPathFromEnvironment();
|
||||
}
|
||||
|
||||
protected function isValidWritablePath(string $path): bool
|
||||
{
|
||||
return @file_exists($path) && @is_writable($path);
|
||||
}
|
||||
|
||||
protected function preparePath(string $path): string
|
||||
{
|
||||
return rtrim($path, DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
protected function initPathFromEnvironment(): string
|
||||
{
|
||||
if (! empty($_SERVER['HOMEDRIVE']) && ! empty($_SERVER['HOMEPATH'])) {
|
||||
return $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
|
||||
}
|
||||
|
||||
if (! empty(getenv('HOME'))) {
|
||||
return getenv('HOME');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function initFile(): string
|
||||
{
|
||||
return $this->path . DIRECTORY_SEPARATOR . self::SETTINGS_FILE_NAME;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function load(): array
|
||||
{
|
||||
return $this->readFromFile();
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
protected function readFromFile(): array
|
||||
{
|
||||
if (! $this->isValidFile()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$content = (string)file_get_contents($this->file);
|
||||
$settings = json_decode($content, true) ?? [];
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
protected function isValidFile(): bool
|
||||
{
|
||||
return $this->isValidPath() &&
|
||||
@file_exists($this->file) &&
|
||||
@is_writable($this->file);
|
||||
}
|
||||
|
||||
protected function isValidPath(): bool
|
||||
{
|
||||
return trim($this->path) !== '';
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function save(array $options): bool
|
||||
{
|
||||
if (! $this->createFile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->saveToFile($options);
|
||||
}
|
||||
|
||||
protected function createFile(): bool
|
||||
{
|
||||
if (! $this->isValidPath()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@file_exists($this->file)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (file_put_contents($this->file, '') !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function saveToFile(array $options): bool
|
||||
{
|
||||
try {
|
||||
$content = json_encode($options, JSON_THROW_ON_ERROR);
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->writeToFile($content);
|
||||
}
|
||||
|
||||
protected function writeToFile(string $content): bool
|
||||
{
|
||||
if (! $this->isValidFile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (file_put_contents($this->file, $content) !== false);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getPersistentInfo(): array
|
||||
{
|
||||
return [
|
||||
'name' => self::SETTINGS_FILE_NAME,
|
||||
'path' => $this->path,
|
||||
'file' => $this->file,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Ignition\Config;
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Spatie\Ignition\Contracts\ConfigManager;
|
||||
use Throwable;
|
||||
|
||||
/** @implements Arrayable<string, string|null|bool|array<string, mixed>> */
|
||||
class IgnitionConfig implements Arrayable
|
||||
{
|
||||
private ConfigManager $manager;
|
||||
|
||||
public static function loadFromConfigFile(): self
|
||||
{
|
||||
return (new self())->loadConfigFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
public function __construct(protected array $options = [])
|
||||
{
|
||||
$defaultOptions = $this->getDefaultOptions();
|
||||
|
||||
$this->options = array_merge($defaultOptions, $options);
|
||||
$this->manager = $this->initConfigManager();
|
||||
}
|
||||
|
||||
public function setOption(string $name, string $value): self
|
||||
{
|
||||
$this->options[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function initConfigManager(): ConfigManager
|
||||
{
|
||||
try {
|
||||
/** @phpstan-ignore-next-line */
|
||||
return app(ConfigManager::class);
|
||||
} catch (Throwable) {
|
||||
return new FileConfigManager();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param array<string, string> $options */
|
||||
public function merge(array $options): self
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function loadConfigFile(): self
|
||||
{
|
||||
$this->merge($this->getConfigOptions());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function getConfigOptions(): array
|
||||
{
|
||||
return $this->manager->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
* @return bool
|
||||
*/
|
||||
public function saveValues(array $options): bool
|
||||
{
|
||||
return $this->manager->save($options);
|
||||
}
|
||||
|
||||
public function hideSolutions(): bool
|
||||
{
|
||||
return $this->options['hide_solutions'] ?? false;
|
||||
}
|
||||
|
||||
public function editor(): ?string
|
||||
{
|
||||
return $this->options['editor'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed> $options
|
||||
*/
|
||||
public function editorOptions(): array
|
||||
{
|
||||
return $this->options['editor_options'] ?? [];
|
||||
}
|
||||
|
||||
public function remoteSitesPath(): ?string
|
||||
{
|
||||
return $this->options['remote_sites_path'] ?? null;
|
||||
}
|
||||
|
||||
public function localSitesPath(): ?string
|
||||
{
|
||||
return $this->options['local_sites_path'] ?? null;
|
||||
}
|
||||
|
||||
public function theme(): ?string
|
||||
{
|
||||
return $this->options['theme'] ?? null;
|
||||
}
|
||||
|
||||
public function shareButtonEnabled(): bool
|
||||
{
|
||||
return (bool)($this->options['enable_share_button'] ?? false);
|
||||
}
|
||||
|
||||
public function shareEndpoint(): string
|
||||
{
|
||||
return $this->options['share_endpoint']
|
||||
?? $this->getDefaultOptions()['share_endpoint'];
|
||||
}
|
||||
|
||||
public function runnableSolutionsEnabled(): bool
|
||||
{
|
||||
return (bool)($this->options['enable_runnable_solutions'] ?? false);
|
||||
}
|
||||
|
||||
/** @return array<string, string|null|bool|array<string, mixed>> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'editor' => $this->editor(),
|
||||
'theme' => $this->theme(),
|
||||
'hideSolutions' => $this->hideSolutions(),
|
||||
'remoteSitesPath' => $this->remoteSitesPath(),
|
||||
'localSitesPath' => $this->localSitesPath(),
|
||||
'enableShareButton' => $this->shareButtonEnabled(),
|
||||
'enableRunnableSolutions' => $this->runnableSolutionsEnabled(),
|
||||
'directorySeparator' => DIRECTORY_SEPARATOR,
|
||||
'editorOptions' => $this->editorOptions(),
|
||||
'shareEndpoint' => $this->shareEndpoint(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed> $options
|
||||
*/
|
||||
protected function getDefaultOptions(): array
|
||||
{
|
||||
return [
|
||||
'share_endpoint' => 'https://flareapp.io/api/public-reports',
|
||||
'theme' => 'light',
|
||||
'editor' => 'vscode',
|
||||
'editor_options' => [
|
||||
'clipboard' => [
|
||||
'label' => 'Clipboard',
|
||||
'url' => '%path:%line',
|
||||
'clipboard' => true,
|
||||
],
|
||||
'sublime' => [
|
||||
'label' => 'Sublime',
|
||||
'url' => 'subl://open?url=file://%path&line=%line',
|
||||
],
|
||||
'textmate' => [
|
||||
'label' => 'TextMate',
|
||||
'url' => 'txmt://open?url=file://%path&line=%line',
|
||||
],
|
||||
'emacs' => [
|
||||
'label' => 'Emacs',
|
||||
'url' => 'emacs://open?url=file://%path&line=%line',
|
||||
],
|
||||
'macvim' => [
|
||||
'label' => 'MacVim',
|
||||
'url' => 'mvim://open/?url=file://%path&line=%line',
|
||||
],
|
||||
'phpstorm' => [
|
||||
'label' => 'PhpStorm',
|
||||
'url' => 'phpstorm://open?file=%path&line=%line',
|
||||
],
|
||||
'phpstorm-remote' => [
|
||||
'label' => 'PHPStorm Remote',
|
||||
'url' => 'javascript:r = new XMLHttpRequest;r.open("get", "http://localhost:63342/api/file/%path:%line");r.send()',
|
||||
],
|
||||
'idea' => [
|
||||
'label' => 'Idea',
|
||||
'url' => 'idea://open?file=%path&line=%line',
|
||||
],
|
||||
'vscode' => [
|
||||
'label' => 'VS Code',
|
||||
'url' => 'vscode://file/%path:%line',
|
||||
],
|
||||
'vscode-insiders' => [
|
||||
'label' => 'VS Code Insiders',
|
||||
'url' => 'vscode-insiders://file/%path:%line',
|
||||
],
|
||||
'vscode-remote' => [
|
||||
'label' => 'VS Code Remote',
|
||||
'url' => 'vscode://vscode-remote/%path:%line',
|
||||
],
|
||||
'vscode-insiders-remote' => [
|
||||
'label' => 'VS Code Insiders Remote',
|
||||
'url' => 'vscode-insiders://vscode-remote/%path:%line',
|
||||
],
|
||||
'vscodium' => [
|
||||
'label' => 'VS Codium',
|
||||
'url' => 'vscodium://file/%path:%line',
|
||||
],
|
||||
'cursor' => [
|
||||
'label' => 'Cursor',
|
||||
'url' => 'cursor://file/%path:%line',
|
||||
],
|
||||
'atom' => [
|
||||
'label' => 'Atom',
|
||||
'url' => 'atom://core/open/file?filename=%path&line=%line',
|
||||
],
|
||||
'nova' => [
|
||||
'label' => 'Nova',
|
||||
'url' => 'nova://open?path=%path&line=%line',
|
||||
],
|
||||
'netbeans' => [
|
||||
'label' => 'NetBeans',
|
||||
'url' => 'netbeans://open/?f=%path:%line',
|
||||
],
|
||||
'xdebug' => [
|
||||
'label' => 'Xdebug',
|
||||
'url' => 'xdebug://%path@%line',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Ignition\Contracts;
|
||||
|
||||
interface ConfigManager
|
||||
{
|
||||
/** @return array<string, mixed> */
|
||||
public function load(): array;
|
||||
|
||||
/** @param array<string, mixed> $options */
|
||||
public function save(array $options): bool;
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function getPersistentInfo(): array;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Ignition\ErrorPage;
|
||||
|
||||
use Spatie\ErrorSolutions\Contracts\Solution;
|
||||
use Spatie\ErrorSolutions\Solutions\SolutionTransformer;
|
||||
use Spatie\FlareClient\Report;
|
||||
use Spatie\FlareClient\Truncation\ReportTrimmer;
|
||||
use Spatie\Ignition\Config\IgnitionConfig;
|
||||
use Throwable;
|
||||
|
||||
class ErrorPageViewModel
|
||||
{
|
||||
/**
|
||||
* @param \Throwable|null $throwable
|
||||
* @param \Spatie\Ignition\Config\IgnitionConfig $ignitionConfig
|
||||
* @param \Spatie\FlareClient\Report $report
|
||||
* @param array<int, Solution> $solutions
|
||||
* @param string|null $solutionTransformerClass
|
||||
*/
|
||||
public function __construct(
|
||||
protected ?Throwable $throwable,
|
||||
protected IgnitionConfig $ignitionConfig,
|
||||
protected Report $report,
|
||||
protected array $solutions,
|
||||
protected ?string $solutionTransformerClass = null,
|
||||
protected string $customHtmlHead = '',
|
||||
protected string $customHtmlBody = ''
|
||||
) {
|
||||
$this->solutionTransformerClass ??= SolutionTransformer::class;
|
||||
}
|
||||
|
||||
public function throwableString(): string
|
||||
{
|
||||
if (! $this->throwable) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$throwableString = sprintf(
|
||||
"%s: %s in file %s on line %d\n\n%s\n",
|
||||
get_class($this->throwable),
|
||||
$this->throwable->getMessage(),
|
||||
$this->throwable->getFile(),
|
||||
$this->throwable->getLine(),
|
||||
$this->report->getThrowable()?->getTraceAsString()
|
||||
);
|
||||
|
||||
return htmlspecialchars($throwableString);
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return htmlspecialchars($this->report->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function config(): array
|
||||
{
|
||||
return $this->ignitionConfig->toArray();
|
||||
}
|
||||
|
||||
public function theme(): string
|
||||
{
|
||||
return $this->config()['theme'] ?? 'auto';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, mixed>
|
||||
*/
|
||||
public function solutions(): array
|
||||
{
|
||||
return array_map(function (Solution $solution) {
|
||||
/** @var class-string $transformerClass */
|
||||
$transformerClass = $this->solutionTransformerClass;
|
||||
|
||||
/** @var SolutionTransformer $transformer */
|
||||
$transformer = new $transformerClass($solution);
|
||||
|
||||
return ($transformer)->toArray();
|
||||
}, $this->solutions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function report(): array
|
||||
{
|
||||
return $this->report->toArray();
|
||||
}
|
||||
|
||||
public function jsonEncode(mixed $data): string
|
||||
{
|
||||
$jsonOptions = JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT;
|
||||
|
||||
return (string) json_encode($data, $jsonOptions);
|
||||
}
|
||||
|
||||
public function getAssetContents(string $asset): string
|
||||
{
|
||||
$assetPath = __DIR__."/../../resources/compiled/{$asset}";
|
||||
|
||||
return (string) file_get_contents($assetPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int|string, mixed>
|
||||
*/
|
||||
public function shareableReport(): array
|
||||
{
|
||||
return (new ReportTrimmer())->trim($this->report());
|
||||
}
|
||||
|
||||
public function updateConfigEndpoint(): string
|
||||
{
|
||||
// TODO: Should be based on Ignition config
|
||||
return '/_ignition/update-config';
|
||||
}
|
||||
|
||||
public function customHtmlHead(): string
|
||||
{
|
||||
return $this->customHtmlHead;
|
||||
}
|
||||
|
||||
public function customHtmlBody(): string
|
||||
{
|
||||
return $this->customHtmlBody;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Ignition\ErrorPage;
|
||||
|
||||
class Renderer
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render(array $data, string $viewPath): void
|
||||
{
|
||||
$viewFile = $viewPath;
|
||||
|
||||
extract($data, EXTR_OVERWRITE);
|
||||
|
||||
include $viewFile;
|
||||
}
|
||||
|
||||
public function renderAsString(array $date, string $viewPath): string
|
||||
{
|
||||
ob_start();
|
||||
|
||||
$this->render($date, $viewPath);
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Ignition;
|
||||
|
||||
use ArrayObject;
|
||||
use ErrorException;
|
||||
use Spatie\ErrorSolutions\Contracts\HasSolutionsForThrowable;
|
||||
use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository as SolutionProviderRepositoryContract;
|
||||
use Spatie\ErrorSolutions\SolutionProviderRepository;
|
||||
use Spatie\ErrorSolutions\SolutionProviders\BadMethodCallSolutionProvider;
|
||||
use Spatie\ErrorSolutions\SolutionProviders\MergeConflictSolutionProvider;
|
||||
use Spatie\ErrorSolutions\SolutionProviders\UndefinedPropertySolutionProvider;
|
||||
use Spatie\FlareClient\Context\BaseContextProviderDetector;
|
||||
use Spatie\FlareClient\Context\ContextProviderDetector;
|
||||
use Spatie\FlareClient\Enums\MessageLevels;
|
||||
use Spatie\FlareClient\Flare;
|
||||
use Spatie\FlareClient\FlareMiddleware\AddDocumentationLinks;
|
||||
use Spatie\FlareClient\FlareMiddleware\AddSolutions;
|
||||
use Spatie\FlareClient\FlareMiddleware\FlareMiddleware;
|
||||
use Spatie\FlareClient\Report;
|
||||
use Spatie\Ignition\Config\IgnitionConfig;
|
||||
use Spatie\Ignition\ErrorPage\ErrorPageViewModel;
|
||||
use Spatie\Ignition\ErrorPage\Renderer;
|
||||
use Throwable;
|
||||
|
||||
class Ignition
|
||||
{
|
||||
protected Flare $flare;
|
||||
|
||||
protected bool $shouldDisplayException = true;
|
||||
|
||||
protected string $flareApiKey = '';
|
||||
|
||||
protected string $applicationPath = '';
|
||||
|
||||
/** @var array<int, FlareMiddleware> */
|
||||
protected array $middleware = [];
|
||||
|
||||
protected IgnitionConfig $ignitionConfig;
|
||||
|
||||
protected ContextProviderDetector $contextProviderDetector;
|
||||
|
||||
protected SolutionProviderRepositoryContract $solutionProviderRepository;
|
||||
|
||||
protected ?bool $inProductionEnvironment = null;
|
||||
|
||||
protected ?string $solutionTransformerClass = null;
|
||||
|
||||
/** @var ArrayObject<int, callable(Throwable): mixed> */
|
||||
protected ArrayObject $documentationLinkResolvers;
|
||||
|
||||
protected string $customHtmlHead = '';
|
||||
|
||||
protected string $customHtmlBody = '';
|
||||
|
||||
public static function make(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
?Flare $flare = null,
|
||||
) {
|
||||
$this->flare = $flare ?? Flare::make();
|
||||
|
||||
$this->ignitionConfig = IgnitionConfig::loadFromConfigFile();
|
||||
|
||||
$this->solutionProviderRepository = new SolutionProviderRepository($this->getDefaultSolutionProviders());
|
||||
|
||||
$this->documentationLinkResolvers = new ArrayObject();
|
||||
|
||||
$this->contextProviderDetector = new BaseContextProviderDetector();
|
||||
|
||||
$this->middleware[] = new AddSolutions($this->solutionProviderRepository);
|
||||
$this->middleware[] = new AddDocumentationLinks($this->documentationLinkResolvers);
|
||||
}
|
||||
|
||||
public function setSolutionTransformerClass(string $solutionTransformerClass): self
|
||||
{
|
||||
$this->solutionTransformerClass = $solutionTransformerClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @param callable(Throwable): mixed $callable */
|
||||
public function resolveDocumentationLink(callable $callable): self
|
||||
{
|
||||
$this->documentationLinkResolvers[] = $callable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setConfig(IgnitionConfig $ignitionConfig): self
|
||||
{
|
||||
$this->ignitionConfig = $ignitionConfig;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function runningInProductionEnvironment(bool $boolean = true): self
|
||||
{
|
||||
$this->inProductionEnvironment = $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFlare(): Flare
|
||||
{
|
||||
return $this->flare;
|
||||
}
|
||||
|
||||
public function setFlare(Flare $flare): self
|
||||
{
|
||||
$this->flare = $flare;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSolutionProviderRepository(SolutionProviderRepositoryContract $solutionProviderRepository): self
|
||||
{
|
||||
$this->solutionProviderRepository = $solutionProviderRepository;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function shouldDisplayException(bool $shouldDisplayException): self
|
||||
{
|
||||
$this->shouldDisplayException = $shouldDisplayException;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function applicationPath(string $applicationPath): self
|
||||
{
|
||||
$this->applicationPath = $applicationPath;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $messageLevel
|
||||
* @param array<int, mixed> $metaData
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function glow(
|
||||
string $name,
|
||||
string $messageLevel = MessageLevels::INFO,
|
||||
array $metaData = []
|
||||
): self {
|
||||
$this->flare->glow($name, $messageLevel, $metaData);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, HasSolutionsForThrowable|class-string<HasSolutionsForThrowable>> $solutionProviders
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addSolutionProviders(array $solutionProviders): self
|
||||
{
|
||||
$this->solutionProviderRepository->registerSolutionProviders($solutionProviders);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @deprecated Use `setTheme('dark')` instead */
|
||||
public function useDarkMode(): self
|
||||
{
|
||||
return $this->setTheme('dark');
|
||||
}
|
||||
|
||||
/** @deprecated Use `setTheme($theme)` instead */
|
||||
public function theme(string $theme): self
|
||||
{
|
||||
return $this->setTheme($theme);
|
||||
}
|
||||
|
||||
public function setTheme(string $theme): self
|
||||
{
|
||||
$this->ignitionConfig->setOption('theme', $theme);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEditor(string $editor): self
|
||||
{
|
||||
$this->ignitionConfig->setOption('editor', $editor);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function sendToFlare(?string $apiKey): self
|
||||
{
|
||||
$this->flareApiKey = $apiKey ?? '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function configureFlare(callable $callable): self
|
||||
{
|
||||
($callable)($this->flare);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FlareMiddleware|array<int, FlareMiddleware> $middleware
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function registerMiddleware(array|FlareMiddleware $middleware): self
|
||||
{
|
||||
if (! is_array($middleware)) {
|
||||
$middleware = [$middleware];
|
||||
}
|
||||
|
||||
foreach ($middleware as $singleMiddleware) {
|
||||
$this->middleware = array_merge($this->middleware, $middleware);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setContextProviderDetector(ContextProviderDetector $contextProviderDetector): self
|
||||
{
|
||||
$this->contextProviderDetector = $contextProviderDetector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function reset(): self
|
||||
{
|
||||
$this->flare->reset();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function register(?int $errorLevels = null): self
|
||||
{
|
||||
error_reporting($errorLevels ?? -1);
|
||||
|
||||
$errorLevels
|
||||
? set_error_handler([$this, 'renderError'], $errorLevels)
|
||||
: set_error_handler([$this, 'renderError']);
|
||||
|
||||
set_exception_handler([$this, 'handleException']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
* @param string $message
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
* @param array<int, mixed> $context
|
||||
*
|
||||
* @return void
|
||||
* @throws \ErrorException
|
||||
*/
|
||||
public function renderError(
|
||||
int $level,
|
||||
string $message,
|
||||
string $file = '',
|
||||
int $line = 0,
|
||||
array $context = []
|
||||
): void {
|
||||
if(error_reporting() === (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE)) {
|
||||
// This happens when PHP version is >=8 and we caught an error that was suppressed with the "@" operator
|
||||
// See the first warning box in https://www.php.net/manual/en/language.operators.errorcontrol.php
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ErrorException($message, 0, $level, $file, $line);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main entry point for the framework agnostic Ignition package.
|
||||
* Displays the Ignition page and optionally sends a report to Flare.
|
||||
*/
|
||||
public function handleException(Throwable $throwable): Report
|
||||
{
|
||||
$this->setUpFlare();
|
||||
|
||||
$report = $this->createReport($throwable);
|
||||
|
||||
if ($this->shouldDisplayException && $this->inProductionEnvironment !== true) {
|
||||
$this->renderException($throwable, $report);
|
||||
}
|
||||
|
||||
if ($this->flare->apiTokenSet() && $this->inProductionEnvironment !== false) {
|
||||
$this->flare->report($throwable, report: $report);
|
||||
}
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main entrypoint for laravel-ignition. It only renders the exception.
|
||||
* Sending the report to Flare is handled in the laravel-ignition log handler.
|
||||
*/
|
||||
public function renderException(Throwable $throwable, ?Report $report = null): void
|
||||
{
|
||||
$this->setUpFlare();
|
||||
|
||||
$report ??= $this->createReport($throwable);
|
||||
|
||||
$viewModel = new ErrorPageViewModel(
|
||||
$throwable,
|
||||
$this->ignitionConfig,
|
||||
$report,
|
||||
$this->solutionProviderRepository->getSolutionsForThrowable($throwable),
|
||||
$this->solutionTransformerClass,
|
||||
$this->customHtmlHead,
|
||||
$this->customHtmlBody,
|
||||
);
|
||||
|
||||
(new Renderer())->render(['viewModel' => $viewModel], self::viewPath('errorPage'));
|
||||
}
|
||||
|
||||
public static function viewPath(string $viewName): string
|
||||
{
|
||||
return __DIR__ . "/../resources/views/{$viewName}.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom HTML which will be added to the head tag of the error page.
|
||||
*/
|
||||
public function addCustomHtmlToHead(string $html): self
|
||||
{
|
||||
$this->customHtmlHead .= $html;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom HTML which will be added to the body tag of the error page.
|
||||
*/
|
||||
public function addCustomHtmlToBody(string $html): self
|
||||
{
|
||||
$this->customHtmlBody .= $html;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setUpFlare(): self
|
||||
{
|
||||
if (! $this->flare->apiTokenSet()) {
|
||||
$this->flare->setApiToken($this->flareApiKey ?? '');
|
||||
}
|
||||
|
||||
$this->flare->setContextProviderDetector($this->contextProviderDetector);
|
||||
|
||||
foreach ($this->middleware as $singleMiddleware) {
|
||||
$this->flare->registerMiddleware($singleMiddleware);
|
||||
}
|
||||
|
||||
if ($this->applicationPath !== '') {
|
||||
$this->flare->applicationPath($this->applicationPath);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return array<class-string<HasSolutionsForThrowable>> */
|
||||
protected function getDefaultSolutionProviders(): array
|
||||
{
|
||||
return [
|
||||
BadMethodCallSolutionProvider::class,
|
||||
MergeConflictSolutionProvider::class,
|
||||
UndefinedPropertySolutionProvider::class,
|
||||
];
|
||||
}
|
||||
|
||||
protected function createReport(Throwable $throwable): Report
|
||||
{
|
||||
return $this->flare->createReport($throwable);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user