1: <?php declare(strict_types=1);
2:
3: namespace Salient\Contract\Console;
4:
5: use Psr\Log\LoggerInterface;
6: use Salient\Contract\Console\ConsoleFormatterInterface as FormatterInterface;
7: use Salient\Contract\Console\ConsoleMessageType as MessageType;
8: use Salient\Contract\Core\MessageLevel as Level;
9: use Salient\Contract\Core\MessageLevelGroup as LevelGroup;
10: use Throwable;
11:
12: interface ConsoleWriterInterface
13: {
14: /**
15: * Register STDOUT and STDERR to receive console output if running on the
16: * command line
17: *
18: * - Errors and warnings are written to `STDERR`
19: * - Informational messages are written to `STDOUT`
20: * - Debug messages are ignored unless environment variable `DEBUG` is set
21: *
22: * @return $this
23: */
24: public function registerStdioTargets();
25:
26: /**
27: * Register STDERR to receive console output if running on the command line
28: *
29: * - Errors, warnings and informational messages are written to `STDERR`
30: * - Debug messages are ignored unless environment variable `DEBUG` is set
31: *
32: * @return $this
33: */
34: public function registerStderrTarget();
35:
36: /**
37: * Register a target to receive console output
38: *
39: * @param array<Level::*> $levels
40: * @return $this
41: */
42: public function registerTarget(
43: ConsoleTargetInterface $target,
44: array $levels = LevelGroup::ALL
45: );
46:
47: /**
48: * Deregister and close a registered target
49: *
50: * If `$target` is registered with the writer, it is deregistered and closed
51: * via {@see ConsoleTargetInterface::close()}, otherwise calling this method
52: * has no effect.
53: *
54: * @return $this
55: */
56: public function deregisterTarget(ConsoleTargetInterface $target);
57:
58: /**
59: * Get a list of registered targets, optionally filtered by level and type
60: *
61: * @param Level::*|null $level
62: * @param int-mask-of<ConsoleTargetTypeFlag::*> $flags
63: * @return ConsoleTargetInterface[]
64: */
65: public function getTargets(?int $level = null, int $flags = 0): array;
66:
67: /**
68: * Set or unset the prefix applied to each line of output by any registered
69: * targets that implement ConsoleTargetPrefixInterface
70: *
71: * @param int-mask-of<ConsoleTargetTypeFlag::*> $flags
72: * @return $this
73: */
74: public function setTargetPrefix(?string $prefix, int $flags = 0);
75:
76: /**
77: * Get the width of a registered target in columns
78: *
79: * Returns {@see ConsoleTargetInterface::getWidth()} from whichever is found
80: * first:
81: *
82: * - the first TTY target registered with the given level
83: * - the first `STDOUT` or `STDERR` target registered with the given level
84: * - the first target registered with the given level
85: * - the target returned by {@see getStderrTarget()} if backed by a TTY
86: * - the target returned by {@see getStdoutTarget()}
87: *
88: * @param Level::* $level
89: */
90: public function getWidth(int $level = Level::INFO): ?int;
91:
92: /**
93: * Get an output formatter for a registered target
94: *
95: * Returns {@see ConsoleTargetInterface::getFormatter()} from the same
96: * target as {@see ConsoleWriterInterface::getWidth()}.
97: *
98: * @param Level::* $level
99: */
100: public function getFormatter(int $level = Level::INFO): FormatterInterface;
101:
102: /**
103: * Get a PSR-3 logger backed by the writer
104: */
105: public function getLogger(): LoggerInterface;
106:
107: /**
108: * Get a target for STDOUT, creating an unregistered one if necessary
109: */
110: public function getStdoutTarget(): ConsoleTargetStreamInterface;
111:
112: /**
113: * Get a target for STDERR, creating an unregistered one if necessary
114: */
115: public function getStderrTarget(): ConsoleTargetStreamInterface;
116:
117: /**
118: * Get the number of error messages recorded by the writer so far
119: */
120: public function getErrorCount(): int;
121:
122: /**
123: * Get the number of warning messages recorded by the writer so far
124: */
125: public function getWarningCount(): int;
126:
127: /**
128: * Escape a string so it can be safely used in a console message
129: */
130: public function escape(string $string): string;
131:
132: /**
133: * Print "! $msg1 $msg2" with level ERROR
134: *
135: * @return $this
136: */
137: public function error(
138: string $msg1,
139: ?string $msg2 = null,
140: ?Throwable $ex = null,
141: bool $count = true
142: );
143:
144: /**
145: * Print "! $msg1 $msg2" with level ERROR once per run
146: *
147: * @return $this
148: */
149: public function errorOnce(
150: string $msg1,
151: ?string $msg2 = null,
152: ?Throwable $ex = null,
153: bool $count = true
154: );
155:
156: /**
157: * Print "^ $msg1 $msg2" with level WARNING
158: *
159: * @return $this
160: */
161: public function warn(
162: string $msg1,
163: ?string $msg2 = null,
164: ?Throwable $ex = null,
165: bool $count = true
166: );
167:
168: /**
169: * Print "^ $msg1 $msg2" with level WARNING once per run
170: *
171: * @return $this
172: */
173: public function warnOnce(
174: string $msg1,
175: ?string $msg2 = null,
176: ?Throwable $ex = null,
177: bool $count = true
178: );
179:
180: /**
181: * Print "➤ $msg1 $msg2" with level NOTICE
182: *
183: * @return $this
184: */
185: public function info(string $msg1, ?string $msg2 = null);
186:
187: /**
188: * Print "➤ $msg1 $msg2" with level NOTICE once per run
189: *
190: * @return $this
191: */
192: public function infoOnce(string $msg1, ?string $msg2 = null);
193:
194: /**
195: * Print "- $msg1 $msg2" with level INFO
196: *
197: * @return $this
198: */
199: public function log(string $msg1, ?string $msg2 = null);
200:
201: /**
202: * Print "- $msg1 $msg2" with level INFO once per run
203: *
204: * @return $this
205: */
206: public function logOnce(string $msg1, ?string $msg2 = null);
207:
208: /**
209: * Print ": <caller> $msg1 $msg2" with level DEBUG
210: *
211: * @param int $depth To print your caller's name instead of your own, set
212: * `$depth` to 1.
213: * @return $this
214: */
215: public function debug(
216: string $msg1,
217: ?string $msg2 = null,
218: ?Throwable $ex = null,
219: int $depth = 0
220: );
221:
222: /**
223: * Print ": <caller> $msg1 $msg2" with level DEBUG once per run
224: *
225: * @param int $depth To print your caller's name instead of your own, set
226: * `$depth` to 1.
227: * @return $this
228: */
229: public function debugOnce(
230: string $msg1,
231: ?string $msg2 = null,
232: ?Throwable $ex = null,
233: int $depth = 0
234: );
235:
236: /**
237: * Print "⠿ $msg1 $msg2" with level INFO to TTY targets without moving to
238: * the next line
239: *
240: * This method can be called repeatedly to display progress updates without
241: * disrupting other console messages or bloating output logs.
242: *
243: * @return $this
244: */
245: public function logProgress(string $msg1, ?string $msg2 = null);
246:
247: /**
248: * Print a "clear to end of line" control sequence with level INFO to TTY
249: * targets with a logProgress() message
250: *
251: * @return $this
252: */
253: public function clearProgress();
254:
255: /**
256: * Print "$msg1 $msg2" with prefix and formatting optionally based on $level
257: *
258: * @param Level::* $level
259: * @param MessageType::* $type
260: * @return $this
261: */
262: public function message(
263: string $msg1,
264: ?string $msg2 = null,
265: int $level = Level::INFO,
266: int $type = MessageType::UNDECORATED,
267: ?Throwable $ex = null,
268: bool $count = true
269: );
270:
271: /**
272: * Print "$msg1 $msg2" with prefix and formatting optionally based on $level
273: * once per run
274: *
275: * @param Level::* $level
276: * @param MessageType::* $type
277: * @return $this
278: */
279: public function messageOnce(
280: string $msg1,
281: ?string $msg2 = null,
282: int $level = Level::INFO,
283: int $type = MessageType::UNDECORATED,
284: ?Throwable $ex = null,
285: bool $count = true
286: );
287:
288: /**
289: * Record a message with level $level without printing anything
290: *
291: * @param Level::* $level
292: * @return $this
293: */
294: public function count(int $level);
295:
296: /**
297: * Increase the indentation level of messages and print "» $msg1 $msg2" with
298: * level NOTICE
299: *
300: * If `$endMsg1` is not `null`, `"« $endMsg1 $endMsg2"` is printed with
301: * level `NOTICE` when {@see groupEnd()} is called to close the group.
302: *
303: * @return $this
304: */
305: public function group(
306: string $msg1,
307: ?string $msg2 = null,
308: ?string $endMsg1 = null,
309: ?string $endMsg2 = null
310: );
311:
312: /**
313: * Close the nested message group most recently opened with group()
314: *
315: * @return $this
316: */
317: public function groupEnd();
318:
319: /**
320: * Print an exception's name and message with a given level, optionally
321: * followed by its stack trace with a different level
322: *
323: * @param Level::* $level
324: * @param Level::*|null $traceLevel If `null`, the exception's stack trace
325: * is not printed.
326: * @return $this
327: */
328: public function exception(
329: Throwable $exception,
330: int $level = Level::ERROR,
331: ?int $traceLevel = Level::DEBUG
332: );
333:
334: /**
335: * Print a "command finished" message with a summary of errors, warnings and
336: * resource usage
337: *
338: * @return $this
339: */
340: public function summary(
341: string $finishedText = 'Command finished',
342: string $successText = 'without errors',
343: bool $withResourceUsage = false,
344: bool $withoutErrorCount = false,
345: bool $withStandardMessageType = false
346: );
347:
348: /**
349: * Print "$msg" to registered targets
350: *
351: * @param Level::* $level
352: * @param MessageType::* $type
353: * @return $this
354: */
355: public function print(
356: string $msg,
357: int $level = Level::INFO,
358: int $type = MessageType::UNFORMATTED
359: );
360:
361: /**
362: * Print "$msg" to registered STDOUT or STDERR targets
363: *
364: * @param Level::* $level
365: * @param MessageType::* $type
366: * @return $this
367: */
368: public function printOut(
369: string $msg,
370: int $level = Level::INFO,
371: int $type = MessageType::UNFORMATTED
372: );
373:
374: /**
375: * Print "$msg" to registered TTY targets
376: *
377: * @param Level::* $level
378: * @param MessageType::* $type
379: * @return $this
380: */
381: public function printTty(
382: string $msg,
383: int $level = Level::INFO,
384: int $type = MessageType::UNFORMATTED
385: );
386:
387: /**
388: * Print "$msg" to STDOUT even if no STDOUT target is registered
389: *
390: * @param Level::* $level
391: * @param MessageType::* $type
392: * @return $this
393: */
394: public function printStdout(
395: string $msg,
396: int $level = Level::INFO,
397: int $type = MessageType::UNFORMATTED
398: );
399:
400: /**
401: * Print "$msg" to STDERR even if no STDERR target is registered
402: *
403: * @param Level::* $level
404: * @param MessageType::* $type
405: * @return $this
406: */
407: public function printStderr(
408: string $msg,
409: int $level = Level::INFO,
410: int $type = MessageType::UNFORMATTED
411: );
412: }
413: