1<?php
2/**
3 * Notify-send report for PHP_CodeSniffer.
4 *
5 * PHP version 5
6 *
7 * @category  PHP
8 * @package   PHP_CodeSniffer
9 * @author    Christian Weiske <christian.weiske@netresearch.de>
10 * @author    Greg Sherwood <gsherwood@squiz.net>
11 * @copyright 2012-2014 Christian Weiske
12 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
13 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
14 * @link      http://pear.php.net/package/PHP_CodeSniffer
15 */
16
17/**
18 * Notify-send report for PHP_CodeSniffer.
19 *
20 * Supported configuration parameters:
21 * - notifysend_path    - Full path to notify-send cli command
22 * - notifysend_timeout - Timeout in milliseconds
23 * - notifysend_showok  - Show "ok, all fine" messages (0/1)
24 *
25 * @category  PHP
26 * @package   PHP_CodeSniffer
27 * @author    Christian Weiske <christian.weiske@netresearch.de>
28 * @author    Greg Sherwood <gsherwood@squiz.net>
29 * @copyright 2012-2014 Christian Weiske
30 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
31 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
32 * @version   Release: @package_version@
33 * @link      http://pear.php.net/package/PHP_CodeSniffer
34 */
35class PHP_CodeSniffer_Reports_Notifysend implements PHP_CodeSniffer_Report
36{
37
38    /**
39     * Notification timeout in milliseconds.
40     *
41     * @var integer
42     */
43    protected $timeout = 3000;
44
45    /**
46     * Path to notify-send command.
47     *
48     * @var string
49     */
50    protected $path = 'notify-send';
51
52    /**
53     * Show "ok, all fine" messages.
54     *
55     * @var boolean
56     */
57    protected $showOk = true;
58
59    /**
60     * Version of installed notify-send executable.
61     *
62     * @var string
63     */
64    protected $version = null;
65
66    /**
67     * A record of the last file checked.
68     *
69     * This is used in case we only checked one file and need to print
70     * the name/path of the file. We wont have access to the checked file list
71     * after the run has been completed.
72     *
73     * @var string
74     */
75    private $_lastCheckedFile = '';
76
77
78    /**
79     * Load configuration data.
80     */
81    public function __construct()
82    {
83        $path = PHP_CodeSniffer::getConfigData('notifysend_path');
84        if ($path !== null) {
85            $this->path = escapeshellcmd($path);
86        }
87
88        $timeout = PHP_CodeSniffer::getConfigData('notifysend_timeout');
89        if ($timeout !== null) {
90            $this->timeout = (int) $timeout;
91        }
92
93        $showOk = PHP_CodeSniffer::getConfigData('notifysend_showok');
94        if ($showOk !== null) {
95            $this->showOk = (boolean) $showOk;
96        }
97
98        $this->version = str_replace(
99            'notify-send ',
100            '',
101            exec($this->path.' --version')
102        );
103
104    }//end __construct()
105
106
107    /**
108     * Generate a partial report for a single processed file.
109     *
110     * Function should return TRUE if it printed or stored data about the file
111     * and FALSE if it ignored the file. Returning TRUE indicates that the file and
112     * its data should be counted in the grand totals.
113     *
114     * @param array                $report      Prepared report data.
115     * @param PHP_CodeSniffer_File $phpcsFile   The file being reported on.
116     * @param boolean              $showSources Show sources?
117     * @param int                  $width       Maximum allowed line width.
118     *
119     * @return boolean
120     */
121    public function generateFileReport(
122        $report,
123        PHP_CodeSniffer_File $phpcsFile,
124        $showSources=false,
125        $width=80
126    ) {
127        // We don't need to print anything, but we want this file counted
128        // in the total number of checked files even if it has no errors.
129        $this->_lastCheckedFile = $report['filename'];
130        return true;
131
132    }//end generateFileReport()
133
134
135    /**
136     * Generates a summary of errors and warnings for each file processed.
137     *
138     * @param string  $cachedData    Any partial report data that was returned from
139     *                               generateFileReport during the run.
140     * @param int     $totalFiles    Total number of files processed during the run.
141     * @param int     $totalErrors   Total number of errors found during the run.
142     * @param int     $totalWarnings Total number of warnings found during the run.
143     * @param int     $totalFixable  Total number of problems that can be fixed.
144     * @param boolean $showSources   Show sources?
145     * @param int     $width         Maximum allowed line width.
146     * @param boolean $toScreen      Is the report being printed to screen?
147     *
148     * @return void
149     */
150    public function generate(
151        $cachedData,
152        $totalFiles,
153        $totalErrors,
154        $totalWarnings,
155        $totalFixable,
156        $showSources=false,
157        $width=80,
158        $toScreen=true
159    ) {
160        $msg = $this->generateMessage($totalFiles, $totalErrors, $totalWarnings);
161        if ($msg === null) {
162            if ($this->showOk === true) {
163                $this->notifyAllFine();
164            }
165        } else {
166            $this->notifyErrors($msg);
167        }
168
169    }//end generate()
170
171
172    /**
173     * Generate the error message to show to the user.
174     *
175     * @param int $totalFiles    Total number of files processed during the run.
176     * @param int $totalErrors   Total number of errors found during the run.
177     * @param int $totalWarnings Total number of warnings found during the run.
178     *
179     * @return string Error message or NULL if no error/warning found.
180     */
181    protected function generateMessage($totalFiles, $totalErrors, $totalWarnings)
182    {
183        if ($totalErrors === 0 && $totalWarnings === 0) {
184            // Nothing to print.
185            return null;
186        }
187
188        $msg = '';
189        if ($totalFiles > 1) {
190            $msg .= 'Checked '.$totalFiles.' files'.PHP_EOL;
191        } else {
192            $msg .= $this->_lastCheckedFile.PHP_EOL;
193        }
194
195        if ($totalWarnings > 0) {
196            $msg .= $totalWarnings.' warnings'.PHP_EOL;
197        }
198
199        if ($totalErrors > 0) {
200            $msg .= $totalErrors.' errors'.PHP_EOL;
201        }
202
203        return $msg;
204
205    }//end generateMessage()
206
207
208    /**
209     * Tell the user that all is fine and no error/warning has been found.
210     *
211     * @return void
212     */
213    protected function notifyAllFine()
214    {
215        $cmd  = $this->getBasicCommand();
216        $cmd .= ' -i info';
217        $cmd .= ' "PHP CodeSniffer: Ok"';
218        $cmd .= ' "All fine"';
219        exec($cmd);
220
221    }//end notifyAllFine()
222
223
224    /**
225     * Tell the user that errors/warnings have been found.
226     *
227     * @param string $msg Message to display.
228     *
229     * @return void
230     */
231    protected function notifyErrors($msg)
232    {
233        $cmd  = $this->getBasicCommand();
234        $cmd .= ' -i error';
235        $cmd .= ' "PHP CodeSniffer: Error"';
236        $cmd .= ' '.escapeshellarg(trim($msg));
237        exec($cmd);
238
239    }//end notifyErrors()
240
241
242    /**
243     * Generate and return the basic notify-send command string to execute.
244     *
245     * @return string Shell command with common parameters.
246     */
247    protected function getBasicCommand()
248    {
249        $cmd  = $this->path;
250        $cmd .= ' --category dev.validate';
251        $cmd .= ' -h int:transient:1';
252        $cmd .= ' -t '.(int) $this->timeout;
253        if (version_compare($this->version, '0.7.3', '>=') === true) {
254            $cmd .= ' -a phpcs';
255        }
256
257        return $cmd;
258
259    }//end getBasicCommand()
260
261
262}//end class
263