Your IP : 216.73.216.54


Current Path : /var/www/html/mediawiki-1.43.1/extensions/PageProperties/includes/
Upload File :
Current File : /var/www/html/mediawiki-1.43.1/extensions/PageProperties/includes/PageProperties.php

<?php
/**
 * This file is part of the MediaWiki extension PageProperties.
 *
 * PageProperties 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.
 *
 * PageProperties 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 PageProperties.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @file
 * @ingroup extensions
 * @author thomas-topway-it <support@topway.it>
 * @copyright Copyright ©2021-2024, https://wikisphere.org
 */

use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;

if ( is_readable( __DIR__ . '/../vendor/autoload.php' ) ) {
	include_once __DIR__ . '/../vendor/autoload.php';
}

class PageProperties {

	/** @var array */
	protected static $cachedPageProperties = [];

	/** @var User */
	public static $User;

	/** @var UserGroupManager */
	private static $userGroupManager;

	/** @var Logger */
	private static $Logger;

	/** @var int */
	public static $queryLimit = 500;

	/**
	 * @return void
	 */
	public static function initialize() {
		self::$Logger = LoggerFactory::getInstance( 'PageProperties' );
		self::$User = RequestContext::getMain()->getUser();
		self::$userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
	}

	/**
	 * @param Title $title
	 * @param OutputPage $outputPage
	 * @return void
	 */
	public static function setJsonLD( $title, $outputPage ) {
		if ( !class_exists( '\EasyRdf\Graph' ) || !class_exists( '\ML\JsonLD\JsonLD' ) ) {
			return;
		}

		// @TODO use directly the function makeExportDataForSubject
		// SemanticMediawiki/includes/export/SMW_Exporter.php
		$export_rdf = SpecialPage::getTitleFor( 'ExportRDF' );
		if ( $export_rdf->isKnown() ) {
			$export_url = $export_rdf->getFullURL( [ 'page' => $title->getFullText(), 'recursive' => '1', 'backlinks' => 0 ] );

			try {
				$foaf = new \EasyRdf\Graph( $export_url );
				$foaf->load();

				$format = \EasyRdf\Format::getFormat( 'jsonld' );
				$output = $foaf->serialise( $format, [
					// ***see vendor/easyrdf/easyrdf/lib/Serialiser/JsonLd.php
					// this will convert
					// [{"@value":"a"},{"@value":"b"}]
					// to ["a", "b"]
					'compact' => true,
				] );

			} catch ( Exception $e ) {
				self::$Logger->error( 'EasyRdf error: ' . $export_url );
				return;
			}

			// https://hotexamples.com/examples/-/EasyRdf_Graph/serialise/php-easyrdf_graph-serialise-method-examples.html
			if ( is_scalar( $output ) ) {
				$outputPage->addHeadItem( 'json-ld', Html::Element(
						'script', [ 'type' => 'application/ld+json' ], $output
					)
				);
			}
		}
	}

	/**
	 * @param Title $title
	 * @param array $conds_ null
	 * @return array|false
	 */
	public static function getPageProperties( $title, $conds_ = [] ) {
		if ( !$title || !$title->canExist() ) {
			return false;
		}

		$page_id = $title->getArticleID();
		if ( !$title->isKnown() || empty( $page_id ) ) {
			return false;
		}

		if ( array_key_exists( $page_id, self::$cachedPageProperties ) ) {
			return self::$cachedPageProperties[ $page_id ];
		}
		$conds = [];
		if ( !empty( $page_id ) ) {
			$conds['page_id'] = $page_id;
		}
		$dbr = self::getDB( DB_REPLICA );

		if ( !$dbr->tableExists( 'pageproperties_pageproperties' ) ) {
			return false;
		}

		$row = $dbr->selectRow(
			'pageproperties_pageproperties',
			'*',
			array_merge( $conds, $conds_ ),
			__METHOD__
		);

		if ( !$row ) {
			// phpcs:ignore MediaWiki.Usage.AssignmentInReturn.AssignmentInReturn
			return self::$cachedPageProperties[ $page_id ] = false;
		}

		$row = (array)$row;
		$row['meta'] = ( empty( $row['meta'] ) ? []
			: json_decode( $row['meta'], true ) );

		// phpcs:ignore MediaWiki.Usage.AssignmentInReturn.AssignmentInReturn
		return self::$cachedPageProperties[ $page_id ] = $row;
	}

	/**
	 * @param Title $title
	 * @param array $obj
	 * @param array &$errors null
	 * @return array|false
	 */
	public static function setPageProperties( $title, $obj, &$errors = [] ) {
		$page_id = $title->getArticleID();
		$date = date( 'Y-m-d H:i:s' );
		$obj['updated_at'] = $date;
		$obj['meta'] = ( !empty( $obj[ 'meta' ] ) ? json_encode( $obj[ 'meta' ] )
			: null );

		$dbr = self::getDB( DB_PRIMARY );
		if ( self::getPageProperties( $title ) === false ) {
			$obj['page_id'] = $page_id;
			$obj['created_at'] = $date;
			$res = $dbr->insert(
				'pageproperties_pageproperties',
				$obj
			);
		} else {
			$res = $dbr->update(
				'pageproperties_pageproperties',
				$obj,
				[ 'page_id' => $page_id ],
				__METHOD__
			);
		}
		// always true
		return $res;
	}

	/**
	 * @param Title $title
	 * @param OutputPage $outputPage
	 * @return void
	 */
	public static function setMetaAndTitle( $title, $outputPage ) {
		global $wgSitename;
		$meta = [];
		$mainPage = Title::newMainPage();

		// the current page is different than the main page
		if ( $mainPage->getPrefixedDBkey() != $title->getPrefixedDBkey() ) {
			$pageProperties = self::getPageProperties( $mainPage, [ 'meta_entire_site' => 1 ] );

			if ( !empty( $pageProperties['meta_entire_site'] )
				&& !empty( $pageProperties['meta'] ) ) {
				$meta = $pageProperties['meta'];
			}
		}

		// retrieve page properties of all ancestors including
		// current page
		$meta = array_merge( $meta, self::getMergedMetas( $title ) );

		if ( !empty( $meta ) ) {
			$meta_underscored = [];
			array_walk( $meta, static function ( $value, $key ) use( &$meta_underscored ) {
				$meta_underscored[ str_replace( ' ', '_', $key ) ] = $value;
			} );

			if ( class_exists( 'MediaWiki\Extension\WikiSEO\WikiSEO' ) ) {
				$seo = new MediaWiki\Extension\WikiSEO\WikiSEO();
				$seo->setMetadata( $meta_underscored );
				$seo->addMetadataToPage( $outputPage );

			} else {
				self::addMetaToPage( $outputPage, $meta_underscored );
			}
		}

		$page_title = self::getDisplayTitle( $title );

		if ( $page_title !== false ) {
			// can be different from the html title
			$outputPage->setPageTitle( $page_title );

			// required by SkinWMAU
			$outputPage->setDisplayTitle( $page_title );

		} else {
			$page_title = $title->getText();
			if ( !empty( $GLOBALS['wgPagePropertiesDisplayAlwaysUnprefixedTitles'] ) ) {
				$outputPage->setPageTitle( $page_title );

				// required by SkinWMAU
				$outputPage->setDisplayTitle( $page_title );
			}
		}

		// page_title can be an empty string
		if ( empty( $page_title ) ) {
			$outputPage->addHeadItem( 'pageproperties_empty_title', '<style>h1 { border: none; } .mw-body .firstHeading { border-bottom: none; margin-bottom: 0; margin-top: 0; } </style>' );
		}

		$html_title_already_set = ( array_key_exists( 'title', $meta ) && class_exists( 'MediaWiki\Extension\WikiSEO\WikiSEO' ) );

		if ( $html_title_already_set ) {
			return;
		}

		if ( empty( $page_title ) && !array_key_exists( 'title', $meta ) ) {
			$html_title = '';

			if ( $wgSitename != $title->getText() ) {
				$html_title = $title->getText() . ' - ';
			}

			$html_title .= $wgSitename;
			$outputPage->setHTMLTitle( $html_title );

		} elseif ( array_key_exists( 'title', $meta ) ) {
			$outputPage->setHTMLTitle( $meta[ 'title' ] );
		}
	}

	/**
	 * @param Title $title
	 * @return array
	 */
	private static function getMergedMetas( $title ) {
		$page_ancestors = self::page_ancestors( $title, false );

		$output = [];
		foreach ( $page_ancestors as $title_ ) {
			$pageProperties_ = self::getPageProperties( $title_ );

			if ( !empty( $pageProperties_ )
				 && ( !empty( $pageProperties_['meta_subpages'] ) || $title_->getArticleID() == $title->getArticleID() )
				 && !empty( $pageProperties_['meta'] ) ) {
					$output = array_merge( $output, $pageProperties_['meta'] );
			}
		}

		return $output;
	}

	/**
	 * @param OutputPage $outputPage
	 * @param array $meta
	 * @return void
	 */
	private static function addMetaToPage( $outputPage, $meta ) {
		// Meta tags already set in the page
		$outputMeta = [];

		foreach ( $outputPage->getMetaTags() as $metaTag ) {
			$outputMeta[ $metaTag[0] ] = $metaTag[1];
		}

		foreach ( $meta as $k => $v ) {
			if ( strpos( $k, 'hreflang' ) !== false ) {
				$outputPage->addHeadItem( $k, Html::element( 'link', [ 'rel' => 'alternate', 'href' => $v, 'hreflang' => substr( $k, 9 ) ] ) );
				continue;
			}

			if ( strpos( $k, ':' ) === false ) {
				if ( !array_key_exists( $k, $outputMeta ) ) {
					$outputPage->addMeta( $k, $v );
				}

			} else {
				$outputPage->addHeadItem( $k, Html::element( 'meta', [ 'property' => $k, 'content'  => $v ] ) );
			}
		}
	}

	/**
	 * @param Title $title
	 * @return mixed
	 */
	public static function getDisplayTitle( $title ) {
		$pageProperties = self::getPageProperties( $title );
		// display title can be null
		if ( $pageProperties !== false
			&& $pageProperties['display_title'] !== null ) {
			return $pageProperties['display_title'];
		}
		return false;
	}

	/**
	 * @param Title $title
	 * @return bool
	 */
	public static function isKnownArticle( $title ) {
		// *** unfortunately we cannot always rely on $title->isContentPage()
		// @see https://github.com/debtcompliance/EmailPage/pull/4#discussion_r1191646022
		// or use $title->exists()
		return ( $title && $title->canExist() && $title->getArticleID() > 0
			&& $title->isKnown() );
	}

	/**
	 * @param Title $title
	 * @return WikiPage|null
	 */
	public static function getWikiPage( $title ) {
		if ( !$title || !$title->canExist() ) {
			return null;
		}
		// MW 1.36+
		if ( method_exists( MediaWikiServices::class, 'getWikiPageFactory' ) ) {
			return MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
		}
		return WikiPage::factory( $title );
	}

	/**
	 * @return array
	 */
	public static function getUserGroups() {
		$user = self::$User;
		$UserGroupManager = self::$userGroupManager;
		$user_groups = array_unique( array_merge(
			$UserGroupManager->getUserEffectiveGroups( $user ),
			$UserGroupManager->getUserImplicitGroups( $user )
		) );
		// $key = array_search( '*', $user_groups );
		// $user_groups[ $key ] = 'all';
		return $user_groups;
	}

	/**
	 * @param Title $title
	 * @param bool $exclude_current
	 * @return array
	 */
	public static function page_ancestors( $title, $exclude_current = true ) {
		$output = [];

		$title_parts = explode( '/', $title->getText() );

		if ( $exclude_current ) {
			array_pop( $title_parts );
		}

		$path = [];

		foreach ( $title_parts as $value ) {
			$path[] = $value;
			$title_text = implode( '/', $path );

			if ( $title->getText() == $title_text ) {
				$output[] = $title;

			} else {
				$title_ = Title::newFromText( $title_text );
				if ( $title_ && $title_->isKnown() ) {
					$output[] = $title_;
				}
			}
		}

		return $output;
	}

	/**
	 * @param string $titleText
	 * @return string
	 */
	public static function currentSubpage( $titleText ) {
		// @see skins/skin.php -> subPageSubtitle()
		$arr = explode( '/', $titleText );
		$ret = '';
		$growinglink = '';
		$display = '';
		foreach ( $arr as $text ) {
			$growinglink .= $text;
			$display .= $text;
			$title_ = Title::newFromText( $growinglink );
			if ( is_object( $title_ ) && $title_->isKnown() ) {
				$ret = $display;
				$display = '';
			} else {
				$display .= '/';
			}
			$growinglink .= '/';
		}
		return $ret;
	}

	/**
	 * @param int $db
	 * @return \Wikimedia\Rdbms\DBConnRef
	 */
	public static function getDB( $db ) {
		if ( !method_exists( MediaWikiServices::class, 'getConnectionProvider' ) ) {
			// @see https://gerrit.wikimedia.org/r/c/mediawiki/extensions/PageEncryption/+/1038754/comment/4ccfc553_58a41db8/
			return MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( $db );
		}
		$connectionProvider = MediaWikiServices::getInstance()->getConnectionProvider();
		switch ( $db ) {
			case DB_PRIMARY:
				return $connectionProvider->getPrimaryDatabase();
			case DB_REPLICA:
			default:
				return $connectionProvider->getReplicaDatabase();
		}
	}

}