Jeroen De Dauw has submitted this change and it was merged.
Change subject: Improvements to the event system
......................................................................
Improvements to the event system
* One class for each responsibility
* Added a ton of tests
Change-Id: I02202d977185eb11702ce8b5948288fd04a9c3f7
---
M EducationProgram.hooks.php
M EducationProgram.php
M includes/Events/EditEventCreator.php
A includes/Events/Event.php
A includes/Events/EventQuery.php
A includes/Events/EventStore.php
M includes/Timeline.php
M includes/TimelineGroup.php
D includes/rows/Event.php
M includes/specials/SpecialMyCourses.php
M includes/tables/Events.php
M tests/phpunit/Events/EditEventCreatorTest.php
A tests/phpunit/Events/EventQueryTest.php
A tests/phpunit/Events/EventStoreTest.php
A tests/phpunit/Events/EventTest.php
15 files changed, 1,080 insertions(+), 150 deletions(-)
Approvals:
Jeroen De Dauw: Verified; Looks good to me, approved
diff --git a/EducationProgram.hooks.php b/EducationProgram.hooks.php
index 39c7d26..794544c 100644
--- a/EducationProgram.hooks.php
+++ b/EducationProgram.hooks.php
@@ -83,6 +83,9 @@
'Utils',
'Events/EditEventCreator',
+ 'Events/EventQuery',
+ 'Events/EventStore',
+ 'Events/Event',
'tables/Orgs',
);
@@ -441,18 +444,21 @@
$dbw = wfGetDB( DB_MASTER );
+ // TODO: properly inject dependencies
$userCourseFinder = new UPCUserCourseFinder( $dbw );
$eventCreator = new \EducationProgram\Events\EditEventCreator(
$dbw, $userCourseFinder );
$events = $eventCreator->getEventsForEdit( $article, $rev,
$user );
$startOwnStransaction = $dbw->trxLevel() === 0;
+ $eventStore = new \EducationProgram\Events\EventStore(
'ep_events' );
+
if ( $startOwnStransaction ) {
$dbw->begin();
}
foreach ( $events as $event ) {
- $event->save( __METHOD__ );
+ $eventStore->insertEvent( $event );
}
if ( $startOwnStransaction ) {
diff --git a/EducationProgram.php b/EducationProgram.php
index c1b3cbc..14ce9a0 100644
--- a/EducationProgram.php
+++ b/EducationProgram.php
@@ -85,6 +85,9 @@
$wgAutoloadClasses['EducationProgram\ApiRefreshEducation']
= $dir . '/includes/api/ApiRefreshEducation.php';
$wgAutoloadClasses['EducationProgram\Events\EditEventCreator']
= $dir . '/includes/Events/EditEventCreator.php';
+$wgAutoloadClasses['EducationProgram\Events\Event']
= $dir . '/includes/Events/Event.php';
+$wgAutoloadClasses['EducationProgram\Events\EventQuery']
= $dir . '/includes/Events/EventQuery.php';
+$wgAutoloadClasses['EducationProgram\Events\EventStore']
= $dir . '/includes/Events/EventStore.php';
// includes/pagers (implementing Pager)
$wgAutoloadClasses['EducationProgram\ArticleTable']
= $dir . '/includes/pagers/ArticleTable.php';
@@ -107,7 +110,6 @@
$wgAutoloadClasses['EducationProgram\Course']
= $dir . '/includes/rows/Course.php';
$wgAutoloadClasses['EducationProgram\EPArticle']
= $dir . '/includes/rows/EPArticle.php';
$wgAutoloadClasses['EducationProgram\EPRevision']
= $dir . '/includes/rows/EPRevision.php';
-$wgAutoloadClasses['EducationProgram\Event']
= $dir . '/includes/rows/Event.php';
$wgAutoloadClasses['EducationProgram\Instructor']
= $dir . '/includes/rows/Instructor.php';
$wgAutoloadClasses['EducationProgram\OA']
= $dir . '/includes/rows/OA.php';
$wgAutoloadClasses['EducationProgram\Org']
= $dir . '/includes/rows/Org.php';
diff --git a/includes/Events/EditEventCreator.php
b/includes/Events/EditEventCreator.php
index 4710616..0284884 100644
--- a/includes/Events/EditEventCreator.php
+++ b/includes/Events/EditEventCreator.php
@@ -2,7 +2,6 @@
namespace EducationProgram\Events;
-use EducationProgram\Event;
use EducationProgram\Courses;
use EducationProgram\Student;
use EducationProgram\UserCourseFinder;
@@ -11,13 +10,15 @@
use User;
use Page;
use DatabaseBase;
+use MWNamespace;
+use Diff;
+use _DiffOp;
/**
* Class that generates edit based events by handling new edits.
*
* TODO: properly inject dependencies
* - Profiler
- * - event factory
*
* 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
@@ -119,24 +120,64 @@
*
* @since 0.3
*
- * @param Revision $rev
+ * @param Revision $revision
* @param User $user
* @param int[] $courseIds
*
* @return Event[]
*/
- protected function createEditEvents( Revision $rev, User $user, array
$courseIds ) {
- if ( is_null( $rev->getTitle() ) ) {
+ protected function createEditEvents( Revision $revision, User $user,
array $courseIds ) {
+ if ( is_null( $revision->getTitle() ) ) {
return array();
}
- $event = Event::newFromRevision( $rev, $user );
$events = array();
+ $title = $revision->getTitle();
+
+ $info = array(
+ 'page' => $title->getFullText(),
+ 'comment' => $revision->getComment(),
+ 'minoredit' => $revision->isMinor(),
+ 'parent' => $revision->getParentId()
+ );
+
+ if ( MWNamespace::isTalk( $title->getNamespace() ) && !is_null(
$revision->getParentId() ) ) {
+ $diff = new Diff(
+ explode( "\n", Revision::newFromId(
$revision->getParentId() )->getText() ),
+ explode( "\n", $revision->getText() )
+ );
+
+ // Only an order of magnitude more lines then the
python equivalent, but oh well... >_>
+ // lines = [ diffOp->closing for diffOp in diff->edits
if diffOp->type == 'add' ]
+ $lines = array_map(
+ function( _DiffOp $diffOp ) {
+ return $diffOp->closing;
+ },
+ array_filter(
+ $diff->edits,
+ function( _DiffOp $diffOp ) {
+ return $diffOp->type == 'add';
+ }
+ )
+ );
+
+ if ( $lines !== array() ) {
+ $lines = call_user_func_array( 'array_merge',
$lines );
+ }
+
+ $info['addedlines'] = $lines;
+ }
+
foreach ( $courseIds as $courseId ) {
- $eventForCourse = clone $event;
- $eventForCourse->setField( 'course_id', $courseId );
- $events[] = $eventForCourse;
+ $events[] = new Event(
+ null,
+ $courseId,
+ $user->getId(),
+ $revision->getTimestamp(),
+ 'edit-' . $title->getNamespace(),
+ $info
+ );
}
return $events;
diff --git a/includes/Events/Event.php b/includes/Events/Event.php
new file mode 100644
index 0000000..40df0d6
--- /dev/null
+++ b/includes/Events/Event.php
@@ -0,0 +1,140 @@
+<?php
+
+namespace EducationProgram\Events;
+
+use User;
+
+/**
+ * Class representing a single Education Program event.
+ *
+ * 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
+ *
+ * @since 0.3
+ *
+ * @ingroup EducationProgram
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < [email protected] >
+ */
+class Event {
+
+ private $eventId;
+ private $courseId;
+ private $userId;
+ private $time;
+ private $type;
+ private $info;
+
+ /**
+ * Constructor.
+ *
+ * @since 0.3
+ *
+ * @param int|null $eventId
+ * @param int $courseId
+ * @param int $userId
+ * @param string $time TS_MW
+ * @param string $type
+ * @param array $info
+ */
+ public function __construct( $eventId, $courseId, $userId, $time,
$type, array $info ) {
+ $this->eventId = $eventId;
+ $this->courseId = $courseId;
+ $this->userId = $userId;
+ $this->time = $time;
+ $this->type = $type;
+ $this->info = $info;
+ }
+
+ /**
+ * Returns the id of the event.
+ *
+ * @since 0.3
+ *
+ * @return int|null
+ */
+ public function getId() {
+ return $this->eventId;
+ }
+
+ /**
+ * Returns the id of the course for which the event is relevant.
+ *
+ * @since 0.3
+ *
+ * @return int
+ */
+ public function getCourseId() {
+ return $this->courseId;
+ }
+
+ /**
+ * Returns the id of the User that made the event.
+ *
+ * @since 0.3
+ *
+ * @return int
+ */
+ public function getUserId() {
+ return $this->userId;
+ }
+
+ /**c
+ * Returns the time at which the event occurred.
+ * The time is a string formatted as TS_MW.
+ *
+ * @since 0.3
+ *
+ * @return string TS_MW
+ */
+ public function getTime() {
+ return $this->time;
+ }
+
+ /**
+ * Returns the string identifier for the events type.
+ *
+ * @since 0.3
+ *
+ * @return string
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * Returns the events type specific info.
+ *
+ * @since 0.3
+ *
+ * @return string
+ */
+ public function getInfo() {
+ return $this->info;
+ }
+
+ /**
+ * Returns the age of the event in seconds.
+ *
+ * @since 0.3
+ *
+ * @return integer
+ */
+ public function getAge() {
+ return time() - (int)wfTimestamp( TS_UNIX, $this->time );
+ }
+
+}
diff --git a/includes/Events/EventQuery.php b/includes/Events/EventQuery.php
new file mode 100644
index 0000000..dc72366
--- /dev/null
+++ b/includes/Events/EventQuery.php
@@ -0,0 +1,205 @@
+<?php
+
+namespace EducationProgram\Events;
+
+use InvalidArgumentException;
+
+/**
+ * Specifies the selection criteria and options for a EventStore query.
+ *
+ * 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
+ *
+ * @since 0.3
+ *
+ * @file
+ * @ingroup EducationProgram
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < [email protected] >
+ */
+class EventQuery {
+
+ const COMP_BIGGER = 0;
+ const COMP_SMALLER = 1;
+
+ const ORDER_NONE = 0;
+ const ORDER_TIME_ASC = 1;
+ const ORDER_TIME_DESC = 2;
+
+ /**
+ * @var int[]
+ */
+ private $courseIds = array();
+
+ /**
+ * @var string|null
+ */
+ private $timeLimit = null;
+
+ /**
+ * @var int|null
+ */
+ private $timeLimitComparator = null;
+
+ /**
+ * @var int|null
+ */
+ private $limit = null;
+
+ /**
+ * @var int|null
+ */
+ private $order = null;
+
+ /**
+ * Sets the ids of the courses to which the events should be relevant.
+ *
+ * @since 0.3
+ *
+ * @param int|int[] $courseIds
+ * @throws InvalidArgumentException
+ */
+ public function setCourses( $courseIds ) {
+ $courseIds = (array)$courseIds;
+
+ foreach ( $courseIds as $courseId ) {
+ if ( !is_int( $courseId ) ) {
+ throw new InvalidArgumentException( 'Course ids
need to be integers' );
+ }
+ }
+
+ $this->courseIds = $courseIds;
+ }
+
+ /**
+ * Sets a time limit all events should be older or newer then,
+ * depending on the provided comparator.
+ *
+ * @since 0.3
+ *
+ * @param string $time TS_MW
+ * @param int $comparator
+ *
+ * @throws InvalidArgumentException
+ */
+ public function setTimeLimit( $time, $comparator ) {
+ if ( !is_string( $time ) ) {
+ throw new InvalidArgumentException( '$time needs to be
a TS_MW string' );
+ }
+
+ if ( !is_int( $comparator ) ) {
+ throw new InvalidArgumentException( '$comparator needs
to be an integer' );
+ }
+
+ $this->timeLimit = $time;
+ $this->timeLimitComparator = $comparator;
+ }
+
+ /**
+ * Sets the query limit.
+ *
+ * @since 0.3
+ *
+ * @param int $limit
+ *
+ * @throws InvalidArgumentException
+ */
+ public function setRowLimit( $limit ) {
+ if ( !is_int( $limit ) ) {
+ throw new InvalidArgumentException( '$limit needs to be
an integer' );
+ }
+
+ if ( $limit <= 0 ) {
+ throw new InvalidArgumentException( '$limit needs to be
bigger than 0' );
+ }
+
+ $this->limit = $limit ;
+ }
+
+ /**
+ * Sets the query sort order.
+ *
+ * @since 0.3
+ *
+ * @param int $order
+ *
+ * @throws InvalidArgumentException
+ */
+ public function setSortOrder( $order ) {
+ if ( !is_int( $order ) ) {
+ throw new InvalidArgumentException( '$order needs to be
an integer' );
+ }
+
+ $this->order = $order;
+ }
+
+ /**
+ * Gets the ids of the courses to which the events should be relevant.
+ *
+ * @since 0.3
+ *
+ * @return int[]
+ */
+ public function getCourseIds() {
+ return $this->courseIds;
+ }
+
+ /**
+ * Returns the time limit.
+ * Returned as string in TS_MW format or null if there is no such limit.
+ *
+ * @since 0.3
+ *
+ * @return string|null
+ */
+ public function getTimeLimit() {
+ return $this->timeLimit;
+ }
+
+ /**
+ * Returns the time limit comparator.
+ *
+ * @since 0.3
+ *
+ * @return int|null
+ */
+ public function getTimeLimitComparator() {
+ return $this->timeLimitComparator;
+ }
+
+ /**
+ * Returns the query row limit.
+ *
+ * @since 0.3
+ *
+ * @return int|null
+ */
+ public function getRowLimit() {
+ return $this->limit;
+ }
+
+ /**
+ * Returns the query sort order.
+ *
+ * @since 0.3
+ *
+ * @return int|null
+ */
+ public function getSortOrder() {
+ return $this->order;
+ }
+
+}
diff --git a/includes/Events/EventStore.php b/includes/Events/EventStore.php
new file mode 100644
index 0000000..0dbee5f
--- /dev/null
+++ b/includes/Events/EventStore.php
@@ -0,0 +1,182 @@
+<?php
+
+namespace EducationProgram\Events;
+
+use DatabaseBase;
+use InvalidArgumentException;
+
+/**
+ * Service via which EducationProgram events can be saved and queried.
+ *
+ * Side note:
+ * This MySQL implementation of the interface pulls in some global
+ * DatabaseBase object. Injecting a connection provider would be better,
+ * though sadly enough we do not have such an interface yet.
+ *
+ * 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
+ *
+ * @since 0.3
+ *
+ * @file
+ * @ingroup EducationProgram
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < [email protected] >
+ */
+class EventStore {
+
+ /**
+ * @since 0.3
+ *
+ * @var string
+ */
+ private $tableName;
+
+ /**
+ * @since 0.3
+ *
+ * @var int
+ */
+ private $readConnectionId;
+
+ /**
+ * Constructor.
+ *
+ * @since 0.3
+ *
+ * @param string $tableName
+ * @param int $readConnectionId
+ */
+ public function __construct( $tableName, $readConnectionId = DB_SLAVE )
{
+ $this->tableName = $tableName;
+ $this->readConnectionId = $readConnectionId;
+ }
+
+ /**
+ * @since 0.3
+ *
+ * @return DatabaseBase
+ */
+ private function getReadConnection() {
+ return wfGetDB( $this->readConnectionId );
+ }
+
+ /**
+ * @since 0.3
+ *
+ * @return DatabaseBase
+ */
+ private function getWriteConnection() {
+ return wfGetDB( DB_MASTER );
+ }
+
+ /**
+ * Runs the provided event query and returns the matching events.
+ *
+ * @since 0.3
+ *
+ * @param EventQuery $query
+ *
+ * @return Event[]
+ */
+ public function query( EventQuery $query ) {
+ $db = $this->getReadConnection();
+
+ $conditions = array();
+
+ if ( $query->getCourseIds() !== null ) {
+ $conditions['event_course_id'] = $query->getCourseIds();
+ }
+
+ if ( $query->getTimeLimit() !== null ) {
+ $comparator = $query->getTimeLimitComparator() ===
EventQuery::COMP_BIGGER ? '>' : '<';
+ $conditions[] = 'event_time ' . $comparator . ' ' .
$db->addQuotes( $query->getTimeLimit() );
+ }
+
+ $options = array();
+
+ if ( $query->getRowLimit() !== null ) {
+ $options['LIMIT'] = $query->getRowLimit();
+
+ $order = $query->getSortOrder() ===
EventQuery::ORDER_TIME_ASC ? ' ASC' : ' DESC';
+
+ $options['ORDER BY'] = 'event_time' . $order;
+ }
+
+ $queryResult = $db->select( $this->tableName, '*', $conditions,
__METHOD__, $options );
+
+ $events = array();
+
+ foreach ( $queryResult as $resultRow ) {
+ $events[] = $this->eventFromDbResult( $resultRow );
+ }
+
+ return $events;
+ }
+
+ /**
+ * Constructs and returns an Event object given a result row from the
events table.
+ *
+ * @since 0.3
+ *
+ * @param object $resultRow
+ *
+ * @return Event
+ */
+ private function eventFromDbResult( $resultRow ) {
+ return new Event(
+ (int)$resultRow->event_id,
+ (int)$resultRow->event_course_id,
+ (int)$resultRow->event_user_id,
+ $resultRow->event_time,
+ $resultRow->event_type,
+ unserialize( $resultRow->event_info )
+ );
+ }
+
+ /**
+ * Inserts a new event into the event store.
+ *
+ * @since 0.3
+ *
+ * @param Event $event
+ *
+ * @return boolean SuccessIndicator
+ * @throws InvalidArgumentException
+ */
+ public function insertEvent( Event $event ) {
+ if ( $event->getId() !== null ) {
+ throw new InvalidArgumentException( 'Can not insert
events that already have an ID' );
+ }
+
+ $db = $this->getWriteConnection();
+
+ $fields = array(
+ 'event_course_id' => $event->getCourseId(),
+ 'event_user_id' => $event->getUserId(),
+ 'event_time' => $event->getTime(),
+ 'event_type' => $event->getType(),
+ 'event_info' => serialize( $event->getInfo() )
+ );
+
+ return $db->insert(
+ $this->tableName,
+ $fields,
+ __METHOD__
+ ) !== false;
+ }
+
+}
diff --git a/includes/Timeline.php b/includes/Timeline.php
index 30c8150..099d545 100644
--- a/includes/Timeline.php
+++ b/includes/Timeline.php
@@ -1,7 +1,9 @@
<?php
namespace EducationProgram;
+
use IContextSource;
+use EducationProgram\Events\Event;
/**
* Education Program timeline.
@@ -65,7 +67,7 @@
$groups = array();
foreach ( $this->events as $event ) {
- $eventInfo = $event->getField( 'info' );
+ $eventInfo = $event->getInfo();
if ( array_key_exists( 'page', $eventInfo ) ) {
$groupId = $eventInfo['page'] . '|';
@@ -74,20 +76,20 @@
if ( array_key_exists( $groupId, $groups ) ) {
$groups[$groupId]['events'][] = $event;
- if ( $event->getField( 'time' ) >
$groups[$groupId]['time'] ) {
- $groups[$groupId]['time'] =
$event->getField( 'time' );
+ if ( $event->getTime() >
$groups[$groupId]['time'] ) {
+ $groups[$groupId]['time'] =
$event->getTime();
}
}
else {
$groups[$groupId] = array(
- 'time' => $event->getField(
'time' ),
+ 'time' => $event->getTime(),
'events' => array( $event ),
);
}
}
else {
$groups[] = array(
- 'time' => $event->getField( 'time' ),
+ 'time' => $event->getTime(),
'events' => array( $event ),
);
}
diff --git a/includes/TimelineGroup.php b/includes/TimelineGroup.php
index c314167..d9443c8 100644
--- a/includes/TimelineGroup.php
+++ b/includes/TimelineGroup.php
@@ -1,7 +1,15 @@
<?php
namespace EducationProgram;
-use IContextSource, MWException, Html, Linker, Message, User, Title;
+
+use IContextSource;
+use MWException;
+use Html;
+use Linker;
+use Message;
+use User;
+use Title;
+use EducationProgram\Events\Event;
/**
* Class for displaying a group of Education Program events in a timeline.
@@ -48,9 +56,9 @@
*/
foreach ( $events as $event ) {
if ( is_null( $type ) ) {
- $type = $event->getField( 'type' );
+ $type = $event->getType();
}
- elseif ( $type !== $event->getField( 'type' ) ) {
+ elseif ( $type !== $event->getType() ) {
throw new MWException( 'Got events of different
types when trying to build a ' . __CLASS__ );
}
}
@@ -242,9 +250,9 @@
protected function getSegmentHTML( Event $event ) {
return $this->msg(
'ep-timeline-unknown',
- $event->getUser()->getName(),
- $this->getLanguage()->time( $event->getField( 'time' )
),
- $this->getLanguage()->date( $event->getField( 'time' ) )
+ User::newFromId( $event->getUserId() ),
+ $this->getLanguage()->time( $event->getTime() ),
+ $this->getLanguage()->date( $event->getTime() )
)->escaped();
}
@@ -275,8 +283,8 @@
protected function getSegmentHTML( Event $event ) {
$html = '';
- $user = $event->getUser();
- $info = $event->getField( 'info' );
+ $user = User::newFromId( $event->getUserId() );
+ $info = $event->getInfo();
$html .= Linker::userLink( $user->getId(), $user->getName() );
@@ -323,7 +331,7 @@
* @var Event $event
*/
foreach ( $this->events as $event ) {
- $userIds[] = $event->getField( 'user_id' );
+ $userIds[] = $event->getUserId();
}
$userIds = array_unique( $userIds );
@@ -345,8 +353,8 @@
)->escaped();
}
- $info = $this->events[0]->getField( 'info' );
- $type = explode( '-', $this->events[0]->getField( 'type' ) );
+ $info = $this->events[0]->getInfo();
+ $type = explode( '-', $this->events[0]->getType() );
$type = (int)array_pop( $type );
$keys = array(
diff --git a/includes/rows/Event.php b/includes/rows/Event.php
deleted file mode 100644
index 817a168..0000000
--- a/includes/rows/Event.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-
-namespace EducationProgram;
-use User, Revision, MWNamespace, Diff, _DiffOp;
-
-/**
- * Class representing a single Education Program event.
- *
- * @since 0.1
- *
- * @ingroup EducationProgram
- *
- * @licence GNU GPL v2+
- * @author Jeroen De Dauw < [email protected] >
- */
-class Event extends \ORMRow {
-
- /**
- * Field for caching the linked user.
- *
- * @since 0.1
- * @var User|bool false
- */
- protected $user = false;
-
- /**
- * Create a new edit event from a revision.
- *
- * @since 0.1
- *
- * @param Revision $revision
- * @param User $user
- *
- * @return Event
- */
- public static function newFromRevision( Revision $revision, User $user
) {
- $title = $revision->getTitle();
-
- $info = array(
- 'page' => $title->getFullText(),
- 'comment' => $revision->getComment(),
- 'minoredit' => $revision->isMinor(),
- 'parent' => $revision->getParentId()
- );
-
- if ( MWNamespace::isTalk( $title->getNamespace() ) && !is_null(
$revision->getParentId() ) ) {
- $diff = new Diff(
- explode( "\n", Revision::newFromId(
$revision->getParentId() )->getText() ),
- explode( "\n", $revision->getText() )
- );
-
- // Only an order of magnitude more lines then the
python equivalent, but oh well... >_>
- // lines = [ diffOp->closing for diffOp in diff->edits
if diffOp->type == 'add' ]
- $lines = array_map(
- function( _DiffOp $diffOp ) {
- return $diffOp->closing;
- },
- array_filter(
- $diff->edits,
- function( _DiffOp $diffOp ) {
- return $diffOp->type == 'add';
- }
- )
- );
-
- if ( $lines !== array() ) {
- $lines = call_user_func_array( 'array_merge',
$lines );
- }
-
- $info['addedlines'] = $lines;
- }
-
- $fields = array(
- 'user_id' => $user->getId(),
- 'time' => $revision->getTimestamp(),
- 'type' => 'edit-' . $title->getNamespace(),
- 'info' => $info,
- );
-
- return Events::singleton()->newRow( $fields );
- }
-
- /**
- * Returns the user that made the event.
- *
- * @since 0.1
- *
- * @return User
- */
- public function getUser() {
- if ( $this->user === false ) {
- $this->user = User::newFromId( $this->getField(
'user_id' ) );
- }
-
- return $this->user;
- }
-
- /**
- * Returns the age of the event in seconds.
- *
- * @since 0.1
- *
- * @return integer
- */
- public function getAge() {
- return time() - (int)wfTimestamp( TS_UNIX, $this->getField(
'time' ) );
- }
-
-}
diff --git a/includes/specials/SpecialMyCourses.php
b/includes/specials/SpecialMyCourses.php
index df52565..8a4e302 100644
--- a/includes/specials/SpecialMyCourses.php
+++ b/includes/specials/SpecialMyCourses.php
@@ -1,7 +1,11 @@
<?php
namespace EducationProgram;
-use IContextSource, Linker;
+
+use IContextSource;
+use Linker;
+use EducationProgram\Events\EventQuery;
+use EducationProgram\Events\EventStore;
/**
* Page listing the recent actibvity of the users classmates.
@@ -177,17 +181,22 @@
protected function displayTimeline( Course $course ) {
$this->addCachedHTML(
function( Course $course, IContextSource $context ) {
- $eventTable = Events::singleton();
+ // TODO: inject dependency
+ $eventStore = new
\EducationProgram\Events\EventStore( 'ep_events' );
- $conds = array(
- 'course_id' => $course->getId(),
- 'time > ' . wfGetDB( DB_SLAVE
)->addQuotes( wfTimestamp( TS_MW, time() - Settings::get(
'timelineDurationLimit' ) ) ),
- );
+ $query = new EventQuery();
- $options = array(
- 'LIMIT' => Settings::get(
'timelineCountLimit' ),
- 'ORDER BY' =>
$eventTable->getPrefixedField( 'time' ) . ' DESC'
- );
+ $query->setCourses( $course->getId() );
+
+ // TODO: inject settings
+ $timeLimit = wfTimestamp( TS_MW, time() -
Settings::get( 'timelineDurationLimit' ) );
+ $query->setTimeLimit( $timeLimit,
EventQuery::COMP_BIGGER );
+
+ $query->setRowLimit( Settings::get(
'timelineCountLimit' ) );
+
+ $query->setSortOrder(
EventQuery::ORDER_TIME_DESC );
+
+ $events = $eventStore->query( $query );
$html = Linker::link(
$course->getTitle(),
@@ -197,8 +206,6 @@
$course->getField( 'name' )
)
);
-
- $events = iterator_to_array(
$eventTable->select( null, $conds, $options ) );
if ( $events === array() ) {
$html .= $context->msg(
'ep-dashboard-timeline-empty' )->escaped();
diff --git a/includes/tables/Events.php b/includes/tables/Events.php
index 77f3e9d..6753399 100644
--- a/includes/tables/Events.php
+++ b/includes/tables/Events.php
@@ -38,7 +38,7 @@
* @return string
*/
public function getRowClass() {
- return 'EducationProgram\Event';
+ return 'ORMRow';
}
/**
diff --git a/tests/phpunit/Events/EditEventCreatorTest.php
b/tests/phpunit/Events/EditEventCreatorTest.php
index ea874eb..9ed909d 100644
--- a/tests/phpunit/Events/EditEventCreatorTest.php
+++ b/tests/phpunit/Events/EditEventCreatorTest.php
@@ -72,7 +72,7 @@
$events = $eventCreator->getEventsForEdit( $article, $rev,
$user );
$this->assertInternalType( 'array', $events );
- $this->assertContainsOnlyInstancesOf( 'EducationProgram\Event',
$events );
+ $this->assertContainsOnlyInstancesOf(
'EducationProgram\Events\Event', $events );
}
}
diff --git a/tests/phpunit/Events/EventQueryTest.php
b/tests/phpunit/Events/EventQueryTest.php
new file mode 100644
index 0000000..a0cfbb2
--- /dev/null
+++ b/tests/phpunit/Events/EventQueryTest.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace EducationProgram\Tests\Events;
+
+use EducationProgram\Events\EventQuery;
+
+/**
+ * Unit tests for the EducationProgram\Events\EventQuery class.
+ *
+ * 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
+ *
+ * @since 0.3
+ *
+ * @file
+ * @ingroup EducationProgramTest
+ *
+ * @group EducationProgram
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < [email protected] >
+ */
+class EventQueryTest extends \PHPUnit_Framework_TestCase {
+
+ public function setCoursesProvider() {
+ $argLists = array();
+
+ $argLists[] = array( 1 );
+ $argLists[] = array( 42 );
+ $argLists[] = array( array( 1 ) );
+ $argLists[] = array( array( 42 ) );
+ $argLists[] = array( array( 1, 2, 3, 9001 ) );
+
+ return $argLists;
+ }
+
+ /**
+ * @dataProvider setCoursesProvider
+ *
+ * @param $courseIds
+ */
+ public function testSetCourses( $courseIds ) {
+ $query = new EventQuery();
+ $query->setCourses( $courseIds );
+ $this->assertEquals( (array)$courseIds, $query->getCourseIds()
);
+ }
+
+ public function timeLimitProvider() {
+ $argLists = array();
+
+ $argLists[] = array( '20010115123456', EventQuery::COMP_BIGGER
);
+ $argLists[] = array( '20010115123456', EventQuery::COMP_SMALLER
);
+
+ return $argLists;
+ }
+
+ /**
+ * @dataProvider timeLimitProvider
+ *
+ * @param $timeLimit
+ * @param $comparator
+ */
+ public function testSetTimeLimit( $timeLimit, $comparator ) {
+ $query = new EventQuery();
+ $query->setTimeLimit( $timeLimit, $comparator );
+
+ $this->assertEquals( $timeLimit, $query->getTimeLimit() );
+ $this->assertEquals( $comparator,
$query->getTimeLimitComparator() );
+ }
+
+ public function rowLimitProvider() {
+ $argLists = array();
+
+ $argLists[] = array( 1 );
+ $argLists[] = array( 42 );
+ $argLists[] = array( 9001 );
+ $argLists[] = array( 7201010 );
+
+ return $argLists;
+ }
+
+ /**
+ * @dataProvider rowLimitProvider
+ *
+ * @param $courseIds
+ */
+ public function testSetRowLimit( $limit ) {
+ $query = new EventQuery();
+ $query->setRowLimit( $limit );
+ $this->assertEquals( $limit, $query->getRowLimit() );
+ }
+
+ public function sortOrderProvider() {
+ $argLists = array();
+
+ $argLists[] = array( EventQuery::ORDER_NONE );
+ $argLists[] = array( EventQuery::ORDER_TIME_ASC );
+ $argLists[] = array( EventQuery::ORDER_TIME_DESC );
+
+ return $argLists;
+ }
+
+ /**
+ * @dataProvider sortOrderProvider
+ *
+ * @param $order
+ */
+ public function testSetSortOrder( $order ) {
+ $query = new EventQuery();
+ $query->setSortOrder( $order );
+ $this->assertEquals( $order, $query->getSortOrder() );
+ }
+
+}
diff --git a/tests/phpunit/Events/EventStoreTest.php
b/tests/phpunit/Events/EventStoreTest.php
new file mode 100644
index 0000000..248b585
--- /dev/null
+++ b/tests/phpunit/Events/EventStoreTest.php
@@ -0,0 +1,207 @@
+<?php
+
+namespace EducationProgram\Tests\Events;
+
+use EducationProgram\Events\EventStore;
+use EducationProgram\Events\EventQuery;
+use EducationProgram\Events\Event;
+
+/**
+ * Unit tests for the EducationProgram\Events\EventStore class.
+ *
+ * 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
+ *
+ * @since 0.3
+ *
+ * @file
+ * @ingroup EducationProgramTest
+ *
+ * @group EducationProgram
+ * @group Database
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < [email protected] >
+ */
+class EventStoreTest extends \MediaWikiTestCase {
+
+ public function getStore() {
+ return new EventStore( 'ep_events' );
+ }
+
+ public function setUp() {
+ parent::setUp();
+
+ wfGetDB( DB_MASTER )->delete( 'ep_events', '*' );
+
+ $events = array();
+
+ $events[] = new Event(
+ null,
+ 900001,
+ 1,
+ '20010115123456',
+ 'foobar',
+ array( 'baz' )
+ );
+
+ $events[] = new Event(
+ null,
+ 900002,
+ 1,
+ '20010115123457',
+ 'foobar',
+ array( 'bah' )
+ );
+
+ $events[] = new Event(
+ null,
+ 900001,
+ 1,
+ '20110115123457',
+ 'foobar',
+ array( 'spam' )
+ );
+
+ $events[] = new Event(
+ null,
+ 900001,
+ 2,
+ '20110115123457',
+ 'foobar',
+ array( 'hax' )
+ );
+
+ $events[] = new Event(
+ null,
+ 900001,
+ 1,
+ '20110115123457',
+ 'nyan',
+ array( '~=[,,_,,]:3', 42, array( 'o_O' ) )
+ );
+
+ foreach ( $events as $event ) {
+ $this->getStore()->insertEvent( $event );
+ }
+ }
+
+ public function queryProvider() {
+ $argLists = array();
+
+ $query = new EventQuery();
+ $query->setCourses( 900001 );
+
+ $argLists[] = array( $query, 4 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( 900002 );
+
+ $argLists[] = array( $query, 1 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( 900003 );
+
+ $argLists[] = array( $query, 0 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( array( 900001, 900002, 900003 ) );
+
+ $argLists[] = array( $query, 5 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( 900001 );
+ $query->setRowLimit( 2 );
+
+ $argLists[] = array( $query, 2 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( 900001 );
+ $query->setRowLimit( 2 );
+ $query->setSortOrder( EventQuery::ORDER_TIME_ASC );
+
+ $argLists[] = array( $query, 2 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( 900001 );
+ $query->setTimeLimit( '20050115123457', EventQuery::COMP_BIGGER
);
+
+ $argLists[] = array( $query, 3 );
+
+
+ $query = new EventQuery();
+ $query->setCourses( 900001 );
+ $query->setTimeLimit( '20050115123457',
EventQuery::COMP_SMALLER );
+
+ $argLists[] = array( $query, 1 );
+
+ return $argLists;
+ }
+
+ /**
+ * @dataProvider queryProvider
+ *
+ * @param EventQuery $query
+ * @param int $expectedCount
+ */
+ public function testQuery( EventQuery $query, $expectedCount ) {
+ $events = $this->getStore()->query( $query );
+
+ $this->assertInternalType( 'array', $events );
+ $this->assertContainsOnlyInstancesOf(
'EducationProgram\Events\Event', $events );
+
+ $this->assertCount( $expectedCount, $events );
+ }
+
+ public function eventProvider() {
+ $events = array();
+
+ $events[] = new Event(
+ null,
+ 900011,
+ 4242,
+ '20110115123457',
+ 'foobar',
+ array( 'hax' )
+ );
+
+ $events[] = new Event(
+ null,
+ 900012,
+ 31337,
+ '20110115123457',
+ 'nyan',
+ array( '~=[,,_,,]:3', 42, array( 'o_O' ) )
+ );
+
+ return $this->arrayWrap( $events );
+ }
+
+ /**
+ * @dataProvider eventProvider
+ *
+ * @param Event $event
+ */
+ public function testInsertEvent( Event $event ) {
+ $this->assertTrue( $this->getStore()->insertEvent( $event ),
'insertEvent returned true' );
+ }
+
+}
diff --git a/tests/phpunit/Events/EventTest.php
b/tests/phpunit/Events/EventTest.php
new file mode 100644
index 0000000..5e786c6
--- /dev/null
+++ b/tests/phpunit/Events/EventTest.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace EducationProgram\Tests\Events;
+
+use EducationProgram\Events\Event;
+
+/**
+ * Unit tests for the EducationProgram\Events\Event class.
+ *
+ * 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
+ *
+ * @since 0.3
+ *
+ * @file
+ * @ingroup EducationProgramTest
+ *
+ * @group EducationProgram
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < [email protected] >
+ */
+class EventTest extends \PHPUnit_Framework_TestCase {
+
+ public function constructorProvider() {
+ $argLists = array();
+
+ $argLists[] = array( 1, 2, 3, '20010115123456', 'type-foobar',
array() );
+ $argLists[] = array( 42, 9001, 7201010, '20010115123456',
'baz', array( 'o' => 'noez' ) );
+ $argLists[] = array( null, 1, 1, '20010115123456', 'spam',
array( 'o' => 'noez', 42 ) );
+
+ return $argLists;
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetId( $id, $courseId, $userId, $time, $type, $info
) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals( $id, $event->getId() );
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetCourseId( $id, $courseId, $userId, $time, $type,
$info ) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals( $courseId, $event->getCourseId() );
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetUserId( $id, $courseId, $userId, $time, $type,
$info ) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals( $userId, $event->getUserId() );
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetTime( $id, $courseId, $userId, $time, $type,
$info ) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals( $time, $event->getTime() );
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetType( $id, $courseId, $userId, $time, $type,
$info ) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals( $type, $event->getType() );
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetInfo( $id, $courseId, $userId, $time, $type,
$info ) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals( $info, $event->getInfo() );
+ }
+
+ /**
+ * @dataProvider constructorProvider
+ */
+ public function testGetAge( $id, $courseId, $userId, $time, $type,
$info ) {
+ $event = new Event( $id, $courseId, $userId, $time, $type,
$info );
+
+ $this->assertEquals(
+ time() - (int)wfTimestamp( TS_UNIX, $time ),
+ $event->getAge()
+ );
+ }
+
+}
--
To view, visit https://gerrit.wikimedia.org/r/53349
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I02202d977185eb11702ce8b5948288fd04a9c3f7
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/extensions/EducationProgram
Gerrit-Branch: master
Gerrit-Owner: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: Ragesoss <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits