Skip to content

Commit

Permalink
refactor: extract syntax parsing into new class
Browse files Browse the repository at this point in the history
This also adds full test coverage and injects the logger as a PSR-3
interface.

Unfortunately, we have to commit the entire vendor directory as DokuWiki
currently does not allow installing plugins via composer (yet). Maybe it
will come day via implementing dokuwiki/dokuwiki#1757
  • Loading branch information
micgro42 committed Mar 20, 2021
1 parent d0c6c8a commit 22faa2c
Show file tree
Hide file tree
Showing 19 changed files with 2,041 additions and 58 deletions.
77 changes: 77 additions & 0 deletions _test/unit/SyntaxHandlerTest.php
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace dokuwiki\plugin\yearbox\test\unit;

use dokuwiki\plugin\yearbox\src\SyntaxHandler;
use Generator;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

/**
* @group plugin_yearbox
* @group plugins
*/
final class SyntaxHandlerTest extends TestCase
{

public function syntaxProvider(): Generator
{
yield 'year' => [ '{{yearbox>year=2010}}', [ 'year' => '2010'] ];
yield 'ns' => [ '{{yearbox>ns=journal}}', [ 'ns' => ':journal'] ];
yield 'ns with colon' => [ '{{yearbox>ns=foo:bar}}', [ 'ns' => 'foo:bar'] ];
yield 'name' => ['{{yearbox>name=entry}}', ['name' => 'entry']];
yield 'size' => ['{{yearbox>size=12}}', ['size' => '12']];
yield 'fontsize' => ['{{yearbox>fontsize=12}}', ['size' => '12']];
yield 'recent' => ['{{yearbox>recent=5}}', ['recent' => 5]];
yield 'recent less than 0' => ['{{yearbox>recent=-5}}', ['recent' => 0]];
yield 'months' => ['{{yearbox>months=foo,bar,baz}}', ['months' => ['foo','bar','baz']]];
yield 'weekdays' => ['{{yearbox>weekdays=foo,bar,baz}}', ['weekdays' => ['foo','bar','baz']]];
yield 'align left' => ['{{yearbox>align=left}}', ['align' => 'left']];
yield 'align right' => ['{{yearbox>align=right}}', ['align' => 'right']];
yield 'align invalid' => ['{{yearbox>align=invalid}}', []];
}

/**
* @dataProvider syntaxProvider
*/
public function testHandle(string $testSyntax, array $optOverrides): void
{
$handler = new SyntaxHandler($this->createStub(LoggerInterface::class));
$expectedOpts = array_merge(
$this->getDefaultOpts(),
$optOverrides
);

$actualOpts = $handler->handle($testSyntax);

self::assertSame($expectedOpts, $actualOpts);
}

public function testUnknownKey(): void {
$loggerMock = $this->createMock(LoggerInterface::class);
$handler = new SyntaxHandler($loggerMock);
$loggerMock
->expects(self::once())
->method('warning')
->with("Yearbox Plugin: Unknown key 'foo' in '{{yearbox>foo=bar}}'");

$actualOpts = $handler->handle('{{yearbox>foo=bar}}');

self::assertSame($this->getDefaultOpts(), $actualOpts);
}

private function getDefaultOpts(): array {
return [
'ns' => '',
'size' => 12,
'name' => 'day',
'year' => date('Y'),
'recent' => false,
'months' => [],
'weekdays' => [],
'align' => '',
];
}
}
10 changes: 10 additions & 0 deletions composer.json
@@ -0,0 +1,10 @@
{
"require": {
"php": "^7.2|^8.0",
"psr/log": "dev-master"
},
"require-dev": {
"roave/security-advisories": "dev-latest"
},
"description": "DokuWiki plugin yearbox"
}
407 changes: 407 additions & 0 deletions composer.lock

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions src/PSR3CoreLogger.php
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace dokuwiki\plugin\yearbox\src;

use dokuwiki\Logger;
use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;

final class PSR3CoreLogger extends AbstractLogger
{
public function log($level, $message, array $context = []): void
{
// PSR-3 states that $message should be a string
$message = (string)$message;

switch ($level) {
case LogLevel::EMERGENCY:
case LogLevel::ALERT:
case LogLevel::CRITICAL:
case LogLevel::ERROR:
$this->logDokuWikiSeverity(Logger::LOG_ERROR, $message, $context);
break;
case LogLevel::WARNING:
$this->logDokuWikiSeverity(LogLevel::WARNING, $message, $context);
break;
case LogLevel::NOTICE:
$this->logDokuWikiSeverity(LogLevel::NOTICE, $message, $context);
break;
case LogLevel::INFO:
$this->logDokuWikiSeverity(LogLevel::INFO, $message, $context);
break;
case LogLevel::DEBUG:
$this->logDokuWikiSeverity(Logger::LOG_DEBUG, $message, $context);
break;
default:
// PSR-3 states that we must throw a
// PsrLogInvalidArgumentException if we don't
// recognize the level
throw new InvalidArgumentException(
'Unknown severity level'
);
}
}

private function logDokuWikiSeverity($level, $message, array $context): void
{
if (!class_exists(Logger::class)) {
if ($context) {
$message .= "\n" . json_encode($context, JSON_PRETTY_PRINT);
}
dbglog($message, $level);
return;
}

Logger::getInstance($level)->log($message, $context);
}
}
78 changes: 78 additions & 0 deletions src/SyntaxHandler.php
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace dokuwiki\plugin\yearbox\src;

use Doku_Handler;
use Psr\Log\LoggerInterface;

final class SyntaxHandler
{
private $logger;

public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}


/**
* Handle the match
* E.g.: {{yearbox>year=2010;name=journal;size=12;ns=diary}}
*
*/
public function handle($match): array
{
global $INFO;
$opt = [];

// default options
$opt['ns'] = $INFO['namespace'] ?? ''; // this namespace
$opt['size'] = 12; // 12px font size
$opt['name'] = 'day'; // a boring default page name
$opt['year'] = date('Y'); // this year
$opt['recent'] = false; // special 1-2 row 'recent pages' view...
$opt['months'] = []; // months to be displayed (csv list), e.g. 1,2,3,4... 1=Sun
$opt['weekdays'] = []; // weekdays which should have links (csv links)... 1=Jan
$opt['align'] = ''; // default is centred

$optionsString = substr($match, 10, -2);
$args = explode(';', $optionsString);
foreach ($args as $arg) {
[$key, $value] = explode('=', $arg);
switch ($key) {
case 'year':
$opt['year'] = $value;
break;
case 'name':
$opt['name'] = $value;
break;
case 'fontsize':
case 'size':
$opt['size'] = $value;
break;
case 'ns':
$opt['ns'] = (strpos($value, ':') === false) ? ':' . $value : $value;
break;
case 'recent':
$opt['recent'] = ((int)$value > 0) ? (int)$value : 0;
break;
case 'months':
$opt['months'] = explode(',', $value);
break;
case 'weekdays':
$opt['weekdays'] = explode(',', $value);
break;
case 'align':
if (in_array($value, ['left', 'right'])) {
$opt['align'] = $value;
}
break;
default:
$this->logger->warning("Yearbox Plugin: Unknown key '$key' in '$match'");
}
}
return $opt;
}
}
67 changes: 9 additions & 58 deletions syntax.php
Expand Up @@ -9,9 +9,13 @@

declare(strict_types=1);

// TODO: find a better way to load our own autoload files
require_once DOKU_PLUGIN . 'yearbox/vendor/autoload.php';

use dokuwiki\Extension\SyntaxPlugin;
use dokuwiki\Logger;
use dokuwiki\plugin\yearbox\services\pageNameStrategies\PageNameStrategy;
use dokuwiki\plugin\yearbox\src\PSR3CoreLogger;
use dokuwiki\plugin\yearbox\src\SyntaxHandler;

/**
* All DokuWiki plugins to extend the parser/rendering mechanism
Expand Down Expand Up @@ -64,63 +68,10 @@ public function connectTo($mode)
*/
public function handle($match, $state, $pos, Doku_Handler $handler)
{
global $INFO;
$opt = [];

// default options
$opt['ns'] = $INFO['namespace'] ?? ''; // this namespace
$opt['size'] = 12; // 12px font size
$opt['name'] = 'day'; // a boring default page name
$opt['year'] = date('Y'); // this year
$opt['recent'] = false; // special 1-2 row 'recent pages' view...
$opt['months'] = []; // months to be displayed (csv list), e.g. 1,2,3,4... 1=Sun
$opt['weekdays'] = []; // weekdays which should have links (csv links)... 1=Jan
$opt['align'] = ''; // default is centred

$optionsString = substr($match, 10, -2);
$args = explode(';', $optionsString);
foreach ($args as $arg) {
[$key, $value] = explode('=', $arg);
switch ($key) {
case 'year':
$opt['year'] = $value;
break;
case 'name':
$opt['name'] = $value;
break;
case 'fontsize':
case 'size':
$opt['size'] = $value;
break;
case 'ns':
$opt['ns'] = (strpos($value, ':') === false) ? ':' . $value : $value;
break;
case 'recent':
$opt['recent'] = ((int)$value > 0) ? (int)$value : 0;
break;
case 'months':
$opt['months'] = explode(',', $value);
break;
case 'weekdays':
$opt['weekdays'] = explode(',', $value);
break;
case 'align':
if (in_array($value, ['left', 'right'])) {
$opt['align'] = $value;
}
break;
default:
if ( class_exists(Logger::class)) {
Logger::getInstance(Logger::LOG_DEBUG)->log(
"Unknown key: '$key' in '$match'"
);
} else {
// TODO: remove after the next DokuWiki release
dbglog("Yearbox Plugin: Unknown key '$key' in '$match'");
}
}
}
return $opt;
$syntaxHandler = new SyntaxHandler(
new PSR3CoreLogger()
);
return $syntaxHandler->handle($match);
}

/**
Expand Down
7 changes: 7 additions & 0 deletions vendor/autoload.php
@@ -0,0 +1,7 @@
<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitccc3681a7a92d5d5faecba541bfbc8af::getLoader();

0 comments on commit 22faa2c

Please sign in to comment.