1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Process;
13
14use Symfony\Component\Process\Exception\RuntimeException;
15
16/**
17 * Provides a way to continuously write to the input of a Process until the InputStream is closed.
18 *
19 * @author Nicolas Grekas <p@tchwork.com>
20 */
21class InputStream implements \IteratorAggregate
22{
23    /** @var callable|null */
24    private $onEmpty = null;
25    private $input = [];
26    private $open = true;
27
28    /**
29     * Sets a callback that is called when the write buffer becomes empty.
30     */
31    public function onEmpty(callable $onEmpty = null)
32    {
33        $this->onEmpty = $onEmpty;
34    }
35
36    /**
37     * Appends an input to the write buffer.
38     *
39     * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar,
40     *                                                                stream resource or \Traversable
41     */
42    public function write($input)
43    {
44        if (null === $input) {
45            return;
46        }
47        if ($this->isClosed()) {
48            throw new RuntimeException(sprintf('"%s" is closed.', static::class));
49        }
50        $this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
51    }
52
53    /**
54     * Closes the write buffer.
55     */
56    public function close()
57    {
58        $this->open = false;
59    }
60
61    /**
62     * Tells whether the write buffer is closed or not.
63     */
64    public function isClosed()
65    {
66        return !$this->open;
67    }
68
69    public function getIterator()
70    {
71        $this->open = true;
72
73        while ($this->open || $this->input) {
74            if (!$this->input) {
75                yield '';
76                continue;
77            }
78            $current = array_shift($this->input);
79
80            if ($current instanceof \Iterator) {
81                foreach ($current as $cur) {
82                    yield $cur;
83                }
84            } else {
85                yield $current;
86            }
87            if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
88                $this->write($onEmpty($this));
89            }
90        }
91    }
92}
93