Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
52.17% covered (warning)
52.17%
12 / 23
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Logger_Settings_Trait
52.17% covered (warning)
52.17%
12 / 23
33.33% covered (danger)
33.33%
2 / 6
24.24
0.00% covered (danger)
0.00%
0 / 1
 get_log_level
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 get_log_levels
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 get_plugin_name
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 get_plugin_slug
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_plugin_basename
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 get_cli_base
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Default function implementations for classes implementing `Logger_Settings_Interface`.
4 *
5 * These functions infer the current plugin's basename, name, log level.
6 *
7 * It is faster to provide your own implementation of each function.
8 *
9 * A Settings class should `implements Logger_Settings_Interface` and `use Logger_Settings_Trait`
10 * then override all the functions. This allows more functions to be added to the interface in future
11 * library updates without requiring projects to implement the new functions, i.e. it provides
12 * forward-compatibility.
13 *
14 * @package brianhenryie/bh-wp-logger
15 */
16
17namespace BrianHenryIE\WP_Logger;
18
19use BrianHenryIE\WP_Logger\WP_Includes\CLI;
20use Exception;
21use Psr\Log\LogLevel;
22use ReflectionClass;
23
24/**
25 * Default function implementations for Logger_Settings_Interface.
26 *
27 * @see Logger_Settings_Interface
28 */
29trait Logger_Settings_Trait {
30
31    /**
32     * The log level to use.
33     *
34     * Default is Info.
35     * Looks for saved value in `get_option( 'my-plugin-slug_log_level' ).
36     *
37     * @see LogLevel
38     */
39    public function get_log_level(): string {
40        try {
41            $saved_option = get_option( $this->get_plugin_slug() . '_log_level' );
42            return is_string( $saved_option )
43                    && in_array(
44                        $saved_option,
45                        $this->get_log_levels(),
46                        true
47                    )
48                    ? $saved_option
49                    : LogLevel::INFO;
50        } catch ( Exception ) {
51            return LogLevel::INFO;
52        }
53    }
54
55    /**
56     * @var string[] $log_levels
57     */
58    protected array $log_levels;
59
60    /**
61     * Returns all valid log levels. Only computes it once.
62     *
63     * @see LogLevel
64     *
65     * @return string[]
66     */
67    protected function get_log_levels(): array {
68        if ( ! isset( $this->log_levels ) ) {
69            $this->log_levels = array_values( ( new ReflectionClass( LogLevel::class ) )->getConstants() );
70        }
71        return $this->log_levels;
72    }
73
74    /**
75     * The plugin friendly name to use in UIs.
76     *
77     * @throws Exception When the basename cannot be determined.
78     */
79    public function get_plugin_name(): string {
80        $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $this->get_plugin_basename() );
81        return $plugin_data['Name'];
82    }
83
84    /**
85     * The plugin slug. I.e. the plugin directory name. Used in URLs and wp_options.
86     *
87     * @throws Exception When the basename cannot be determined.
88     */
89    public function get_plugin_slug(): string {
90        return explode( '/', $this->get_plugin_basename() )[0];
91    }
92
93    /**
94     * The plugin basename. Used to add the Logs link on `plugins.php`.
95     *
96     * @see https://core.trac.wordpress.org/ticket/42670
97     *
98     * @throws Exception When it cannot be determined. I.e. a symlink inside a symlink.
99     */
100    public function get_plugin_basename(): string {
101
102        /**
103         * TODO: The following might work but there are known issues around symlinks that need to be tested and handled correctly.
104         *
105         * @see  https://core.trac.wordpress.org/ticket/42670
106         */
107
108        $wp_plugin_basename = plugin_basename( __DIR__ );
109
110        /** @var array<string, array<string>> $plugin_data */
111        $plugin_data = get_plugins( explode( '/', $wp_plugin_basename )[0] );
112
113        if ( 1 === count( $plugin_data ) ) {
114            return array_key_first( $plugin_data );
115        }
116
117        throw new Exception( 'Plugin installed in an unusual directory.' );
118    }
119
120    /**
121     * Default CLI commands to use the plugin slug as the base for commands.
122     *
123     * @see CLI
124     */
125    public function get_cli_base(): ?string {
126        return $this->get_plugin_slug();
127    }
128}