ueberdosis / pandoc

A PHP wrapper for Pandoc to convert any text format in any other text format
MIT License
77 stars 10 forks source link

Priblem with passing multuple options of the same type #25

Open om-arino opened 3 years ago

om-arino commented 3 years ago

Hello, i like the wrapper a lot, but I've stumbled on an issue, which is crucial for my implementation, and it looks like a bug. When I pass multiple options of the same type, which are supported by pandoc ( you can pass multiple --metadata or --variable options), the wrapper passes on only the first one ... for example in

echo (new \Pandoc\Pandoc) ->from('markdown_mmd') ->inputFile(mmd_file($id)) ->option('standalone') ->option('self-contained') ->option('template',$okvir) ->option('css',$css) ->option('metadata-file', $yaml_file) ->option('metadata','x=y') ->option('metadata', 'n_izv_text='.$nizi['original']) ->to('html5') ->log($log_file) ->run(); I can access variable x in the template, but the n_izv_text or any other metadata does not get passed to template? Any ideas on why is that? Thank you in advance, Regards, Om

dregini commented 3 years ago

Hi, to solve this issue I have this proposal:

edit pandoc->option:

    public function option($name, $value = false)
    {
        if(key_exists($name, $this->options)){
            if(is_array($value)){
                $this->options[$name] = array_merge($this->options[$name], $value);
            }else{
                array_push($this->options[$name], $value);
            }
        }else{
            $this->options[$name] = is_array($value) ? $value : [$value];
        }
        return $this;
    }

and pandoc->execute:


    public function execute(array $parameters = [])
    {
        $parameters = array_merge([
            $this->config['command'],
        ], $parameters);
        //new code start here
        if (!empty($this->options)) {
            foreach ($this->options as $name => $value) {
                foreach ($value as  $sub_value) {
                    if($sub_value !== false){
                        array_push($parameters, "--{$name}", $sub_value);
                    }else{
                        array_push($parameters, "--{$name}");
                    }
                }
            }
        }
        //new code ends here
        $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;
    }

And for the usage:

//preferred way:
 (new \Pandoc\Pandoc)
     ->option('metadata',   'x=y')
      ->option('metadata',  'a=b')

//optional way:
 (new \Pandoc\Pandoc)->option('metadata', [
    'x=y',
    'a=b'
])
dregini commented 3 years ago

To make it more compatible with previous implementation another option could be this:

public function option($name, $value = false, $override = true)
{
    if($override){
        $this->options[$name] = [];
    }
    if(key_exists($name, $this->options)){
        if(is_array($value)){
            $this->options[$name] = array_merge($this->options[$name], $value);
        }else{
            array_push($this->options[$name], $value);
        }
    }else{
        $this->options[$name] = is_array($value) ? $value : [$value];
    }
    return $this;
}

$override is set to true by default to keep compatiblility to previous version. Because if a user was setting 2 times toc-depth (for example) the second one was kept and the first ignored.

so usage would be:

//preferred way:
 (new \Pandoc\Pandoc)
     ->option('metadata',   'x=y', true)
     ->option('metadata',  'a=b', true)
     ->option('toc-depth', 2) //ignored
     ->option('toc-depth', 4)

//optional way:
 (new \Pandoc\Pandoc)->option('metadata', [
    'x=y',
    'a=b'
], true)
     ->option('toc-depth', 2) //ignored
     ->option('toc-depth', 4)

Note: I don't know if is a non issue and pandoc himself understand to override previous value. I'm pretty new to pandoc.