Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.40% covered (warning)
81.40%
35 / 43
66.67% covered (warning)
66.67%
8 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Schema_Parser
81.40% covered (warning)
81.40%
35 / 43
66.67% covered (warning)
66.67%
8 / 12
21.32
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 set_context
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 or
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
2.06
 fallback
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 nullable
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 parse
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
 jsonSerialize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 schema
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 has_fallback
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 get_fallback
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
4.07
 get_log
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Automattic\Jetpack\Schema;
4
5use Automattic\Jetpack\Schema\Modifiers\Modifier_Fallback;
6use Automattic\Jetpack\Schema\Types\Type_Literal;
7use Automattic\Jetpack\Schema\Types\Type_Void;
8
9class Schema_Parser implements Parser {
10    /**
11     * Each Schema entry has a Parser that's able to parse a value.
12     *
13     * @var Parser
14     */
15    private $parser;
16
17    /**
18     * @var Schema_Context|null
19     */
20    private $context;
21
22    /**
23     * @param Parser $parser
24     */
25    public function __construct( Parser $parser ) {
26        $this->parser = $parser;
27    }
28
29    public function set_context( Schema_Context $context ) {
30        $this->context = $context;
31    }
32
33    public function __toString() {
34        return $this->parser->__toString();
35    }
36
37    /**
38     * Allow combining multiple types of schemas internally for easier fallbacks.
39     * For a public or API, use `Schema::either()` instead.
40     *
41     * @param Parser $parser
42     *
43     * @return $this
44     * @see Schema::either()
45     */
46    private function or( Parser $parser ) {
47        if ( $this->parser instanceof Modifier_Fallback ) {
48            $this->parser->add_fallback_parser( $parser );
49            return $this;
50        }
51
52        // Keep track of the current parser
53        $current_parser = $this->parser;
54        // Replace the current parser with a new Modifier_Fallback parser
55        $this->parser = new Modifier_Fallback();
56        // Add the current parser back
57        $this->parser->add_fallback_parser( $current_parser );
58        // Add the new parser
59        $this->parser->add_fallback_parser( $parser );
60        return $this;
61    }
62
63    /**
64     * Sets a fallback value for the schema type when the input data is invalid.
65     *
66     * @param mixed $default_value The fallback value to use when the input data is invalid.
67     *
68     * @throws Schema_Error When the input data is invalid and debug mode is enabled.
69     */
70    public function fallback( $default_value ) {
71
72        // In debug mode: Ensure that the fallback value can be parsed.
73        if ( Utils::is_debug() ) {
74            $this->parse( $default_value );
75        }
76
77        $this->or( new Type_Literal( $default_value ) );
78        return $this;
79    }
80
81    /**
82     * Turn this schema into a nullable schema.
83     * This means that the schema will accept `null` as a valid value.
84     *
85     * @return $this
86     */
87    public function nullable() {
88        $this->or( new Type_Void() );
89        return $this;
90    }
91
92    /**
93     * Parses the input data according to the schema type.
94     *
95     * @param mixed $value The input data to be parsed.
96     *
97     * @return mixed The parsed data according to the schema type.
98     * @throws Schema_Error When the input data is invalid.
99     */
100    public function parse( $value, $context = null ) {
101
102        $context ??= $this->context ?? new Schema_Context( 'unknown' );
103        $context->set_data( $value );
104        $parser = $this->parser;
105
106        try {
107            $context->verbose_log(
108                "Parse: {$parser}",
109                array(
110                    'value' => $value,
111                )
112            );
113            return $parser->parse( $value, $context );
114        } catch ( Schema_Error $e ) {
115            $context->log( "Schema_Error: {$this}->parse failed.", array(), $e );
116            throw new Schema_Error( $e->getMessage(), $e->get_value(), $context );
117        }
118    }
119
120    #[\ReturnTypeWillChange]
121    public function jsonSerialize() {
122        return $this->schema();
123    }
124
125    public function schema() {
126        return $this->parser->schema();
127    }
128
129    public function has_fallback() {
130        try {
131            $this->get_fallback();
132            return true;
133        } catch ( Schema_Error $e ) {
134            return false;
135        }
136    }
137
138    public function get_fallback() {
139        if ( $this->parser instanceof Modifier_Fallback ) {
140            $parsers = $this->parser->get_parsers();
141            foreach ( $parsers as $parser ) {
142                if ( $parser instanceof Type_Literal ) {
143                    return $parser->parse( null, $this->context );
144                }
145            }
146        }
147        throw new Schema_Error( 'No fallback value defined for this schema', null, $this->context );
148    }
149
150    public function get_log() {
151        return $this->context->get_log() ?? array();
152    }
153}