Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 37 |
|
0.00% |
0 / 14 |
CRAP | |
0.00% |
0 / 1 |
JCContent | |
0.00% |
0 / 37 |
|
0.00% |
0 / 14 |
420 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getData | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSafeData | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getRawData | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getStatus | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isValid | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isEmpty | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
isCountable | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
isValidJson | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
thorough | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
validate | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
parse | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
getView | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
createDefaultView | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace JsonConfig; |
4 | |
5 | use FormatJson; |
6 | use MediaWiki\Status\Status; |
7 | use stdClass; |
8 | |
9 | /** |
10 | * Represents the content of a JSON Json Config article. |
11 | * @file |
12 | * @ingroup Extensions |
13 | * @ingroup JsonConfig |
14 | * |
15 | * @author Yuri Astrakhan <yurik@wikimedia.org>, |
16 | * based on Ori Livneh <ori@wikimedia.org> extension schema |
17 | */ |
18 | class JCContent extends \TextContent { |
19 | /** @var mixed */ |
20 | private $rawData = null; |
21 | /** @var stdClass */ |
22 | protected $data = null; |
23 | /** @var Status */ |
24 | private $status; |
25 | /** @var bool */ |
26 | private $thorough; |
27 | /** @var bool */ |
28 | private $stripComments; |
29 | /** @var JCContentView|null contains an instance of the view class */ |
30 | private $view = null; |
31 | |
32 | /** |
33 | * @param string|null $text Json configuration. If null, default content will be inserted instead |
34 | * @param string $modelId |
35 | * @param bool $thorough True if extra validation should be performed |
36 | */ |
37 | public function __construct( $text, $modelId, $thorough ) { |
38 | $this->stripComments = $text !== null; |
39 | $text ??= $this->getView( $modelId )->getDefault( $modelId ); |
40 | parent::__construct( $text, $modelId ); |
41 | $this->thorough = $thorough; |
42 | $this->status = new Status(); |
43 | $this->parse(); |
44 | } |
45 | |
46 | /** |
47 | * Get validated data |
48 | * @return stdClass |
49 | */ |
50 | public function getData() { |
51 | return $this->data; |
52 | } |
53 | |
54 | /** |
55 | * Returns data after sanitization, suitable for third-party use |
56 | * |
57 | * @param stdClass $data |
58 | * @return stdClass |
59 | */ |
60 | public function getSafeData( $data ) { |
61 | return $data; |
62 | } |
63 | |
64 | /** |
65 | * Returns JSON object as resulted from parsing initial text, |
66 | * before any validation/modifications took place |
67 | * @return mixed |
68 | */ |
69 | public function getRawData() { |
70 | return $this->rawData; |
71 | } |
72 | |
73 | /** |
74 | * Get content status object |
75 | * @return Status |
76 | */ |
77 | public function getStatus() { |
78 | return $this->status; |
79 | } |
80 | |
81 | /** |
82 | * @return bool False if this configuration has parsing or validation errors |
83 | */ |
84 | public function isValid() { |
85 | return $this->status->isGood(); |
86 | } |
87 | |
88 | public function isEmpty() { |
89 | $text = trim( $this->getNativeData() ); |
90 | return $text === '' || $text === '{}'; |
91 | } |
92 | |
93 | /** |
94 | * Determines whether this content should be considered a "page" for statistics |
95 | * In our case, just making sure it's not empty or a redirect |
96 | * @param bool|null $hasLinks |
97 | * @return bool |
98 | */ |
99 | public function isCountable( $hasLinks = null ) { |
100 | return !$this->isEmpty() && !$this->isRedirect(); |
101 | } |
102 | |
103 | /** |
104 | * Returns true if the text is in JSON format. |
105 | * @return bool |
106 | */ |
107 | public function isValidJson() { |
108 | return $this->rawData !== null; |
109 | } |
110 | |
111 | /** |
112 | * @return bool true if thorough validation may be needed - |
113 | * e.g. rendering HTML or saving new value |
114 | */ |
115 | public function thorough() { |
116 | return $this->thorough; |
117 | } |
118 | |
119 | /** |
120 | * Override this method to perform additional data validation |
121 | * @param mixed $data |
122 | * @return stdClass |
123 | */ |
124 | public function validate( $data ) { |
125 | return $data; |
126 | } |
127 | |
128 | /** |
129 | * Perform initial json parsing and validation |
130 | */ |
131 | private function parse() { |
132 | $rawText = $this->getNativeData(); |
133 | $parseOpts = FormatJson::TRY_FIXING; |
134 | if ( $this->stripComments ) { |
135 | $parseOpts += FormatJson::STRIP_COMMENTS; |
136 | } |
137 | $status = FormatJson::parse( $rawText, $parseOpts ); |
138 | if ( !$status->isOK() ) { |
139 | $this->status = $status; |
140 | return; |
141 | } |
142 | $data = $status->getValue(); |
143 | // @fixme: HACK - need a deep clone of the data |
144 | // @fixme: but doing (object)(array)$data will re-encode empty [] as {} |
145 | // @performance: re-encoding is likely faster than stripping comments in PHP twice |
146 | $this->rawData = FormatJson::decode( |
147 | FormatJson::encode( $data, false, FormatJson::ALL_OK ), true |
148 | ); |
149 | $this->data = $this->validate( $data ); |
150 | } |
151 | |
152 | /** |
153 | * Get a view object for this content object |
154 | * @internal Only public for JCContentHandler |
155 | * |
156 | * @param string $modelId is required here because parent ctor might not have ran yet |
157 | * @return JCContentView |
158 | */ |
159 | public function getView( $modelId ) { |
160 | global $wgJsonConfigModels; |
161 | if ( !$this->view ) { |
162 | $configModels = \ExtensionRegistry::getInstance()->getAttribute( 'JsonConfigModels' ) |
163 | + $wgJsonConfigModels; |
164 | $class = $configModels[$modelId]['view'] ?? null; |
165 | $this->view = $class ? new $class() : $this->createDefaultView(); |
166 | } |
167 | return $this->view; |
168 | } |
169 | |
170 | /** |
171 | * In case view is not associated with the model for this class, this function will instantiate |
172 | * a default. Override may instantiate a more appropriate view |
173 | * @return JCContentView |
174 | */ |
175 | protected function createDefaultView() { |
176 | return new JCDefaultContentView(); |
177 | } |
178 | } |