diff --git a/README.txt b/README.txt
index 3ed2ae992cd21986a008cdf50e536782cf6d5869..723f2d0e8fd7bf38d09238c4ab0709216065336c 100644
--- a/README.txt
+++ b/README.txt
@@ -47,32 +47,6 @@ to provides localized version of a same item.
Support of Tooltip for item rollovers. Use wowhead provider by default. You can
also provide your own representation of an item.
-Important note about Items: Due to a bug in D7 (http://drupal.org/node/1284332)
-if you install the wow_item module, you will not be able to uninstall it.
-A field is used to handle serveral locales for the item entity, and the module
-declaring the field use it in the same time. This will be fixed in a future
-patch and already fixed in D8 (http://drupal.org/node/943772).
-
Realms:
Provides realm status information as Drupal Entity.
Provides an ajax auto-completion callback for Realm selection textfield.
-
-Work in progress
-Support of the PVP Resources: this will be a new module included in the default
-package. The base component and service communication will be fully implemented,
-however additional features will be covered in more specific modules.
-
-Support of the Auction Resources: same as above.
-Realm: Provides a new form widget, realm selector with ajax auto-completion.
-Provides a batch processing queue system instead of the drupal cron. Each time
-you need to update a guild, character, it gets queued and executed on demand, or
-automatically.
-
-Possible design improvement
-In a future version it will completely separate framework and product. For
-instance the guild module allows to enable 'guild' entity with its own database
-table. This entity is nice for website working with guild only such as
-wowprogress.com. However, the guild module also set a default guild used to
-define if a user belong to a guild or not. Separate thoses functionalities will
-allows community developers to use the default guild functionality and guild
-progress website not to use it for instance.
diff --git a/UPGRADE.txt b/UPGRADE.txt
index c03fca3dcc6f44fd1dac6ff2e65fb5c2a00c6acd..c20e5521af9e6b20532070837fd918c06c718ef0 100755
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -1,19 +1,33 @@
+
2.x upgrade instructions to 3.x:
+
+The 3.x release focus on more unit-testable API and a better quality class
+design for developers.
+
+- First ensure you are running the last available version of the 2.x branch
+and updates has been applied.
+
+- Dependencies: No new dependencies has been added for this release.
+
+- Put your site in maintenance mode and visit the update.php script. Apply the
+ updates and check nothing has failed.
+
+
1.x upgrade instructions to 2.x:
Upgrading is strongly advised, among many bug fixes there is a new architecture
granting both scalability and stability. More than 500 unit, functional and
-integration tests has been written for this release.
+integration tests has been written for the 2.x release.
- First ensure you are running the last available version of the 1.x branch
and updates has been applied.
- Dependencies: Download and install the entity module.
-- Important: Disable the WoW Guild Rank module before any atempt to upgrade to
-2.x. Do not uninstall it, just disable it.
+- Important: Disable the WoW Guild Rank module before any attempt to upgrade to
+2.x. Do not un-install it, just disable it.
- Put your site in maintenance mode and visit the update.php script. Apply the
updates and check nothing has failed.
- (Optional) If you previously disabled the WoW Guild Rank module, you can
-re-enable it.
\ No newline at end of file
+re-enable it.
diff --git a/lib/WoW/Core/Callback.php b/lib/WoW/Core/Callback.php
new file mode 100755
index 0000000000000000000000000000000000000000..1d38b9fb821657fe4027387692c13bb9c872d48a
--- /dev/null
+++ b/lib/WoW/Core/Callback.php
@@ -0,0 +1,19 @@
+entityType = $entity_type;
- $this->entityInfo = $entity_info;
- $this->idKey = $entity_info['entity keys']['id'];
- $this->storage = entity_get_controller($entity_type);
+ public function __construct($entityType, array $entityInfo, EntityAPIControllerInterface $storage) {
+ $this->entityType = $entityType;
+ $this->entityInfo = $entityInfo;
+ $this->idKey = $entityInfo['entity keys']['id'];
+ $this->remoteKey = $entityInfo['entity keys']['remote'];
+ $this->moduleKey = reset(explode('/', $entityInfo['remote path']));
+ $this->storage = $storage;
}
/**
- * Fetch remote data resources from the service.
+ * Fetches remote data resources from the service.
+ *
+ *
*
* @param string $region
* The region to fetch the data from.
* @param string $language
- * The Drupal language to retrieve the data with.
+ * The language to retrieve the data with.
+ * @param bool $force
+ * Whether to force the refresh or not.
*
- * @return WoWResponse
- * An response object in case of HTTP status 200.
+ * @return array
+ * An array of remote entities.
*
* @throws WoWException
- * An HTTP Exception in case of HTTP status 500 or 404.
+ * An HTTP Exception in case of HTTP status 500.
*/
- public function fetchAll($region, $language, $force = FALSE) {
+ public function fetch($region, $language, $force = FALSE) {
$service = wow_data_service($region);
- $db_entities = $entities = $this->storage->load(FALSE);
+ // Loads all entities for create/save/delete operations.
+ $entities = $this->storage->load(FALSE);
- // Do not call the service if the expiration date has not be reached or
- // force is not TRUE.
- if ($service->expires($language, 'wow_character', 'class') > REQUEST_TIME || $force) {
- $response = $service->newRequest('data/character/classes')
+ // Do not call the service if the expiration date has not be reached.
+ if ($service->expires($language, $this->moduleKey, $this->remoteKey) > REQUEST_TIME || $force) {
+ // Performs a request to the service API by setting a language code. Each
+ // data resources are saved with the language key in mind.
+ return $service->newRequest($this->entityInfo['remote path'])
->setLocale($language)
+ ->onResponse(200, array($this, 'onResult'), array($entities))
+ // @TODO:
+ ->onResponseDefault()
->execute();
-
- // Builds the array of entities to return.
- $entities = array();
- foreach ($response->getData('classes') as $values) {
- $entities[$values[$this->idKey]] = $this->storage->create($values + array(
- 'language' => $language,
- // TODO: put this in the storage controller.
- 'is_new' => empty($db_entities[$values[$this->idKey]])
- ));
- }
-
- // Deletes entities that are not existing anymore.
- foreach (array_diff_key($entities, $db_entities) as $entity) {
- $entity->delete();
- }
-
- // Updates the service with the new cache expiration value.
- $cache_control = explode('=', $response->getHeader('cache-control'));
- $expires = $response->getDate()->format('U') + $cache_control[1];
- $service->setCacheControl($language, 'wow_character', 'class', $expires);
}
return $entities;
}
+
+ /**
+ * When the service response is 200 OK, compares the response to the local
+ * database, performs updates, creates, and deletes operations on entities.
+ *
+ * @param WoWDataService $service
+ * @param WoWResponse $response
+ * @param array $entities
+ */
+ protected function onResult(WoWDataService $service, WoWResponse $response, array $entities) {
+ $new_entities = array();
+ // Builds the array of entities to return.
+ foreach ($response->getData($this->remoteKey) as $values) {
+ $id = $values[$this->idKey];
+ // Creates entities from their remote equivalent. The idKey respects a
+ // 1-1 relationship with the database.
+ $new_entities[$id] = $this->storage->create($values + array(
+ 'language' => $language,
+ 'is_new' => empty($entities[$id])
+ ));
+
+ // Permanently saves the entity.
+ $new_entities[$id]->save();
+ }
+
+ // Deletes entities that are not existing anymore in the service.
+ foreach (array_diff_key($entities, $new_entities) as $entity) {
+ $entity->delete();
+ }
+
+ // Updates the service with the new cache expiration value.
+ $cache_control = explode('=', $response->getHeader('cache-control'));
+ $expires = $response->getDate()->format('U') + $cache_control[1];
+ $service->setCacheControl($language, $this->moduleKey, $this->remoteKey, $expires);
+
+ return $new_entities;
+ }
+
}
diff --git a/lib/WoW/Core/Entity/Entity.php b/lib/WoW/Core/Entity/Entity.php
index e7164af3a8f61dcce08403be4b3e262e5a646702..6a6c30a7ed85301faa13050b2b453c3481e8bbc9 100755
--- a/lib/WoW/Core/Entity/Entity.php
+++ b/lib/WoW/Core/Entity/Entity.php
@@ -39,22 +39,7 @@ abstract class WoWEntity extends Entity {
public $language = LANGUAGE_NONE;
/**
- * Merges an entity with a response object.
- *
- * @param array $data
- * The entity array as returned by the service.
- */
- public function merge(array $values) {
- foreach ($values as $key => $value) {
- $this->{$key} = $value;
- }
- }
-
- /**
- * Fetch a remote entity from the service.
- *
- * @param array $fields
- * (Optional) An array of fields to request.
+ * Refresh this remote entity from the service.
*
* @return WoWResponse
* An response object in case of HTTP status 200 or 304.
@@ -62,7 +47,7 @@ abstract class WoWEntity extends Entity {
* @throws WoWException
* An HTTP Exception in case of HTTP status 500 or 404.
*/
- public function fetch(array $fields = array()) {
- return wow_service_controller($this->entityType)->fetch($this, $fields);
+ public function refresh(array $fields = array()) {
+ return wow_service_controller($this->entityType)->refresh($this);
}
}
diff --git a/lib/WoW/Core/Entity/EntityServiceController.php b/lib/WoW/Core/Entity/EntityServiceController.php
index 55f71a3adf5b59de90a3859ce899ac160b2b9feb..72e8c31723e2b01db21139f346dfa7d1c555b850 100755
--- a/lib/WoW/Core/Entity/EntityServiceController.php
+++ b/lib/WoW/Core/Entity/EntityServiceController.php
@@ -46,16 +46,18 @@ abstract class WoWEntityServiceController {
/**
* Constructs an EntityServiceController abstract class.
*
- * @param string $entity_type
+ * @param string $entityType
* The entity type.
- * @param array $entity_info
+ * @param array $entityInfo
* The entity info array of an entity type.
+ * @param EntityAPIControllerInterface $storage
+ * The entity storage controller.
*/
- public function __construct($entity_type, $entity_info) {
- $this->entityType = $entity_type;
- $this->entityInfo = $entity_info;
- $this->idKey = $entity_info['entity keys']['id'];
- $this->storage = entity_get_controller($entity_type);
+ public function __construct($entityType, array $entityInfo, EntityAPIControllerInterface $storage) {
+ $this->entityType = $entityType;
+ $this->entityInfo = $entityInfo;
+ $this->idKey = $entityInfo['entity keys']['id'];
+ $this->storage = $storage;
}
/**
@@ -69,6 +71,8 @@ abstract class WoWEntityServiceController {
$entity->lastFetched = $response->getDate()->format('U');
if ($response->getCode() == 304 || $response->getCode() == 404) {
+ // @TODO: remove '404' from IF statement in Drupal 8. This wont be needed
+ // anymore.
// Updates the lastFetched time stamp. This will avoid the trigger of a
// refresh when deleting an entity for instance if the refresh method is
// set at load time.
@@ -95,8 +99,6 @@ abstract class WoWEntityServiceController {
$this->merge($entity, $response);
break;
}
-
- return $response;
}
/**
@@ -108,6 +110,8 @@ abstract class WoWEntityServiceController {
* The response object as returned by the service.
*/
public function merge(WoWEntity $entity, WoWResponse $response) {
- $entity->merge($response->getData());
+ foreach ($response->getData() as $key => $value) {
+ $entity->{$key} = $value;
+ }
}
}
diff --git a/lib/WoW/Core/Entity/EntityStorageController.php b/lib/WoW/Core/Entity/EntityStorageController.php
index 310a5cc08dc47bc2fdd10e3ed44f47154da19ee6..35336562b17a82357b77ba1dfd1ae5c60c78d616 100755
--- a/lib/WoW/Core/Entity/EntityStorageController.php
+++ b/lib/WoW/Core/Entity/EntityStorageController.php
@@ -61,8 +61,11 @@ abstract class WoWEntityStorageController extends EntityAPIController {
foreach ($queried_entities as $entity) {
// Check the lastFetched value before proceeding to an update.
if ($entity->lastFetched + $this->refreshThreshold < REQUEST_TIME) {
- // Refresh the entity by calling the service.
- module_invoke($this->entityInfo['load hook'], 'refresh', $entity);
+ // For efficiency manually save the original character before applying
+ // any changes.
+ $entity->original = clone $entity;
+ $entity->refresh();
+ $entity->save();
}
}
}
diff --git a/lib/WoW/Core/Handler.php b/lib/WoW/Core/Handler.php
new file mode 100755
index 0000000000000000000000000000000000000000..42307cfebd8cf2ab2f2ca3d55bef779825ded5cb
--- /dev/null
+++ b/lib/WoW/Core/Handler.php
@@ -0,0 +1,92 @@
+request = $request;
+ $this->service = $service;
+ $this->handlers = array();
+ }
+
+ /**
+ * Executes the request.
+ *
+ * @return WoWResponse|mixed
+ * The response returned by the service or by the handler function if defined.
+ */
+ public function execute() {
+ $response = $this->request->execute();
+
+ // Checks if a handler has been registered for this response code.
+ if (isset($this->handlers[$response->getCode()])) {
+ $handler = $this->handlers[$response->getCode()];
+
+ if (is_null($handler['parameters'])) {
+ return $handler['callback'];
+ }
+ else {
+ // Adds this response object as first parameter.
+ array_unshift($handler['parameters'], $this->service, $response);
+ return call_user_func_array($handler['callback'], $handler['parameters']);
+ }
+ }
+ else {
+ // No handlers has been defined for this response: throw an exception.
+ throw new WoWException($response);
+ }
+ }
+
+ /**
+ * Adds a response handler to the request.
+ *
+ * @param int $code
+ * The response code.
+ * @param callback $callback
+ * The callback to be called.
+ * @param array $parameters
+ * The parameters to be passed to the callback, as an indexed array.
+ */
+ public function onResponse($code, $callback, array $parameters) {
+ $this->handlers[$code] = array(
+ 'callback' => $callback,
+ 'parameters' => $parameters,
+ );
+
+ return $this;
+ }
+}
diff --git a/lib/WoW/Core/Request.php b/lib/WoW/Core/Request.php
index 563b8dbce94702ac77d16d4ced66028e12da1810..f8c2b4f3084548bafa5650085d0016874d405066 100755
--- a/lib/WoW/Core/Request.php
+++ b/lib/WoW/Core/Request.php
@@ -1,5 +1,4 @@
path = $path;
$this->query = array();
$this->headers = array();
+ $this->handlers = array();
}
/**
@@ -80,7 +80,7 @@ class WoWRequest {
* The Request.
*/
public function setLocale($language) {
- // Prepares the query by adding a locale string if supported.
+ // Prepares the query by adding a locale parameter if supported.
if ($locale = $this->service->getLocale($language)) {
$this->query['locale'] = $locale;
}
@@ -88,7 +88,7 @@ class WoWRequest {
}
/**
- * Adds a query parameter to the request.
+ * Adds a non-empty query parameter to the request.
*
* @param string $key
* The query key.
@@ -99,15 +99,32 @@ class WoWRequest {
* The Request.
*/
public function setQuery($key, $value) {
- $this->query[$key] = is_array($value) ? implode(",", $value) : $value;
+ if (!empty($value)) {
+ $this->query[$key] = is_array($value) ? implode(",", $value) : $value;
+ }
return $this;
}
+ /**
+ * Adds a response handler to the request.
+ *
+ * @param int $code
+ * The response code.
+ * @param callback $callback
+ * The callback to be called.
+ * @param array $parameters
+ * The parameters to be passed to the callback, as an indexed array.
+ */
+ public function onResponse($code, $callback, array $parameters) {
+ $handler = new WoWHandler($this, $this->service);
+ return $handler->onResponse($code, $callback, $parameters);
+ }
+
/**
* Executes the request.
*
* @return WoWResponse
- * The response returned by the service.
+ * The response returned by the service
*/
public function execute() {
// The date is used to sign the request, in the following format:
diff --git a/modules/wow_character/lib/WoW/Character/CharacterClassServiceController.php b/modules/wow_character/lib/WoW/Character/CharacterClassServiceController.php
index 28f9aa7ef4f03ddf655de7a43b11b5d9d9b01d2b..a8a2ff9636cc452014c90100283cc1fdcb3931af 100755
--- a/modules/wow_character/lib/WoW/Character/CharacterClassServiceController.php
+++ b/modules/wow_character/lib/WoW/Character/CharacterClassServiceController.php
@@ -70,9 +70,11 @@ class WoWCharacterClassServiceController implements WoWDataServiceControllerInte
$response = wow_service($region)
->newRequest('data/character/classes')
->setLocale($language)
- ->execute();
+ ->onResponse(200, array($this, 'onResult'), $parameters)
+ ->execute();
- $entities = $this->storage->load(FALSE);
+ $entities = array();
+ $db_entities = $this->storage->load(FALSE);
//
if ($response->getCode() == 200) {
@@ -82,17 +84,16 @@ class WoWCharacterClassServiceController implements WoWDataServiceControllerInte
foreach ($response->getData('classes') as $values) {
$id = $values[$this->idKey];
- // Saves the entity.
- $this->storage->create($values + array(
+ // Creates the entity from service values.
+ $entities[$id] = $this->storage->create($values + array(
'language' => $language,
- 'is_new' => empty($entities[$id]),
- ))->save();
-
- // Flag as not delete.
- unset($entities[$id]);
+ 'is_new' => empty($db_entities[$id]),
+ ));
+ // Permanently saves the entity.
+ $entities[$id]->save();
}
- foreach ($entities as $entity) {
+ foreach (array_diff_key($db_entities, $entities) as $entity) {
// Deletes extra entities that are not in the service anymore.
$entity->delete();
}
diff --git a/modules/wow_character/lib/WoW/Character/CharacterServiceController.php b/modules/wow_character/lib/WoW/Character/CharacterServiceController.php
index 5b52ffd5c4d778a575476b8c8edd19b434c59d76..18f47ca6f80478ade4caef0f15f045f0b440fabd 100755
--- a/modules/wow_character/lib/WoW/Character/CharacterServiceController.php
+++ b/modules/wow_character/lib/WoW/Character/CharacterServiceController.php
@@ -13,6 +13,66 @@
*/
class WoWCharacterServiceController extends WoWEntityServiceController {
+ /**
+ * The list of fields supported by the character resource end point.
+ *
+ * @var array
+ */
+ public static $fields = array(
+ 'achievements',
+ 'appearance',
+ 'feed',
+ 'guild',
+ 'hunterPets',
+ 'items',
+ 'mounts',
+ 'pets',
+ 'petSlots',
+ 'professions',
+ 'progression',
+ 'pvp',
+ 'quest',
+ 'reputation',
+ 'stats',
+ 'talents',
+ 'titles'
+ );
+
+ /**
+ * Refreshes a Character entity.
+ *
+ * @param WoWCharacter $character
+ * The wow_character entity to refresh.
+ *
+ * @return WoWResponse
+ * The Response object returned by the service.
+ *
+ * @throws WoWException
+ * An exception in case of HTTP status 404, 500 or 503.
+ */
+ public function refresh(WoWCharacter $character) {
+ $fields = array();
+ // Fields are user defined: builds the 'fields' parameter with only what is
+ // needed by the entity.
+ foreach (self::$fields as $key) {
+ if (isset($character->{$key})) {
+ $fields[] = $key;
+ }
+ }
+
+ $response = wow_service($character->region)
+ ->newRequest("character/$character->realm/$character->name")
+ ->setQuery('fields', $fields)
+ ->setLocale($character->language)
+ ->setIfModifiedSince($character->lastModified)
+ ->execute();
+
+ // Handles the response from the service.
+ $this->handleResponse($character, $response);
+
+ return $response;
+ }
+
/**
* The Character API is the primary way to access character information.
*
@@ -24,8 +84,12 @@ class WoWCharacterServiceController extends WoWEntityServiceController {
* or more additional fields can be retrieved. To access this API, craft a
* resource URL pointing to the character whos information is to be retrieved.
*
- * @param WoWCharacter $character
- * The wow_character entity.
+ * @param string $region
+ * The guild region.
+ * @param string $realm
+ * The character realm.
+ * @param string $name
+ * The character name.
* @param array $fields
* An array of fields to fetch:
* - achievements: A map of achievement data including completion timestamps
@@ -59,32 +123,29 @@ class WoWCharacterServiceController extends WoWEntityServiceController {
* - titles: A list of the titles obtained by the character including the
* currently selected title.
*
- * @return WoWResponse
- * The Response object returned by the service.
+ * @return WoWCharacter
+ * The Character object returned by the service.
*
* @throws WoWException
* An exception in case of HTTP status 404, 500 or 503.
*/
- public function refresh(WoWCharacter $character) {
+ public function fetch($region, $realm, $name, array $fields = array()) {
+ $values = array('region' => $region, 'realm' => $realm, 'name' => $name);
+ $entities = $this->storage->load(FALSE, $values);
+ // Creates the character entity if not found from the storage.
+ $character = empty($entities) ? reset($entities) : $this->storage->create($values);
+
$response = wow_service($character->region)
->newRequest("character/$character->realm/$character->name")
-// ->setQuery('fields', $fields)
+ ->setQuery('fields', $fields)
->setLocale($character->language)
->setIfModifiedSince($character->lastModified)
->execute();
- return $this->handleResponse($character, $response);
- }
+ // Handles the response from the service.
+ $this->handleResponse($character, $response);
- public function fetch($realm, $name, array $fields = array()) {
- $character = db_select('wow_characters', 'c')
- ->fields('c', array('cid'))
- ->condition('region', $region)
- ->condition('realm', $realm)
- ->condition('name', $name)
- ->execute()
- ->fetch();
- wow_character_load_by_name($region, $realm, $name);
+ return $character;
}
/**
@@ -92,7 +153,7 @@ class WoWCharacterServiceController extends WoWEntityServiceController {
* @see WoWEntityServiceController::merge()
*/
public function merge($entity, WoWResponse $response) {
- $entity->merge($response->getData());
+ parent::merge($entity, $response);
$entity->lastModified = $response->getData('lastModified') / 1000;
}
}
diff --git a/modules/wow_character/wow_character.character.inc b/modules/wow_character/wow_character.character.inc
index 84addecc0bf096c4a36183ac79353775353cfb52..9ee50f66812716ffe864dbc027f4a5c9720a3990 100755
--- a/modules/wow_character/wow_character.character.inc
+++ b/modules/wow_character/wow_character.character.inc
@@ -2,7 +2,7 @@
/**
* @file
- * Contains funtions to interact with character module hooks.
+ * Contains functions to interact with character module hooks.
*/
/**
diff --git a/modules/wow_character/wow_character.module b/modules/wow_character/wow_character.module
index dbe9af1241468f69f6748943ca44095f87c7c0cc..5722f7c20b3f40d7325266473f42f4b3e4c11ed7 100644
--- a/modules/wow_character/wow_character.module
+++ b/modules/wow_character/wow_character.module
@@ -234,31 +234,6 @@ function wow_character_uri_load($region, $realm, $name) {
return $character ? wow_character_load($character->cid) : FALSE;
}
-/**
- * Load a character object from the database.
- *
- * @param string $region
- * The character region.
- * @param string $realm
- * The character realm.
- * @param string $name
- * The character name.
- *
- * @return WoWCharacter
- * A fully-populated character object.
- */
-function wow_character_load_by_name($region, $realm, $name) {
- $character = db_select('wow_characters', 'c')
- ->fields('c', array('cid'))
- ->condition('region', $region)
- ->condition('realm', wow_realm_to_slug($realm))
- ->condition('name', drupal_ucfirst($name))
- ->execute()
- ->fetch();
-
- return $character ? wow_character_load($character->cid) : FALSE;
-}
-
/**
* Implements hook_user_delete().
*/
@@ -339,6 +314,7 @@ function wow_character_entity_info() {
'entity class' => 'WoWCharacterRace',
'controller class' => 'WoWCharacterRaceController',
'service controller class' => 'WoWDataServiceController',
+ 'remote path' => 'character/classes',
'base table' => 'wow_character_races',
'load hook' => 'wow_character_race',
'fieldable' => TRUE,
@@ -347,6 +323,7 @@ function wow_character_entity_info() {
),
'entity keys' => array(
'id' => 'id',
+ 'remote' => 'classes',
),
),
'wow_character_class' => array(
@@ -504,48 +481,17 @@ function _wow_character_class_callback(&$values, $class) {
* - titles: A list of the titles obtained by the character including the
* currently selected title.
*
- * @param array $options
- * (Optional) For a complete list of options, see wow_http_request method.
- * @param Boolean $catch
- * Whether to catch exceptions or not.
- *
* @return WoWCharacter
* The character object returned by the API. The core dataset returned includes
* the character's name, level, class, gender and achievement points.
*
- * @see wow_http_request()
- */
-function wow_character_fetch($region, $realm, $name, array $fields = array(), array $options = array(), $catch = TRUE) {
- $character = wow_character_load_by_name($region, $realm, $name);
-
- if (!$character) {
- $character = entity_create('wow_character', array(
- 'region' => $region,
- 'realm' => $realm,
- 'name' => $name,
- ));
- }
-
- $character->fetch($fields, $options, $catch);
- return $character;
-}
-
-/**
- * Fetch an already know character.
- *
- * @param WoWCharacter $character
- * A character entity.
- * @param array $fields
- * (Optional) For the complete list of fields supported, see wow_character_fetch method.
+ * @throws WoWException
+ * An exception in case of HTTP status 404, 500 or 503.
*
- * @see wow_character_fetch()
- * @see wow_http_request()
+ * @see WoWCharacterServiceController::fetch()
*/
-function wow_character_refresh(WoWCharacter $character, array $fields = array()) {
- // For efficiency manually save the original character before applying any changes.
- $character->original = clone $character;
- $character->fetch($fields);
- $character->save();
+function wow_character_fetch($region, $realm, $name, array $fields = array()) {
+ return wow_service_controller('wow_character')->fetch($region, $realm, $name, $fields);
}
/**
@@ -598,7 +544,8 @@ function wow_character_cron() {
->fetchCol();
// Long-running tasks and tasks that could time out, such as retrieving
- // remote data makes use of the queue API instead of executing tak directly.
+ // remote data makes use of the queue API instead of executing task
+ // directly.
$queue = DrupalQueue::get('wow_character');
foreach (wow_character_load_multiple($cids) as $character) {
// Add characters that need to be refreshed to the wow_character queue.
diff --git a/modules/wow_character/wow_character.pages.inc b/modules/wow_character/wow_character.pages.inc
index 4d9b11314cd36b222491f0cc2348624f3e482357..0300ba366e7d93345b866380004bab2b6a2ebc58 100644
--- a/modules/wow_character/wow_character.pages.inc
+++ b/modules/wow_character/wow_character.pages.inc
@@ -139,20 +139,15 @@ function wow_character_user_add_validate($form, &$form_state) {
$realm = $form_state['values']['realm'];
$character_name = $form_state['values']['name'];
$fields = module_exists('wow_guild') ? array('guild') : array();
- $character = wow_character_load_by_name($realm->region, $realm->slug, $character_name);
- $character = wow_character_fetch($realm->region, $realm->slug, $character_name, $fields, array(), FALSE);
- $debug = true;
+ $character = wow_character_fetch($realm->region, $realm->slug, $character_name, $fields);
}
catch (WoWException $exception) {
switch ($exception->getCode()) {
- case 304:
- // Already loaded previously.
- $character = wow_character_load_by_name($realm->region, $realm->slug, $character_name);
- break;
case 404:
$args = array('%name' => $character_name, '!realm' => drupal_strtoupper($realm->region) . '-' . $realm->name);
form_set_error('name', t('%name not found on !realm. Please try again with a correct name.', $args));
return;
+ // @TODO: 503 and a default exception handler.
default:
watchdog_exception('wow_character', $exception, t('An exception has been thrown during the %name character validation.', array('%name' => $character_name)));
form_set_error('name', t('The website encountered an unexpected error. Please try again later.'));
@@ -194,6 +189,7 @@ function wow_character_user_add_validate($form, &$form_state) {
*/
function wow_character_user_add_submit($form, &$form_state) {
$character = $form_state['character'];
+ // @TODO: pass only the uid to saves bandwidth. Or reuse arg1 ? $account.
$character->uid = $form_state['user']->uid;
$character->save();
diff --git a/modules/wow_realm/wow_realm.info b/modules/wow_realm/wow_realm.info
index 78666d09884cc36ad1e636c0429ba627f023c605..9b05249603f91903bad27d3e4e648d21a6659c7e 100644
--- a/modules/wow_realm/wow_realm.info
+++ b/modules/wow_realm/wow_realm.info
@@ -1,10 +1,7 @@
name = "Realm"
-description = "Realm APIs currently provide realm status information."
+description = "Logs API request statistics."
package = World of Warcraft
dependencies[] = wow
core = 7.x
-configure = admin/config/wow/realm
-
-files[] = lib/WoW/Realm/Realm.php
-files[] = lib/WoW/Realm/RealmServiceController.php
+files[] = lib/WoW/Statistics/Realm.php
diff --git a/modules/wow_statistics/wow_statistics.info b/modules/wow_statistics/wow_statistics.info
new file mode 100755
index 0000000000000000000000000000000000000000..51c122970bc714e033750a987a55b6bf8f0fa369
--- /dev/null
+++ b/modules/wow_statistics/wow_statistics.info
@@ -0,0 +1,10 @@
+name = "Statistics"
+description = "Realm APIs currently provide realm status information."
+package = World of Warcraft
+dependencies[] = wow
+core = 7.x
+
+configure = admin/config/wow/realm
+
+files[] = lib/WoW/Realm/Realm.php
+files[] = lib/WoW/Realm/RealmServiceController.php
diff --git a/wow.module b/wow.module
index 5a32723e4c5e1dbad4edc49fa145a419ab249c74..13b6fb0bda31aa911ed409ac46fb783583d839bd 100644
--- a/wow.module
+++ b/wow.module
@@ -612,11 +612,14 @@ function wow_service_list($field = 'language') {
*/
function wow_service_controller($entity_type) {
$controllers = &drupal_static(__FUNCTION__, array());
+
if (!isset($controllers[$entity_type])) {
$entity_info = entity_get_info($entity_type);
$class = $entity_info['service controller class'];
- $controllers[$entity_type] = new $class($entity_type, $entity_info);
+ $storage = entity_get_controller($entity_type);
+ $controllers[$entity_type] = new $class($entity_type, $entity_info, $storage);
}
+
return $controllers[$entity_type];
}
@@ -641,18 +644,12 @@ function wow_service($region) {
// creation. For now the database is called each time a new region is created.
if (!isset($services[$region])) {
// Returns the enabled services and their configuration.
- $result = db_select('wow_services', 's')
+ $locales = db_select('wow_services', 's')
->fields('s', array('language', 'locale'))
->condition('enabled', TRUE)
->condition('region', $region)
- ->execute();
-
- // Creates the array of supported locales for this service, keyed by
- // language.
- $locales = array();
- foreach($result->fetchAllAssoc('language') as $language => $row) {
- $locales[$language] = $row->locale;
- }
+ ->execute()
+ ->fetchAllKeyed();
// Configures the service to return. We use here static IoC based on the
// public and private key configuration.
@@ -660,12 +657,16 @@ function wow_service($region) {
$public_key = variable_get('wow_public_key');
if (empty($key) || empty($public_key) || !extension_loaded('openssl')) {
// Sets an HTTP implementation of the service.
- $services[$region] = new WoWServiceHttp(wow_api_info($region)->host, $locales);
+ $service = new WoWServiceHttp(wow_api_info($region)->host, $locales);
}
else {
// Sets an HTTPS implementation of the service.
- $services[$region] = new WoWServiceHttps(wow_api_info($region)->host, $locales);
+ $service = new WoWServiceHttps(wow_api_info($region)->host, $locales);
}
+
+ module_invoke_all('service', $service);
+
+ $services[$region] = $service;
}
return $services[$region];