305 lines
6.6 KiB
PHP
305 lines
6.6 KiB
PHP
<?php
|
||
|
||
namespace Pandoc;
|
||
|
||
use Exception;
|
||
use Pandoc\Exceptions\BadMethodCall;
|
||
use Pandoc\Exceptions\PandocNotFound;
|
||
use Symfony\Component\Process\Process;
|
||
use Pandoc\Exceptions\InputFileNotFound;
|
||
use Pandoc\Exceptions\UnknownInputFormat;
|
||
use Pandoc\Exceptions\LogFileNotWriteable;
|
||
use Pandoc\Exceptions\UnknownOutputFormat;
|
||
use Symfony\Component\Process\ExecutableFinder;
|
||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||
|
||
class Pandoc
|
||
{
|
||
public $config;
|
||
|
||
protected $input;
|
||
|
||
protected $standalone = true;
|
||
|
||
protected $inputFile;
|
||
|
||
protected $from;
|
||
|
||
protected $to;
|
||
|
||
protected $output;
|
||
|
||
protected $log;
|
||
|
||
protected $dataDir;
|
||
|
||
protected $cwd;
|
||
|
||
protected $options;
|
||
|
||
public function __construct($config = [])
|
||
{
|
||
$this->config = array_merge([
|
||
'command' => (new ExecutableFinder)->find('pandoc', 'pandoc'),
|
||
], $config);
|
||
|
||
$this->options = [];
|
||
}
|
||
|
||
public function inputFile($value)
|
||
{
|
||
$this->inputFile = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function input($value)
|
||
{
|
||
$this->input = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function from($value)
|
||
{
|
||
$this->from = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function to($value)
|
||
{
|
||
$this->to = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function output($value)
|
||
{
|
||
$this->output = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function option($name, $value = false)
|
||
{
|
||
$this->options[$name] = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function log($value)
|
||
{
|
||
$this->log = $value;
|
||
$this->option('log', $value);
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function dataDir($value)
|
||
{
|
||
$this->dataDir = $value;
|
||
$this->option('data-dir', $value);
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function cwd($value)
|
||
{
|
||
$this->cwd = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
/* Convenience wrappers around option() */
|
||
public function columns($value)
|
||
{
|
||
$this->option('columns', $value);
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function tocDepth($value)
|
||
{
|
||
$this->option('toc-depth', $value);
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function standalone()
|
||
{
|
||
$this->option('standalone');
|
||
$this->standalone = true;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function noStandalone()
|
||
{
|
||
$this->standalone = false;
|
||
|
||
return $this;
|
||
}
|
||
|
||
public function execute(array $parameters = [])
|
||
{
|
||
$parameters = array_merge([
|
||
$this->config['command'],
|
||
], $parameters);
|
||
|
||
if (!empty($this->options)) {
|
||
foreach ($this->options as $name => $value) {
|
||
if ($value !== false) {
|
||
array_push($parameters, "--{$name}", $value);
|
||
} else {
|
||
array_push($parameters, "--{$name}");
|
||
}
|
||
}
|
||
}
|
||
|
||
$process = new Process($parameters);
|
||
|
||
if ($this->cwd) {
|
||
$process->setWorkingDirectory($this->cwd);
|
||
}
|
||
|
||
if ($this->input) {
|
||
$process->setInput($this->input);
|
||
}
|
||
|
||
$process->run();
|
||
|
||
if (!$process->isSuccessful()) {
|
||
$output = $process->getErrorOutput();
|
||
|
||
if (strpos($output, "pandoc: {$this->inputFile}: openBinaryFile: does not exist") !== false) {
|
||
throw new InputFileNotFound;
|
||
}
|
||
|
||
if (strpos($output, "pandoc: {$this->log}: openBinaryFile: does not exist") !== false) {
|
||
throw new LogFileNotWriteable;
|
||
}
|
||
|
||
if (strpos($output, 'Unknown input format') !== false) {
|
||
throw new UnknownInputFormat;
|
||
}
|
||
|
||
if (strpos($output, 'Unknown output format') !== false) {
|
||
throw new UnknownOutputFormat;
|
||
}
|
||
|
||
if (strpos($output, 'not found') !== false) {
|
||
throw new PandocNotFound;
|
||
}
|
||
|
||
throw new ProcessFailedException($process);
|
||
}
|
||
|
||
$output = $process->getOutput();
|
||
|
||
if ($output === '') {
|
||
return true;
|
||
}
|
||
|
||
return $output;
|
||
}
|
||
|
||
public function run()
|
||
{
|
||
$parameters = [
|
||
'--sandbox',
|
||
];
|
||
|
||
if ($this->standalone) {
|
||
array_push($parameters, '--standalone');
|
||
}
|
||
|
||
if ($this->inputFile) {
|
||
array_push($parameters, $this->inputFile);
|
||
}
|
||
|
||
if ($this->from) {
|
||
array_push($parameters, '--from', "{$this->from}");
|
||
}
|
||
|
||
if ($this->to) {
|
||
array_push($parameters, '--to', "{$this->to}");
|
||
}
|
||
|
||
if ($this->output) {
|
||
array_push($parameters, '--output', "{$this->output}");
|
||
}
|
||
|
||
return $this->execute($parameters);
|
||
}
|
||
|
||
public function version()
|
||
{
|
||
$output = $this->execute(['--version']);
|
||
|
||
preg_match("~^.*\K\d(?<![a-z\d.].)\d*(?:\.\d+)*+~mi", $output, $matches);
|
||
list($version) = $matches;
|
||
|
||
if (!$version) {
|
||
throw new Exception('Couldn’t find a pandoc version number in the output.');
|
||
}
|
||
|
||
return $version;
|
||
}
|
||
|
||
public function listInputFormats()
|
||
{
|
||
$output = $this->execute(['--list-input-formats']);
|
||
|
||
return array_filter(explode("\n", $output));
|
||
}
|
||
|
||
public function listOutputFormats()
|
||
{
|
||
$output = $this->execute(['--list-output-formats']);
|
||
|
||
return array_filter(explode("\n", $output));
|
||
}
|
||
|
||
public function __call($method, $args)
|
||
{
|
||
$stringsStartsWithFrom = strpos($method, 'from') === 0;
|
||
$desiredInputFormat = strtolower(
|
||
array_reverse(explode('from', $method, 2))[0]
|
||
);
|
||
$availableInputFormats = $this->listInputFormats();
|
||
|
||
if ($stringsStartsWithFrom && in_array($desiredInputFormat, $availableInputFormats)) {
|
||
$this->from($desiredInputFormat);
|
||
|
||
if (! empty($args)) {
|
||
$this->input(...$args);
|
||
}
|
||
|
||
return $this;
|
||
}
|
||
|
||
$stringStartsWithTo = strpos($method, 'to') === 0;
|
||
$desiredOutputFormat = strtolower(
|
||
array_reverse(explode('to', $method, 2))[0]
|
||
);
|
||
$availableOutputFormats = $this->listOutputFormats();
|
||
|
||
if ($stringStartsWithTo && in_array($desiredOutputFormat, $availableOutputFormats)) {
|
||
$this->to($desiredOutputFormat);
|
||
|
||
if (! empty($args)) {
|
||
$this->output(...$args);
|
||
}
|
||
|
||
return $this;
|
||
}
|
||
|
||
throw new BadMethodCall(sprintf(
|
||
'Call to undefined method %s::%s()',
|
||
get_class($this),
|
||
$method
|
||
));
|
||
}
|
||
}
|