Skip to content

Commit

Permalink
(refactor) Turn EventCalendar class into a service
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardspec committed Dec 16, 2024
1 parent 8153fca commit a0da415
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 24 deletions.
2 changes: 0 additions & 2 deletions .phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
<arg name="encoding" value="UTF-8" />

<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationProtected" />
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic" />
<exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
</rule>
</ruleset>
13 changes: 12 additions & 1 deletion extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,16 @@
"MediaWiki\\JsCalendar\\HtmlSanitizer": "includes/HtmlSanitizer.php",
"MediaWiki\\JsCalendar\\Hooks": "includes/Hooks.php"
},
"HookHandlers": {
"main": {
"class": "MediaWiki\\JsCalendar\\Hooks",
"services": [
"JsCalendar.EventCalendar"
]
}
},
"Hooks": {
"ParserFirstCallInit": "MediaWiki\\JsCalendar\\Hooks::onParserFirstCallInit"
"ParserFirstCallInit": "main"
},
"config": {
"ECMaxCacheTime": {
Expand All @@ -66,5 +74,8 @@
"description": "Version of FullCalendar library to use (this library is responsible for how the calendar is displayed). The only supported values are 2 (default) and 5 (experimental)."
}
},
"ServiceWiringFiles": [
"includes/ServiceWiring.php"
],
"manifest_version": 2
}
69 changes: 52 additions & 17 deletions includes/EventCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,64 @@
use DateTime;
use FormatJson;
use Html;
use MediaWiki\MediaWikiServices;
use Language;
use MediaWiki\Config\ServiceOptions;
use MWException;
use ObjectCache;
use Parser;
use ReadOnlyMode;
use Title;
use Wikimedia\Rdbms\ILoadBalancer;

class EventCalendar {
/** @var ServiceOptions */
protected $options;

/** @var ILoadBalancer */
protected $loadBalancer;

/** @var Language */
protected $contentLanguage;

/** @var ReadOnlyMode */
protected $readOnlyMode;

public const CONSTRUCTOR_OPTIONS = [
'ECMaxCacheTime',
'JsCalendarFullCalendarVersion'
];

/**
* @param ServiceOptions $options
* @param ILoadBalancer $loadBalancer
* @param Language $contentLanguage
* @param ReadOnlyMode $readOnlyMode
*/
public function __construct(
ServiceOptions $options,
ILoadBalancer $loadBalancer,
Language $contentLanguage,
ReadOnlyMode $readOnlyMode
) {
$this->options = $options;
$this->loadBalancer = $loadBalancer;
$this->contentLanguage = $contentLanguage;
$this->readOnlyMode = $readOnlyMode;
}

/**
* @var int
* For multiple calendars on the same page: they will be named Calendar1, Calendar2, etc.
*/
protected static $calendarsCounter = 0;
protected $calendarsCounter = 0;

/**
* Calculate an array of events in the format expected by JavaScript side of the calendar.
* @param array $opt Parameters obtained from contents of <eventcalendar> tag.
* @param Parser $recursiveParser Parser object that is being used to render <EventCalendar>.
* @return array
*/
public static function findEvents( array $opt, Parser $recursiveParser ) {
public function findEvents( array $opt, Parser $recursiveParser ) {
$namespaceIdx = $opt['namespace'] ?? NS_MAIN;
$prefix = $opt['prefix'] ?? '';
$suffix = $opt['suffix'] ?? '';
Expand Down Expand Up @@ -103,7 +140,7 @@ public static function findEvents( array $opt, Parser $recursiveParser ) {
$res = $query->getResult();

// Obtain connections to DB/cache that may or may not be used for storing snippets in cache.
$dbw = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_PRIMARY );
$dbw = $this->loadBalancer->getConnection( DB_PRIMARY );
$dbCache = ObjectCache::getInstance( CACHE_DB );

$eventmap = [];
Expand Down Expand Up @@ -207,7 +244,7 @@ public static function findEvents( array $opt, Parser $recursiveParser ) {
// NOTE: the reason why we don't use $dbCache->set() here is that SqlBagOStuff::set() will do
// both compression and serialization, and decoding this is in protected methods.
// We don't want all that code duplication here, so we store HTML snippet in raw form.
if ( !MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
if ( !$this->readOnlyMode->isReadOnly() ) {
$dbw->insert( 'objectcache', [
'keyname' => $dbCache->makeKey( 'jscalendar-snippet-' . $row->latest ),
'value' => $snippet,
Expand Down Expand Up @@ -307,12 +344,9 @@ public static function findEvents( array $opt, Parser $recursiveParser ) {
* @param Parser $parser
* @return array|string
*/
public static function renderEventCalendar( $input, Parser $parser ) {
// config variables
global $wgECMaxCacheTime, $wgJsCalendarFullCalendarVersion;

public function renderCalendar( $input, Parser $parser ) {
$modules = [];
switch ( $wgJsCalendarFullCalendarVersion ) {
switch ( intval( $this->options->get( 'JsCalendarFullCalendarVersion' ) ) ) {
case 2:
$modules[] = 'ext.yasec';
break;
Expand All @@ -322,14 +356,15 @@ public static function renderEventCalendar( $input, Parser $parser ) {
break;

default:
throw new MWException( 'Unsupported value of $wgJsCalendarFullCalendarVersion (' .
$wgJsCalendarFullCalendarVersion . '): can only be 2 or 5.' );
throw new MWException(
'Unsupported value of $wgJsCalendarFullCalendarVersion: can only be 2 or 5.' );
}

$parser->getOutput()->addModules( $modules );

if ( $wgECMaxCacheTime !== false ) {
$parser->getOutput()->updateCacheExpiry( $wgECMaxCacheTime );
$cacheTime = $this->options->get( 'ECMaxCacheTime' );
if ( $cacheTime !== false ) {
$parser->getOutput()->updateCacheExpiry( $cacheTime );
}

// Parse the contents of the tag ($input string) for parameters.
Expand All @@ -345,13 +380,13 @@ public static function renderEventCalendar( $input, Parser $parser ) {
$val = trim( $keyval[1] );

if ( $key == 'namespace' ) {
$val = MediaWikiServices::getInstance()->getContentLanguage()->getNsIndex( $val );
$val = $this->contentLanguage->getNsIndex( $val );
}

$options[$key] = $val;
}

$events = self::findEvents( array_filter( $options ), $parser );
$events = $this->findEvents( array_filter( $options ), $parser );

// calendar container and data array
$scriptHtml = '';
Expand All @@ -360,7 +395,7 @@ public static function renderEventCalendar( $input, Parser $parser ) {

$attr = [
'class' => 'eventcalendar',
'id' => 'eventcalendar-' . ( ++ self::$calendarsCounter )
'id' => 'eventcalendar-' . ( ++$this->calendarsCounter )
];

$height = $options['height'] ?? 0;
Expand Down
19 changes: 15 additions & 4 deletions includes/Hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,25 @@
use Parser;

class Hooks {

/** @var EventCalendar */
protected $eventCalendar;

/**
* @param EventCalendar $eventCalendar
*/
public function __construct( EventCalendar $eventCalendar ) {
$this->eventCalendar = $eventCalendar;
}

/**
* Set up the <EventCalendar> tag.
*
* @param Parser $parser
* @return true
*/
public static function onParserFirstCallInit( Parser $parser ) {
$parser->setHook( 'EventCalendar', '\MediaWiki\JsCalendar\Hooks::parserFunction' );
public function onParserFirstCallInit( Parser $parser ) {
$parser->setHook( 'EventCalendar', [ $this, 'parserFunction' ] );
return true;
}

Expand All @@ -44,7 +55,7 @@ public static function onParserFirstCallInit( Parser $parser ) {
* @param Parser $parser
* @return array|string
*/
public static function parserFunction( $input, $args, Parser $parser ) {
return EventCalendar::renderEventCalendar( $input, $parser );
public function parserFunction( $input, $args, Parser $parser ) {
return $this->eventCalendar->renderCalendar( $input, $parser );
}
}
46 changes: 46 additions & 0 deletions includes/ServiceWiring.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/**
* Implements the JsCalendar extension for MediaWiki.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/

namespace MediaWiki\JsCalendar;

use MediaWiki\Config\ServiceOptions;
use MediaWiki\MediaWikiServices;

// @codeCoverageIgnoreStart

return [
'JsCalendar.EventCalendar' =>
static function ( MediaWikiServices $services ): EventCalendar {
return new EventCalendar(
new ServiceOptions(
EventCalendar::CONSTRUCTOR_OPTIONS,
$services->getMainConfig()
),
$services->getDBLoadBalancer(),
$services->getContentLanguage(),
$services->getReadOnlyMode()
);
}
];

// @codeCoverageIgnoreEnd

0 comments on commit a0da415

Please sign in to comment.