Passed
Push — main ( 221f6d...f8c128 )
by Siad
05:28
created

src/Phing/Listener/JsonLogger.php (1 issue)

1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Listener;
22
23
use Exception;
24
use Phing\Exception\BuildException;
25
use Phing\Io\FileOutputStream;
26
use Phing\Io\IOException;
27
use Phing\Io\OutputStreamWriter;
28
use SimpleXMLElement;
29
30
/**
31
 * Generates a file in the current directory with
32
 * an JSON description of what happened during a build.
33
 * The default filename is "log.json", but this can be overridden
34
 * with the property <code>JsonLogger.file</code>.
35
 *
36
 * @author  Siad Ardroumli <[email protected]>
37
 */
38
class JsonLogger extends XmlLogger
39
{
40
    /**
41
     * Fired when the build finishes, this adds the time taken and any
42
     * error stacktrace to the build element and writes the document to disk.
43
     *
44
     * @param BuildEvent $event An event with any relevant extra information.
45
     *                          Will not be <code>null</code>.
46
     *
47
     * @throws BuildException
48
     */
49
    public function buildFinished(BuildEvent $event)
50
    {
51
        $elapsedTime = $this->clock->getCurrentTime() - $this->getBuildTimerStart();
52
53
        $this->getBuildElement()->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::formatTime($elapsedTime));
54
55
        if (null != $event->getException()) {
56
            $this->getBuildElement()->setAttribute(XmlLogger::ERROR_ATTR, $event->getException()->getMessage());
57
            $errText = $this->getDoc()->createCDATASection($event->getException()->getTraceAsString());
58
            $stacktrace = $this->getDoc()->createElement(XmlLogger::STACKTRACE_TAG);
59
            $stacktrace->appendChild($errText);
60
            $this->getBuildElement()->appendChild($stacktrace);
61
        }
62
63
        $this->getDoc()->appendChild($this->getBuildElement());
64
65
        $outFilename = $event->getProject()->getProperty('JsonLogger.file');
66
        if (null == $outFilename) {
67
            $outFilename = 'log.json';
68
        }
69
70
        $stream = $this->getOut();
71
72
        try {
73
            if (null === $stream) {
74
                $stream = new FileOutputStream($outFilename);
75
            }
76
77
            $writer = new OutputStreamWriter($stream);
78
            $writer->write($this->xml2js(simplexml_import_dom($this->getDoc())));
79
            $writer->close();
80
        } catch (IOException $exc) {
81
            try {
82
                $stream->close(); // in case there is a stream open still ...
83
            } catch (Exception $x) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
84
            }
85
86
            throw new BuildException('Unable to write log file.', $exc);
87
        }
88
89
        // cleanup:remove the buildElement
90
        $this->setBuildElement(null);
91
92
        array_pop($this->getElementStack());
93
        array_pop($this->getTimesStack());
94
    }
95
96
    private function xml2js(SimpleXMLElement $xmlnode, $isRoot = true)
97
    {
98
        $jsnode = [];
99
100
        if (!$isRoot) {
101
            if (count($xmlnode->attributes()) > 0) {
102
                $jsnode['@attribute'] = [];
103
                foreach ($xmlnode->attributes() as $key => $value) {
104
                    $jsnode['@attribute'][$key] = (string) $value;
105
                }
106
            }
107
108
            $textcontent = trim((string) $xmlnode);
109
            if (count($textcontent) > 0) {
110
                $jsnode['_'] = $textcontent;
111
            }
112
113
            foreach ($xmlnode->children() as $childxmlnode) {
114
                $childname = $childxmlnode->getName();
115
                if (!array_key_exists($childname, $jsnode)) {
116
                    $jsnode[$childname] = [];
117
                }
118
                $jsnode[$childname][] = $this->xml2js($childxmlnode, false);
119
            }
120
121
            return $jsnode;
122
        }
123
124
        $nodename = $xmlnode->getName();
125
        $jsnode[$nodename] = [];
126
        $jsnode[$nodename][] = $this->xml2js($xmlnode, false);
127
128
        return json_encode($jsnode, JSON_PRETTY_PRINT);
129
    }
130
}
131