1 <?php
2 
3 namespace dokuwiki\Parsing\Handler;
4 
5 /**
6  * Generic call writer class to handle nesting of rendering instructions
7  * within a render instruction. Also see nest() method of renderer base class
8  *
9  * @author    Chris Smith <chris@jalakai.co.uk>
10  */
11 class Nest extends AbstractRewriter
12 {
13     protected $closingInstruction;
14 
15     /**
16      * @inheritdoc
17      *
18      * @param  CallWriterInterface $CallWriter     the parser's current call writer, i.e. the one above us in the chain
19      * @param  string     $close          closing instruction name, this is required to properly terminate the
20      *                                    syntax mode if the document ends without a closing pattern
21      */
22     public function __construct(CallWriterInterface $CallWriter, $close = "nest_close")
23     {
24         parent::__construct($CallWriter);
25         $this->closingInstruction = $close;
26     }
27 
28     /** @inheritdoc */
29     public function writeCall($call)
30     {
31         $this->calls[] = $call;
32     }
33 
34     /** @inheritdoc */
35     public function writeCalls($calls)
36     {
37         $this->calls = array_merge($this->calls, $calls);
38     }
39 
40     /** @inheritdoc */
41     public function finalise()
42     {
43         $last_call = end($this->calls);
44         $this->writeCall([$this->closingInstruction, [], $last_call[2]]);
45 
46         $this->process();
47         $this->callWriter->finalise();
48         unset($this->callWriter);
49     }
50 
51     /** @inheritdoc */
52     public function process()
53     {
54         // merge consecutive cdata
55         $unmerged_calls = $this->calls;
56         $this->calls = [];
57 
58         foreach ($unmerged_calls as $call) $this->addCall($call);
59 
60         $first_call = reset($this->calls);
61         $this->callWriter->writeCall(["nest", [$this->calls], $first_call[2]]);
62 
63         return $this->callWriter;
64     }
65 
66     /**
67      * @param array $call
68      */
69     protected function addCall($call)
70     {
71         $key = count($this->calls);
72         if ($key && $call[0] == 'cdata' && $this->calls[$key - 1][0] == 'cdata') {
73             $this->calls[$key - 1][1][0] .= $call[1][0];
74         } elseif ($call[0] == 'eol') {
75             // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699)
76         } else {
77             $this->calls[] = $call;
78         }
79     }
80 }
81