Completed
Push — master ( e94bc5...52c81e )
by Derek
02:08
created

File::close()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Subreality\Dilmun\Nabu\LoggerHandler;
4
5
/**
6
 * Log file object implementing a standard HandlerInterface for log entry handlers.
7
 *
8
 * @author derek
9
 *
10
 * @todo Create methods that set Class properties from actual file properties.
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
11
 * @todo Implement log rotation mechanism based on the size of an existing log file specified for writing.
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
12
 */
13
class File implements HandlerInterface
0 ignored issues
show
Coding Style introduced by
The property $file_name is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $file_path is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $display_init_failure is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $init_failure_email_address is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style introduced by
The property $file_pointer is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
14
{
15
    private $file_name;
16
    private $file_path;
17
18
    private $display_init_failure = true;
19
20
    private $init_failure_email_address = false;
21
22
    /**
23
     * @var \SplFileObject
24
     */
25
    private $file_pointer;
26
27
    /**
28
     * Sets up the file name and path if optional parameters provided.
29
     *
30
     * @param string $file_name [optional] The name of the file used for logging; file_path is not required if file_name
0 ignored issues
show
Documentation introduced by
Should the type for parameter $file_name not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
31
     *                          is fully-qualified.
32
     * @param string $file_path [optional] The path of the file used for logging without the trailing directory
0 ignored issues
show
Documentation introduced by
Should the type for parameter $file_path not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
33
     *                          separator
34
     */
35 19
    public function __construct($file_name = null, $file_path = null)
36
    {
37 19
        $this->file_name = $file_name;
38
39
        //Trim any trailing directory separators from the path.
40 19
        if (isset($file_path)) {
41
            $this->file_path = rtrim($file_path, '\/');
42
        }
43 19
    }
44
45
    /**
46
     * Clean-up
47
     */
48 19
    public function __destruct()
49
    {
50 19
        $this->close();
51 19
    }
52
53
    /**
54
     * @return null|string  The file_name set for the File instance
55
     */
56 1
    public function getFileName()
57
    {
58 1
        return $this->file_name;
59
    }
60
61
    /**
62
     * @return null|string  The file_path set for the File instance
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
63
     */
64 1
    public function getFilePath()
65
    {
66 1
        return $this->file_path;
67
    }
68
69
    /**
70
     * Sets the name of the file to be used for logging; setting file_path is not required if the specified file name
71
     * is fully-qualified.
72
     *
73
     * @param string $file_name The name of the file to be used for logging
74
     *
75
     * @todo Perform some sort of validation against the file name string
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
76
     */
77 2
    public function setFileName($file_name)
78
    {
79 2
        $this->file_name = $file_name;
80 2
    }
81
82
    /**
83
     * Sets the path of the file to be used for logging; file path should not be set if the File's file name is
84
     * fully-qualified.
85
     *
86
     * @see File::setFileName()
87
     *
88
     * @param string $file_path The path of the file to be used for logging
89
     *
90
     * @todo Perform some sort of validation against the file path string, maybe considering file_name contents
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
91
     */
92 2
    public function setFilePath($file_path)
93
    {
94
        //Trip any trailing directory separators from the path.
95 2
        $this->file_path = rtrim($file_path, '\/');
96 2
    }
97
98
    /**
99
     * Prevents the initialization function from outputting an exception/failure message when initialization fails;
100
     * reversed by displayInitFailureMessage. If message is suppressed, a message is instead written to the PHP error
101
     * log via error_log.
102
     *
103
     * @see error_log()
104
     * @see File::displayInitFailureMessage()
105
     * @see File::initialize()
106
     */
107 11
    public function suppressInitFailureMessage()
108
    {
109 11
        $this->display_init_failure = false;
110 11
    }
111
112
    /**
113
     * Enables the initialization function to output an exception/failure message when initialization fails; reversed
114
     * by suppressInitFailureMessage.
115
     *
116
     * @see File::initialize()
117
     * @see File::suppressInitFailureMessage()
118
     */
119 2
    public function displayInitFailureMessage()
120
    {
121 2
        $this->display_init_failure = true;
122 2
    }
123
124
    /**
125
     * Sets the email address to send a failure notification if File initialization fails. Note that setting the email
126
     * address enables sending an email notification via PHP's error_log.
127
     *
128
     * @see File::initialize()
129
     * @see error_log()
130
     *
131
     * @param string $email_address
132
     */
133 2
    public function sendInitFailureEmailAddress($email_address)
134
    {
135 2
        $this->init_failure_email_address = $email_address;
0 ignored issues
show
Documentation Bug introduced by
The property $init_failure_email_address was declared of type boolean, but $email_address is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
136 2
    }
137
138
    /**
139
     * Truncates the File to zero bytes, effectively clearing the file's contents. Does not delete the file.
140
     *
141
     * @return bool Returns true if truncate succeeded; returns false on failure.
142
     */
143 21
    public function clearFile()
144
    {
145 21
        if (isset($this->file_pointer)) {
146 20
            $this->file_pointer->ftruncate(0);
147
148 20
            return true;
149
        } else {
150 1
            return false;
151
        }
152
    }
153
154
    /**
155
     * Sets the File's file_pointer to null to clean up resource.
156
     */
157 19
    public function close()
158
    {
159 19
        $this->file_pointer = null;
160 19
    }
161
162
    /**
163
     * Initializes the File for writing via append. Initialization attempts to create an SplFileObject pointer using
164
     * the File's name and path properties. On failure, initialization may output the full file path with an Exception
165
     * message depending on File properties. By default, File::initialize() writes output to the standard output
166
     * buffer and does not send email.
167
     *
168
     * @see \SplFileObject
169
     *
170
     * @return bool Returns true on successful file pointer creation; returns false on failure.
171
     *
172
     * @todo Detect whether file_path has trailing directory separator; add both cases to FileTest.
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
173
     */
174 12
    public function initialize()
175
    {
176 12
        $full_file = "";
177
178 12
        if (isset($this->file_path)) {
179 1
            $full_file = $this->file_path . DIRECTORY_SEPARATOR;
180 1
        }
181
182 12
        $full_file .= $this->file_name;
183
184
        try {
185 12
            $this->file_pointer = new \SplFileObject($full_file, "a");
186
187 3
            return true;
188 9
        } catch (\Exception $e) {
189 9
            $file_error_message = "Cannot open specified log file for writing: {$full_file}: {$e->getMessage()}\n";
190
191 9
            if ($this->init_failure_email_address) {
192 1
                $email_success = error_log($file_error_message, 1, $this->init_failure_email_address);
193
194
                //Write to PHP log if sending email fails
195 1
                if (!$email_success) {
196 1
                    error_log("Sending email to {$this->init_failure_email_address}
197 1
                               failed! Message: {$file_error_message}");
198 1
                }
199 1
            }
200
201 9
            if ($this->display_init_failure) {
202 1
                echo $file_error_message;
203 1
            } else {
204 8
                error_log($file_error_message);
205
            }
206
207 9
            return false;
208
        }
209
    }
210
211
    /**
212
     * Writes the specified message to the File pointer. Requires initialization via File::initialize().
213
     *
214
     * @see File::initialize()
215
     *
216
     * @param string $message   Message to be written to the file.
217
     *
218
     * @return bool Returns true on successful write; returns false on failure.
219
     *
220
     * @todo Refactor to return what was written to the file rather than true on success.
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
221
     */
222 21
    public function write($message)
223
    {
224 21
        if (isset($this->file_pointer)) {
225 17
            $locked = $this->file_pointer->flock(LOCK_EX);
226 17
        } else {
227 4
            $locked = false;
228
        }
229
230 21
        if ($locked) {
231 17
            $now = date('Y-m-d H:i:s');
232 17
            $this->file_pointer->fwrite("$now : $message" . "\r\n");
233 17
            $this->file_pointer->flock(LOCK_UN);
234
235 17
            return true;
236
        } else {
237 4
            return false;
238
        }
239
    }
240
}
241