Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
93.94% |
31 / 33 |
|
66.67% |
4 / 6 |
CRAP | |
0.00% |
0 / 1 |
SimpleParsoidOutputStash | |
93.94% |
31 / 33 |
|
66.67% |
4 / 6 |
11.03 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
makeCacheKey | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
set | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
get | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
newSelserContextFromJson | |
88.89% |
8 / 9 |
|
0.00% |
0 / 1 |
3.01 | |||
selserContextToJsonArray | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Edit; |
4 | |
5 | use MediaWiki\Content\IContentHandlerFactory; |
6 | use Wikimedia\ObjectCache\BagOStuff; |
7 | use Wikimedia\Parsoid\Core\PageBundle; |
8 | |
9 | /** |
10 | * @internal |
11 | * @since 1.39 |
12 | */ |
13 | class SimpleParsoidOutputStash implements ParsoidOutputStash { |
14 | |
15 | /** @var BagOStuff */ |
16 | private $bagOfStuff; |
17 | |
18 | /** @var int */ |
19 | private $duration; |
20 | |
21 | /** @var IContentHandlerFactory */ |
22 | private $contentHandlerFactory; |
23 | |
24 | /** |
25 | * @param IContentHandlerFactory $contentHandlerFactory |
26 | * @param BagOStuff $bagOfStuff storage backend |
27 | * @param int $duration cache duration in seconds |
28 | */ |
29 | public function __construct( IContentHandlerFactory $contentHandlerFactory, BagOStuff $bagOfStuff, int $duration ) { |
30 | $this->bagOfStuff = $bagOfStuff; |
31 | $this->duration = $duration; |
32 | $this->contentHandlerFactory = $contentHandlerFactory; |
33 | } |
34 | |
35 | private function makeCacheKey( ParsoidRenderID $renderId ): string { |
36 | return $this->bagOfStuff->makeKey( 'ParsoidOutputStash', $renderId->getKey() ); |
37 | } |
38 | |
39 | /** |
40 | * Before we stash, we serialize & encode into JSON the relevant |
41 | * parts of the data we need to construct a page bundle in the future. |
42 | * |
43 | * @param ParsoidRenderID $renderId Combination of revision ID and revision's time ID |
44 | * @param SelserContext $selserContext |
45 | * |
46 | * @return bool |
47 | */ |
48 | public function set( ParsoidRenderID $renderId, SelserContext $selserContext ): bool { |
49 | $jsonic = $this->selserContextToJsonArray( $selserContext ); |
50 | |
51 | $key = $this->makeCacheKey( $renderId ); |
52 | return $this->bagOfStuff->set( $key, $jsonic, $this->duration ); |
53 | } |
54 | |
55 | /** |
56 | * This will decode the JSON data and create a page bundle from it |
57 | * if we have something in the stash that matches a given rendering or |
58 | * will just return an empty array if no entry in the stash. |
59 | * |
60 | * @param ParsoidRenderID $renderId |
61 | * |
62 | * @return SelserContext|null |
63 | */ |
64 | public function get( ParsoidRenderID $renderId ): ?SelserContext { |
65 | $key = $this->makeCacheKey( $renderId ); |
66 | $jsonic = $this->bagOfStuff->get( $key ) ?? []; |
67 | |
68 | if ( !is_array( $jsonic ) ) { |
69 | // Defend against old stashed data. |
70 | // Only needed for a couple of days after this code has been deployed. |
71 | return null; |
72 | } |
73 | |
74 | $selserContext = $this->newSelserContextFromJson( $jsonic ); |
75 | return $selserContext ?: null; |
76 | } |
77 | |
78 | private function newSelserContextFromJson( array $json ): ?SelserContext { |
79 | if ( !isset( $json['pb'] ) ) { |
80 | return null; |
81 | } |
82 | |
83 | // TODO: should use proper JsonCodec for this |
84 | $pb = PageBundle::newFromJsonArray( $json['pb'] ); |
85 | |
86 | $revId = (int)$json['revId']; |
87 | |
88 | if ( isset( $json['content'] ) ) { |
89 | $contentHandler = $this->contentHandlerFactory->getContentHandler( $json['content']['model'] ); |
90 | $content = $contentHandler->unserializeContent( $json['content']['data'] ); |
91 | } else { |
92 | $content = null; |
93 | } |
94 | |
95 | return new SelserContext( $pb, $revId, $content ); |
96 | } |
97 | |
98 | private function selserContextToJsonArray( SelserContext $selserContext ): array { |
99 | $json = [ |
100 | 'revId' => $selserContext->getRevisionID(), |
101 | ]; |
102 | |
103 | // TODO: should use proper JsonCodec for this |
104 | $json['pb'] = $selserContext->getPageBundle()->toJsonArray(); |
105 | |
106 | $content = $selserContext->getContent(); |
107 | if ( $content ) { |
108 | $json['content'] = [ |
109 | 'model' => $content->getModel(), |
110 | 'data' => $content->serialize() |
111 | ]; |
112 | } |
113 | |
114 | return $json; |
115 | } |
116 | |
117 | } |