Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1429262
HookHandler.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
HookHandler.php
View Options
<?php
namespace
CommonsMetadata
;
use
CommonsMetadata\Hooks\SkinAfterBottomScriptsHandler
;
use
File
;
use
FormatMetadata
;
use
LocalRepo
;
use
MediaWiki\Content\Content
;
use
MediaWiki\Content\Hook\ContentAlterParserOutputHook
;
use
MediaWiki\Context\DerivativeContext
;
use
MediaWiki\Context\IContextSource
;
use
MediaWiki\Hook\GetExtendedMetadataHook
;
use
MediaWiki\Hook\SkinAfterBottomScriptsHook
;
use
MediaWiki\Hook\ValidateExtendedMetadataCacheHook
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Parser\ParserOutput
;
use
MediaWiki\Title\Title
;
use
Skin
;
use
Wikimedia\Bcp47Code\Bcp47Code
;
/**
* Hook handler
*/
class
HookHandler
implements
GetExtendedMetadataHook
,
ValidateExtendedMetadataCacheHook
,
ContentAlterParserOutputHook
,
SkinAfterBottomScriptsHook
{
/**
* Metadata version. When getting metadata of a remote file via the API, sometimes
* we get the data generated by a CommonsMetadata extension installed at the remote,
* as well. We use this version number to keep track of whether that data is different
* from what would be generated here.
* @var float
*/
private
const
VERSION
=
1.2
;
/**
* Hook handler for extended metadata
*
* @param array &$combinedMeta Metadata so far
* @param File $file The file object in question
* @param IContextSource $context Context. Used to select language
* @param bool $singleLang Get only target language, or all translations
* @param int &$maxCache How many seconds to cache the result
*/
public
function
onGetExtendedMetadata
(
&
$combinedMeta
,
$file
,
$context
,
$singleLang
,
&
$maxCache
)
{
global
$wgCommonsMetadataForceRecalculate
;
if
(
isset
(
$combinedMeta
[
'CommonsMetadataExtension'
][
'value'
]
)
&&
$combinedMeta
[
'CommonsMetadataExtension'
][
'value'
]
==
self
::
VERSION
&&
!
$wgCommonsMetadataForceRecalculate
)
{
// This is a file from a remote API repo, and CommonsMetadata is installed on
// the remote as well, and generates the same metadata format. We have nothing to do.
return
;
}
else
{
$combinedMeta
[
'CommonsMetadataExtension'
]
=
[
'value'
=>
self
::
VERSION
,
'source'
=>
'extension'
,
];
}
$lang
=
$context
->
getLanguage
();
$templateParser
=
new
TemplateParser
();
$templateParser
->
setMultiLanguage
(
!
$singleLang
);
$fallbacks
=
MediaWikiServices
::
getInstance
()->
getLanguageFallback
()->
getAll
(
$lang
->
getCode
()
);
array_unshift
(
$fallbacks
,
$lang
->
getCode
()
);
$templateParser
->
setPriorityLanguages
(
$fallbacks
);
$templateParser
->
setArtistCreditSeparator
(
$context
->
msg
(
'commonsmetadata-artistcredit-separator'
)->
text
()
);
$dataCollector
=
new
DataCollector
();
$dataCollector
->
setLanguage
(
$lang
);
$dataCollector
->
setMultiLang
(
!
$singleLang
);
$dataCollector
->
setTemplateParser
(
$templateParser
);
$dataCollector
->
setLicenseParser
(
new
LicenseParser
()
);
$dataCollector
->
collect
(
$combinedMeta
,
$file
);
if
(
!
$file
->
getDescriptionTouched
()
)
{
// Not all files provide the last update time of the description.
// If that's the case, just cache blindly for a shorter period.
$maxCache
=
60
*
60
*
12
;
}
}
/**
* Hook to check if cache is stale
*
* @param string $timestamp Timestamp of when cache taken
* @param File $file The file metadata is for
* @return bool Is metadata still valid
*/
public
function
onValidateExtendedMetadataCache
(
$timestamp
,
$file
)
{
return
// use cached value if...
// we don't know when the file was last updated
!
$file
->
getDescriptionTouched
()
// or last update was before we cached it
||
wfTimestamp
(
TS_UNIX
,
$file
->
getDescriptionTouched
()
)
<=
wfTimestamp
(
TS_UNIX
,
$timestamp
);
}
/**
* Check HTML output of a file page to see if it has all the basic metadata, and
* add tracking categories if it does not.
* @param Content $content
* @param Title $title
* @param ParserOutput $parserOutput
*/
public
function
onContentAlterParserOutput
(
$content
,
$title
,
$parserOutput
)
{
global
$wgCommonsMetadataSetTrackingCategories
;
if
(
!
$wgCommonsMetadataSetTrackingCategories
||
!
$title
->
inNamespace
(
NS_FILE
)
||
!
$parserOutput
->
hasText
()
||
$content
->
getModel
()
!==
CONTENT_MODEL_WIKITEXT
)
{
return
;
}
/*
* We also need to check if the file can be found. This is pretty straightforward, except
* for when a file gets moved: the old & new file details are cached, and cache is purged
* later on, in a DeferredUpdate.
* We could just `$repo->findFile( $title, [ 'ignoreRedirect' => true, 'latest' => true ] )`
* to force it to always check the database, but apart from file moves, the data in cache
* (if any) is usually just fine.
* Instead, we'll:
* * first test if `$title->isRedirect()`, to weed out the old (now renamed) title
* * attempt to fetch from cache, which should usually be fine
* * then fallback to DB, for files that have just been renamed
*/
$services
=
MediaWikiServices
::
getInstance
();
$trackingCategories
=
$services
->
getTrackingCategories
();
$repo
=
$services
->
getRepoGroup
()->
getLocalRepo
();
if
(
$title
->
isRedirect
()
)
{
return
;
}
$file
=
$repo
->
findFile
(
$title
,
[
'ignoreRedirect'
=>
true
]
);
if
(
$file
===
false
)
{
$file
=
$repo
->
findFile
(
$title
,
[
'ignoreRedirect'
=>
true
,
'latest'
=>
true
]
);
if
(
$file
===
false
)
{
return
;
}
}
$langCode
=
$parserOutput
->
getLanguage
()
??
$services
->
getContentLanguage
();
$dataCollector
=
self
::
getDataCollector
(
$langCode
,
true
);
$categoryKeys
=
$dataCollector
->
verifyAttributionMetadata
(
$parserOutput
,
$file
);
foreach
(
$categoryKeys
as
$key
)
{
$trackingCategories
->
addTrackingCategory
(
$parserOutput
,
'commonsmetadata-trackingcategory-'
.
$key
,
$title
);
}
}
/**
* @param Bcp47Code $langCode
* @param bool $singleLang
* @return DataCollector
*/
private
static
function
getDataCollector
(
Bcp47Code
$langCode
,
$singleLang
)
{
$templateParser
=
new
TemplateParser
();
$templateParser
->
setMultiLanguage
(
!
$singleLang
);
$fallbacks
=
MediaWikiServices
::
getInstance
()->
getLanguageFallback
()->
getAll
(
$langCode
->
toBcp47Code
()
);
array_unshift
(
$fallbacks
,
$langCode
->
toBcp47Code
()
);
$templateParser
->
setPriorityLanguages
(
$fallbacks
);
$templateParser
->
setArtistCreditSeparator
(
wfMessage
(
'commonsmetadata-artistcredit-separator'
)->
text
()
);
$lang
=
MediaWikiServices
::
getInstance
()->
getLanguageFactory
()->
getLanguage
(
$langCode
);
$dataCollector
=
new
DataCollector
();
$dataCollector
->
setLanguage
(
$lang
);
$dataCollector
->
setMultiLang
(
!
$singleLang
);
$dataCollector
->
setTemplateParser
(
$templateParser
);
$dataCollector
->
setLicenseParser
(
new
LicenseParser
()
);
return
$dataCollector
;
}
/**
* Injects an inline JSON-LD script schema with image license info.
*
* See https://phabricator.wikimedia.org/T254039. This only adds the script
* to File pages.
*
* @param Skin $skin
* @param string &$html
*/
public
function
onSkinAfterBottomScripts
(
$skin
,
&
$html
)
{
$title
=
$skin
->
getOutput
()->
getTitle
();
$isFilePage
=
$title
->
inNamespace
(
NS_FILE
);
if
(
!
$title
||
!
$title
->
exists
()
||
!
$isFilePage
)
{
return
;
}
$localRepo
=
MediaWikiServices
::
getInstance
()->
getRepoGroup
()->
getLocalRepo
();
// Get and prepare FormatMetadata object.
$format
=
new
FormatMetadata
;
$context
=
new
DerivativeContext
(
$format
->
getContext
()
);
// Language doesn't matter so just use en to improve performance.
$format
->
setSingleLanguage
(
true
);
$context
->
setLanguage
(
'en'
);
$format
->
setContext
(
$context
);
// Get URL for public domain page from config.
$config
=
MediaWikiServices
::
getInstance
()->
getConfigFactory
()->
makeConfig
(
'CommonsMetadata'
);
$publicDomainPageUrl
=
$config
->
get
(
'CommonsMetadataPublicDomainPageUrl'
);
$handler
=
new
SkinAfterBottomScriptsHandler
(
$format
,
$publicDomainPageUrl
);
$html
.=
$this
->
doSkinAfterBottomScripts
(
$localRepo
,
$handler
,
$title
);
}
/**
* Get schema script html (or empty string).
*
* @param LocalRepo $localRepo
* @param SkinAfterBottomScriptsHandler $handler
* @param Title $title
* @return string
*/
public
function
doSkinAfterBottomScripts
(
LocalRepo
$localRepo
,
SkinAfterBottomScriptsHandler
$handler
,
Title
$title
)
{
$file
=
$localRepo
->
newFile
(
$title
);
return
$handler
->
getSchemaElement
(
$title
,
$file
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 17:20 (10 h, 23 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
8f/cb/4b4de868802d87f59c436dacc826
Default Alt Text
HookHandler.php (8 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment