Adamw has uploaded a new change for review.
https://gerrit.wikimedia.org/r/59366
Change subject: WIP: objects to manage allocations data
......................................................................
WIP: objects to manage allocations data
This will make it simple to merge groupings when allocations are the same.
Change-Id: I047074df32f61554d8d21e76727ee1b596710fdc
---
M api/ApiCentralNoticeAllocations.php
M api/ApiCentralNoticeLogs.php
M includes/BannerChooser.php
M includes/CampaignLog.php
M special/SpecialGlobalAllocation.php
5 files changed, 122 insertions(+), 60 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CentralNotice
refs/changes/66/59366/1
diff --git a/api/ApiCentralNoticeAllocations.php
b/api/ApiCentralNoticeAllocations.php
index e61fc86..b59a48b 100644
--- a/api/ApiCentralNoticeAllocations.php
+++ b/api/ApiCentralNoticeAllocations.php
@@ -51,9 +51,8 @@
$params['language'],
$params['anonymous'],
$params['device'],
- $params['bucket'],
- $params['minimal']
- );
+ $params['bucket']
+ )->getBanners();
$result->setIndexedTagName( $bannerList, 'BannerAllocation' );
$result->addValue( $this->getModuleName(), 'banners',
$bannerList );
@@ -68,7 +67,6 @@
$params['anonymous']=
ApiCentralNoticeAllocations::DEFAULT_ANONYMOUS;
$params['device'] =
ApiCentralNoticeAllocations::DEFAULT_DEVICE_NAME;
$params['bucket'] =
ApiCentralNoticeAllocations::DEFAULT_BUCKET;
- $params['minimal'] = false;
return $params;
}
@@ -84,7 +82,6 @@
$params['anonymous']= "The logged-in status to filter on
(true|false)";
$params['device'] = "Device name to filter on";
$params['bucket'] = "The bucket to filter on, by number (0 ..
$wgNoticeNumberOfBuckets, optional)";
- $params['minimal'] = "Alters return - only what is required
for the banner loader will be returned";
return $params;
}
@@ -110,17 +107,14 @@
* MediaWiki interface to this API call -- obtains banner allocation
information; ie how many
* buckets there are in a campaign, and what banners should be
displayed for a given filter.
*
- * Returns results as an array of banners
- * - banners
+ * @return BannerChooser object, which can be queried with getBanners()
to
+ * obtain a list of banner structs having:
*
- * The following information is provided in minimal mode:
* - name The name of the banner
* - allocation What the allocation proportion (0 to 1)
should be
* - campaign The name of the associated campaign
* - fundraising 1 if this is a fundraising banner
* - bucket The bucket this is assigned to in the
campaign
- *
- * In normal mode the following information is
additionally supplied:
* - weight The assigned weight in the campaign
* - display_anon 1 if should be displayed to
anonymous users
* - display_account 1 if should be displayed to logged
in users
@@ -134,26 +128,21 @@
* @param string $anonymous - Is user anonymous, eg 'true'
* @param string $device - What device to filter on, eg 'desktop' or
'mobile.device.ie'
* @param string $bucket - Which A/B bucket the user is in
- * @param bool $minimize - True if the results should be minimized
for banner usage
*
* @return array
*/
- public static function getBannerAllocation( $project, $country,
$language, $anonymous, $device, $bucket = null, $minimize = false ) {
- self::sanitizeParams( $project, $country, $language,
$anonymous, $device, $bucket, $minimize );
+ public static function getBannerAllocation( $project, $country,
$language, $anonymous, $device, $bucket = null ) {
+ self::sanitizeParams( $project, $country, $language,
$anonymous, $device, $bucket );
$chooser = new BannerChooser();
$chooser->filter( $project, $language, $country, $anonymous,
$device, $bucket );
$banners = $chooser->getBanners();
- if ( $minimize ) {
- $banners = static::minimizeBanners( $banners );
- }
-
return $banners;
}
// FIXME: this function is steeoopid
- protected static function sanitizeParams( &$project, &$country,
&$language, &$anonymous, &$device, &$bucket, &$minimize ) {
+ protected static function sanitizeParams( &$project, &$country,
&$language, &$anonymous, &$device, &$bucket ) {
$project = ApiCentralNoticeAllocations::sanitizeText(
$project,
self::PROJECT_FILTER,
@@ -190,8 +179,6 @@
self::BUCKET_FILTER,
self::DEFAULT_BUCKET
);
-
- $minimize = (boolean) $minimize;
}
/**
@@ -213,25 +200,5 @@
} else {
return $default;
}
- }
-
- /**
- * Reduces a set of banners to only what the banner controller needs
- */
- private static function minimizeBanners( $banners ) {
- $requiredKeys = array(
- 'allocation',
- 'campaign',
- 'fundraising',
- 'name',
- 'bucket',
- );
-
- $filtVal = array();
- foreach ( $banners as $banner ) {
- $filtVal[] = array_intersect_key( $banner, array_flip(
$requiredKeys ) );
- }
-
- return $filtVal;
}
}
diff --git a/api/ApiCentralNoticeLogs.php b/api/ApiCentralNoticeLogs.php
index cd913e4..a74fd63 100644
--- a/api/ApiCentralNoticeLogs.php
+++ b/api/ApiCentralNoticeLogs.php
@@ -4,7 +4,7 @@
class ApiCentralNoticeLogs extends ApiQueryBase {
- #XXX
+ #FIXME: from a shared include
const USER_FILTER = '/[a-zA-Z0-9_.]+/';
const CAMPAIGNS_FILTER = '/[a-zA-Z0-9_|\-]+/';
diff --git a/includes/BannerChooser.php b/includes/BannerChooser.php
index 22a0f7c..32c0281 100644
--- a/includes/BannerChooser.php
+++ b/includes/BannerChooser.php
@@ -183,4 +183,17 @@
function getBanners() {
return $this->banners;
}
+
+ function getBanners() {
+ return $this->banners;
+ }
+
+ function getAllocationHash() {
+ $allocSignatures = array();
+ foreach ( $this->banners as $banner ) {
+ //FIXME: no LCF search
+ $allocSignatures[] =
"{$banner['name']}:{$banner['allocation']}";
+ }
+ return sha1( implode( ";", $allocSignatures ) );
+ }
}
diff --git a/includes/CampaignLog.php b/includes/CampaignLog.php
index 8600513..de9b1b3 100644
--- a/includes/CampaignLog.php
+++ b/includes/CampaignLog.php
@@ -46,7 +46,7 @@
$removed = array();
$added = array();
- # XXX cannot use "this" in closures until php 5.4
+ # TODO: cannot use "this" in closures until php 5.4
$begin =& $this->begin;
$end =& $this->end;
diff --git a/special/SpecialGlobalAllocation.php
b/special/SpecialGlobalAllocation.php
index 9e701f5..115debc 100644
--- a/special/SpecialGlobalAllocation.php
+++ b/special/SpecialGlobalAllocation.php
@@ -353,21 +353,7 @@
}
if ( $result ) {
- sort( $contributing );
- if ( $excluding ) {
- sort( $excluding );
- $label = $this->msg(
'centralnotice-excluding-list',
-
$this->getLanguage()->commaList( $contributing ),
-
$this->getLanguage()->listToText( $excluding )
- );
- } else {
- $label =
$this->getLanguage()->commaList( $contributing );
- }
-
- $groupings[] = array(
- 'label' => $label,
- 'rows' => $result,
- );
+ $groupings[] = new AllocationGrouping(
$contributing, $excluding, $result );
}
}
}
@@ -377,7 +363,7 @@
/**
* Return every (unordered) combination of $num elements from $list
- * TODO: don't use recursion.
+ * TODO: don't use recursion, it limits num_campaigns << 100
*/
protected static function makeCombinations( array $list, $num ) {
if ( $num <= 0 or $num > count( $list ) ) {
@@ -417,6 +403,8 @@
* @return string HTML for the table
*/
protected function getBannerAllocationsTable( $project, $location,
$language, $numBuckets ) {
+ //XXX pass BannerChooser obj
+
// This is annoying. Within the campaign, banners usually vary
by user
// logged-in status, and bucket. Determine the allocations and
// collapse any dimensions which do not vary.
@@ -490,7 +478,7 @@
$this->msg( 'centralnotice-notice' )->text() );
$htmlOut .= Html::closeElement( 'tr' );
- foreach ( $variations as $isAnon => $bucketVariations ) {
+ foreach ( $grouping->getAllocations() as $isAnon =>
$bucketVariations ) {
foreach ( $bucketVariations as $bucket => $banners ) {
foreach ( $banners as $banner ) {
$htmlOut .=
$this->getBannerAllocationsVariantRow( $banner, $variesAnon, $variesBucket,
$isAnon, $bucket );
@@ -509,7 +497,7 @@
/**
* Print one line of banner allocations.
*/
- function getBannerAllocationsVariantRow( $banner, $variesAnon,
$variesBucket, $isAnon, $bucket ) {
+ function getBannerAllocationsVariantRow( array $banner, $variesAnon,
$variesBucket, $isAnon, $bucket ) {
$htmlOut = '';
$viewBanner = $this->getTitleFor( 'NoticeTemplate', 'view' );
@@ -582,6 +570,100 @@
return $htmlOut;
}
+
+ protected function getGroupingLabel( AllocationGrouping $grouping ) {
+ sort( $grouping->getContributing() );
+ if ( $grouping->getExcluding() ) {
+ sort( $grouping->getExcluding() );
+ return $this->msg( 'centralnotice-excluding-list',
+ $this->getLanguage()->commaList(
$grouping->getContributing() ),
+ $this->getLanguage()->listToText(
$grouping->getExcluding() )
+ );
+ } else {
+ return $this->getLanguage()->commaList(
$grouping->getContributing() );
+ }
+ }
+}
+
+/**
+ * A group of targets (project, country, language) for which the allocations
are the same.
+ */
+class AllocationGrouping {
+ protected $contributing;
+ protected $excluding;
+ protected $rows;
+
+ protected $numBuckets = 0;
+
+ /**
+ * @var multidimensional array with indexes (isAnon, bucket)
+ * -> BannerChooser as returned by
ApiCentralNoticeAllocations::getAllocationInformation()
+ */
+ protected $variations;
+
+ function __construct( $contributing, $excluding, $rows ) {
+ sort( $contributing );
+ sort( $excluding );
+ $this->contributing = $contributing;
+ $this->excluding = $excluding;
+ $this->rows = $rows;
+
+ foreach ( $this->contributing as $campaign ) {
+ $this->numBuckets = max( $this->numBuckets,
$campaign['buckets'] );
+ }
+
+ $this->variations = $this->calculateAllocations();
+ }
+
+ static function mergeGroupings() {
+ }
+
+ function isVaryBucket() {
+ // Even if allocations don't vary, this is enough reason to
show the full matrix:
+ //FIXME: merging should preserve
+ return ( $this->numBuckets > 1 );
+ }
+
+ function isVaryAuthenticated() {
+ foreach ( range( 0, $numBuckets - 1 ) as $bucket ) {
+ if ( $this->variations[0][$bucket]->getAllocationHash()
!= $this->variations[1][$bucket]->getAllocationHash() ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function getHash() {
+ $summary = array();
+ array_walk_recursive( $this->variations,
+ function ( $alloc ) use ( &$summary ) {
+ $summary[] = $alloc->getAllocationHash();
+ }
+ );
+ return sha1( implode( ";", $summary ) );
+ }
+
+ function getVariations() {
+ return $this->variations;
+ }
+
+ protected function calculateAllocations() {
+ // This is annoying. Within the campaign, banners usually vary
by user
+ // logged-in status, and bucket. Determine the allocations and
+ // collapse any dimensions which do not vary.
+ //
+ // TODO: the allocation hash should also be used to collapse
groupings which
+ // are identical because of e.g. z-index
+ foreach ( array( true, false ) as $isAnon ) {
+ for ( $bucket = 0; $bucket < $numBuckets; $bucket++ ) {
+ $variations[$isAnon][$bucket] =
ApiCentralNoticeAllocations::getAllocationInformation(
+ $project, $country, $language,
+ $isAnon ? 'true' : 'false',
+ $bucket
+ );
+ }
+ }
+ }
}
class CampaignCriteria {
--
To view, visit https://gerrit.wikimedia.org/r/59366
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I047074df32f61554d8d21e76727ee1b596710fdc
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CentralNotice
Gerrit-Branch: master
Gerrit-Owner: Adamw <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits