Skip to content

Commit

Permalink
Add custom exceptions instead of using Runtimeexception everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
Sander De la Marche committed May 3, 2022
1 parent 4b51783 commit 3f35c43
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 37 deletions.
25 changes: 7 additions & 18 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,31 @@ Each Jug project follows this structure:
|-- output/ # Your generated site
|-- source/ # Your site's source files
| |-- _templates/ # Templates, includes & macros. These files are not built as pages
| `-- assets/ # Images, stylesheets, scripts, ...
|-- translations/ # Optional: if you're building a multi-language site
|-- config.php # Configuration
|-- events.php # Optional: Pre and post build event handling
`-- composer.json # Dependencies
```
Jug expects two mandatory configuration options in your `config.php`: `source` and `output`. These are the two names of your source and output folders.

When you run the build or serve command, Jug will scan and build each Twig template inside the source folder and place the generated HTML in the output folder.
When you run the build or serve command, Jug will scan and build each Twig template inside the source folder and dump the generated HTML in the output folder.

You can then [deploy](deploying.md) the content of the output folder to any host you like.

## Installation

There are two ways to start a new Jug project:
1. Require Jug through Composer and create all the required folders and files yourself.
To start a new Jug site, create your folder, require the package through Composer and run the `init` command.
```
mkdir my-new-project
cd my-new-project
mkdir my-new-site
cd my-new-site
composer require dreadnip/jug
mkdir output
mkdir source/_templates
touch config.php
vi config.php (enter correct configuration, see below)
./vendor/bin/jug serve
```
2. Use the skeleton project to get started more quickly
```
composer create-project dreadnip/jug-skeleton my-new-project
cd my-new-project
./vendor/bin/jug serve
./vendor/bin/jug init
```

## Commands

* `./vendor/bin/jug build` builds the site, once.
* `./vendor/bin/jug serve` launches the PHP built-in webserver and watches all files in the source folder for changes. The site will be rebuilt on every change.
* `./vendor/bin/jug init` generate a blank project skeleton.

## Configuration

Expand Down
4 changes: 2 additions & 2 deletions src/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Jug\Config;

use RuntimeException;
use Jug\Exception\ConfigException;

class Config
{
Expand All @@ -24,7 +24,7 @@ public function has(string $key): bool
public function get(string $key): mixed
{
if (!array_key_exists($key, $this->values)) {
throw new RuntimeException('Attempted to read config value for key: ' . $key . ', but it doesn\'t exist');
throw ConfigException::missingKey($key);
}

return $this->values[$key];
Expand Down
94 changes: 94 additions & 0 deletions src/Exception/ConfigException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

declare(strict_types=1);

namespace Jug\Exception;

use Exception;

class ConfigException extends Exception
{
public static function missingFile(): self
{
return new self('Couldn\'t find a config.php file in your project.');
}

public static function missingKey(
string $key,
): self {
return new self(sprintf(
'Missing required config key "%s".',
$key
));
}

public static function missingPropertyTypeHint(
string $propertyName,
string $className,
): self {
return new self(sprintf(
'Missing type hint for property "%s" on class "%s".',
$propertyName,
$className
));
}

public static function missingMethod(
string $methodName,
string $className,
): self {
return new self(sprintf(
'Missing method "%s" on class "%s".',
$methodName,
$className
));
}

/**
* @param array<string> $classes
*/
public static function missingAttribute(
string $attributeName,
array $classes
): self {
return new self(sprintf(
'Missing attribute "%s" on classes: "%s"',
$attributeName,
implode(',', $classes)
));
}

public static function nonExistentClass(
string $className,
): self {
return new self(sprintf(
'Class "%s" does not exist.',
$className
));
}

public static function missingAbstractExtend(
string $className,
): self {
return new self(sprintf(
'Class "%s" does not extend the AbstractDataTransferObject class.',
$className
));
}

public static function mappedClassMismatch(
string $mappedClassName,
string $passedClassname,
): self {
return new self(sprintf(
'Passed object "%s" is not the same class as configured by the MapsTo attribute (%s)',
$passedClassname,
$mappedClassName
));
}

public static function updateWithoutSource(): self
{
return new self('Running an update without passing a source entity is invalid.');
}
}
28 changes: 28 additions & 0 deletions src/Exception/FileSystemException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Jug\Exception;

use Exception;

class FileSystemException extends Exception
{
public static function missingFile(
string $fileName
): self {
return new self(sprintf(
'Missing file: "%s".',
$fileName
));
}

public static function missingDirectory(
string $directoryName
): self {
return new self(sprintf(
'Missing directory: %s',
$directoryName,
));
}
}
4 changes: 2 additions & 2 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use DOMElement;
use Jug\Event\AfterBuild;
use Jug\Event\BeforeBuild;
use RuntimeException;
use Jug\Exception\ConfigException;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Filesystem\Filesystem;
Expand Down Expand Up @@ -101,7 +101,7 @@ private function setLocale(string $locale): void
private function compressImages(string $imageFolder): void
{
if (!$this->site->getConfig()->has('image_cache')) {
throw new RuntimeException('Missing required config option: image_cache.');
throw ConfigException::missingKey('image_cache');
}

$imageCacheFile = $this->site->getConfig()->getString('image_cache');
Expand Down
13 changes: 8 additions & 5 deletions src/Kernel.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<?php

declare(strict_types=1);

namespace Jug;

use Jug\Config\Config;
use Jug\Exception\ConfigException;
use Jug\Exception\FileSystemException;
use Jug\Twig\AssetExtension;
use Jug\Twig\DynamicFilesystemLoader;
use Jug\Twig\FolderExtension;
use Jug\Twig\HighlightExtension;
use Jug\Twig\MarkdownExtension;
use Jug\Twig\SqliteExtension;
use Michelf\Markdown;
use RuntimeException;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Filesystem\Filesystem;
Expand All @@ -29,7 +32,7 @@ public function buildGenerator(): Generator
{
// Config
if (!is_file('config.php')) {
throw new RuntimeException('Missing required config file in project root: config.php');
throw FileSystemException::missingFile('config.php');
}

$config = require 'config.php';
Expand All @@ -40,7 +43,7 @@ public function buildGenerator(): Generator
!$config->has('source') ||
!$config->has('output')
) {
throw new RuntimeException('Missing required config values: source & output');
ConfigException::missingKey('source & output');
}

$sourceFolder = $config->getString('source');
Expand All @@ -50,7 +53,7 @@ public function buildGenerator(): Generator
!$this->filesystem->exists($sourceFolder) ||
!$this->filesystem->exists($templateFolder)
) {
throw new RuntimeException('Missing required folder in source folder: _templates');
throw FileSystemException::missingDirectory('_templates');
}

// Twig
Expand All @@ -65,7 +68,7 @@ public function buildGenerator(): Generator

// Translations
if (!$config->has('default_locale')) {
throw new RuntimeException('Missing required config option: default_locale.');
throw ConfigException::missingKey('default_locale.');
}

$translator = new Translator($config->getString('default_locale'));
Expand Down
3 changes: 2 additions & 1 deletion src/Twig/AssetExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Jug\Twig;

use Jug\Config\Config;
use Jug\Exception\ConfigException;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

Expand All @@ -23,7 +24,7 @@ public function getFunctions(): array
public function addHash(string $path): string
{
if (!$this->config->has('hash')) {
throw new \RuntimeException('Provide a valid hash in your config before using the asset function.');
throw ConfigException::missingKey('hash');
}

$extension = pathinfo($path, PATHINFO_EXTENSION);
Expand Down
3 changes: 2 additions & 1 deletion src/Twig/SqliteExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Jug\Twig;

use Jug\Exception\FileSystemException;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

Expand All @@ -20,7 +21,7 @@ public function getFunctions(): array
public function loadData(string $databaseFile, string $query): ?array
{
if (!file_exists($databaseFile)) {
throw new \RuntimeException($databaseFile . ' does not exist.');
throw FileSystemException::missingFile($databaseFile);
}

$database = new \PDO("sqlite:$databaseFile");
Expand Down
6 changes: 0 additions & 6 deletions tests/BaseFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Jug\Twig\SqliteExtension;
use Michelf\Markdown;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Filesystem\Filesystem;
Expand Down Expand Up @@ -46,11 +45,6 @@ protected function setUp(): void
$twig->addGlobal($key, $value);
}

// Translations
if (!$config->has('default_locale')) {
throw new RuntimeException('Missing required config option: default_locale.');
}

$translator = new Translator($config->getString('default_locale'));
$translator->addLoader('yaml', new YamlFileLoader());

Expand Down
4 changes: 2 additions & 2 deletions tests/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

use DateTime;
use Jug\Config\Config;
use Jug\Exception\ConfigException;
use PHPUnit\Framework\TestCase;
use RuntimeException;

class ConfigTest extends TestCase
{
Expand Down Expand Up @@ -34,7 +34,7 @@ public function testHas(): void

public function testGetThatDoesNotExist(): void
{
$this->expectException(RuntimeException::class);
$this->expectException(ConfigException::class);

$this->fixture->get('foo');
}
Expand Down

0 comments on commit 3f35c43

Please sign in to comment.