diff --git a/phpcs.xml b/phpcs.xml
index 7ba6b304..b98b14a9 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -26,13 +26,6 @@
-
-
-
-
-
-
-
diff --git a/src/Controller/ViewerController.php b/src/Controller/ViewerController.php
index 5835bb3f..083b9166 100644
--- a/src/Controller/ViewerController.php
+++ b/src/Controller/ViewerController.php
@@ -24,10 +24,18 @@
*/
class ViewerController extends ControllerBase {
+ /**
+ * The renderer service.
+ *
+ * @var \Drupal\Core\Render\RendererInterface
+ */
private $renderer;
/**
* The controller constructor.
+ *
+ * @param \Drupal\Core\Render\RendererInterface $renderer
+ * The renderer service.
*/
public function __construct(RendererInterface $renderer) {
$this->renderer = $renderer;
@@ -45,9 +53,14 @@ public static function create(ContainerInterface $container): self {
/**
* Returns a raw page for the iframe embed.
*
- * Set edit to true for an editor.
+ * @param \Drupal\media\Entity\Media $media
+ * Media entity.
+ * @param bool $edit
+ * TRUE to open Collabora Online in edit mode.
+ * FALSE to open Collabora Online in readonly mode.
*
- * @return Response
+ * @return \Symfony\Component\HttpFoundation\Response
+ * Response suitable for iframe, without the usual page decorations.
*/
public function editor(Media $media, $edit = FALSE) {
$options = [
diff --git a/src/Controller/WopiController.php b/src/Controller/WopiController.php
index 9ca7d088..4f22dd4a 100644
--- a/src/Controller/WopiController.php
+++ b/src/Controller/WopiController.php
@@ -40,6 +40,17 @@ public static function permissionDenied(): Response {
);
}
+ /**
+ * Handles the WOPI 'info' request for a media entity.
+ *
+ * @param string $id
+ * Media id from url.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * Request object with query parameters.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ * The response with file contents.
+ */
public function wopiCheckFileInfo(string $id, Request $request) {
$token = $request->query->get('access_token');
@@ -97,6 +108,17 @@ public function wopiCheckFileInfo(string $id, Request $request) {
return $response;
}
+ /**
+ * Handles the wopi "content" request for a media entity.
+ *
+ * @param string $id
+ * Media id from url.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * Request object with query parameters.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ * The response with file contents.
+ */
public function wopiGetFile(string $id, Request $request) {
$token = $request->query->get('access_token');
@@ -121,6 +143,17 @@ public function wopiGetFile(string $id, Request $request) {
return $response;
}
+ /**
+ * Handles the wopi "save" request for a media entity..
+ *
+ * @param string $id
+ * Media id from url.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * Request object with headers, query parameters and payload.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ * The response.
+ */
public function wopiPutFile(string $id, Request $request) {
$token = $request->query->get('access_token');
$timestamp = $request->headers->get('x-cool-wopi-timestamp');
@@ -214,11 +247,15 @@ public function wopiPutFile(string $id, Request $request) {
/**
* The WOPI entry point.
*
- * action: 'info', 'content' or 'save'.
- * id: the ID of the media.
- * request: The request as originating.
+ * @param string $action
+ * One of 'info', 'content' or 'save', depending with path is visited.
+ * @param string $id
+ * Media id from url.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * Request object for headers and query parameters.
*
- * @return Response
+ * @return \Symfony\Component\HttpFoundation\Response
+ * Response to be consumed by Collabora Online.
*/
public function wopi(string $action, string $id, Request $request) {
$returnCode = Response::HTTP_BAD_REQUEST;
diff --git a/src/Cool/CoolRequest.php b/src/Cool/CoolRequest.php
index 394530ac..631457aa 100644
--- a/src/Cool/CoolRequest.php
+++ b/src/Cool/CoolRequest.php
@@ -13,9 +13,13 @@
namespace Drupal\collabora_online\Cool;
/**
- * Get the discovery XML content
+ * Gets the contents of discovery.xml from the Collabora server.
*
- * Return `false` in case of error.
+ * @param string $server
+ * Url of the Collabora Online server.
+ *
+ * @return string|false
+ * The full contents of discovery.xml, or FALSE on failure.
*/
function getDiscovery($server) {
$discovery_url = $server . '/hosting/discovery';
@@ -36,6 +40,19 @@ function getDiscovery($server) {
return $res;
}
+/**
+ * Extracts a WOPI url from the parsed discovery.xml.
+ *
+ * @param \SimpleXMLElement|null|false $discovery_parsed
+ * Parsed contents from discovery.xml from the Collabora server.
+ * Currently, NULL or FALSE are supported too, but lead to NULL return value.
+ * @param string $mimetype
+ * MIME type for which to fetch the WOPI url. E.g. 'text/plain'.
+ *
+ * @return mixed|null
+ * WOPI url as configured for this MIME type in discovery.xml, or NULL if none
+ * was found for the given MIME type.
+ */
function getWopiSrcUrl($discovery_parsed, $mimetype) {
if ($discovery_parsed === NULL || $discovery_parsed == FALSE) {
return NULL;
@@ -47,13 +64,34 @@ function getWopiSrcUrl($discovery_parsed, $mimetype) {
return NULL;
}
+/**
+ * Checks if a string starts with another string.
+ *
+ * @param string $s
+ * Haystack.
+ * @param string $ss
+ * Needle.
+ *
+ * @return bool
+ * TRUE if $ss is a prefix of $s.
+ *
+ * @see str_starts_with()
+ */
function strStartsWith($s, $ss) {
$res = strrpos($s, $ss);
return !is_bool($res) && $res == 0;
}
+/**
+ * Helper class to fetch a WOPI client url.
+ */
class CoolRequest {
+ /**
+ * Error code from last attempt to fetch the client WOPI url.
+ *
+ * @var int
+ */
private $error_code;
const ERROR_MSG = [
@@ -67,18 +105,37 @@ class CoolRequest {
204 => 'Warning! You have to specify the scheme protocol too (http|https) for the server address.',
];
+ /**
+ * The WOPI url that was last fetched, or '' as initial value.
+ *
+ * @var int
+ */
private $wopi_src;
+ /**
+ * Constructor.
+ */
public function __construct() {
$this->error_code = 0;
$this->wopi_src = '';
}
+ /**
+ * Gets an error string from the last attempt to fetch the WOPI url.
+ *
+ * @return string
+ * Error string containing int error code and a message.
+ */
public function errorString() {
return $this->error_code . ': ' . static::ERROR_MSG[$this->error_code];
}
- /** Return the wopi client URL */
+ /**
+ * Gets the URL for the WOPI client.
+ *
+ * @return string|null
+ * The WOPI client url, or NULL on failure.
+ */
public function getWopiClientURL() {
$_HOST_SCHEME = isset($_SERVER['HTTPS']) ? 'https' : 'http';
$default_config = \Drupal::config('collabora_online.settings');
diff --git a/src/Cool/CoolUtils.php b/src/Cool/CoolUtils.php
index 1db446f7..f8c4b8e3 100644
--- a/src/Cool/CoolUtils.php
+++ b/src/Cool/CoolUtils.php
@@ -18,9 +18,20 @@
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
+/**
+ * Class with various static methods.
+ */
class CoolUtils {
- /** Get the file from the Media entity */
+ /**
+ * Gets the file referenced by a media entity.
+ *
+ * @param \Drupal\media\Entity\Media $media
+ * The media entity.
+ *
+ * @return \Drupal\file\FileInterface|null
+ * The file entity, or NULL if not found.
+ */
public static function getFile(Media $media) {
$fid = $media->getSource()->getSourceFieldValue($media);
$file = File::load($fid);
@@ -28,19 +39,40 @@ public static function getFile(Media $media) {
return $file;
}
- /** Get the file based on the entity id */
+ /**
+ * Gets a file based on the media id.
+ *
+ * @param int|string $id
+ * Media id which might be in strong form like '123'.
+ *
+ * @return \Drupal\file\FileInterface|null
+ * File referenced by the media entity, or NULL if not found.
+ */
public static function getFileById($id) {
/** @var \Drupal\media\MediaInterface|null $media */
$media = \Drupal::entityTypeManager()->getStorage('media')->load($id);
return CoolUtils::getFile($media);
}
+ /**
+ * Sets the file entity reference for a media entity.
+ *
+ * @param \Drupal\media\Entity\Media $media
+ * Media entity to be modified.
+ * @param \Drupal\file\Entity\File $source
+ * File entity to reference.
+ */
public static function setMediaSource(Media $media, File $source) {
$name = $media->getSource()->getSourceFieldDefinition($media->bundle->entity)->getName();
$media->set($name, $source);
}
- /** Obtain the signing key from the key storage */
+ /**
+ * Obtains the signing key from the key storage.
+ *
+ * @return string
+ * The key value.
+ */
public static function getKey() {
$default_config = \Drupal::config('collabora_online.settings');
$key_id = $default_config->get('cool')['key_id'];
@@ -49,11 +81,22 @@ public static function getKey() {
return $key;
}
- /** Verify JWT token
+ /**
+ * Decodes and verifies a JWT token.
*
- * Verification include:
+ * Verification include:
* - matching $id with fid in the payload
- * - verifying the expiration
+ * - verifying the expiration.
+ *
+ * @param string $token
+ * The token to verify.
+ * @param int|string $id
+ * Media id for which the token was created.
+ * This could be in string form like '123'.
+ *
+ * @return \stdClass|null
+ * Data decoded from the token, or NULL on failure or if the token has
+ * expired.
*/
public static function verifyTokenForId(
#[\SensitiveParameter]
@@ -75,7 +118,10 @@ public static function verifyTokenForId(
}
/**
- * Return the TTL of the token in seconds, from the EPOCH.
+ * Gets the TTL of the token in seconds, from the EPOCH.
+ *
+ * @return int
+ * Token TTL in seconds.
*/
public static function getAccessTokenTtl() {
$default_config = \Drupal::config('collabora_online.settings');
@@ -85,8 +131,7 @@ public static function getAccessTokenTtl() {
}
/**
- * Create a JWT token for the Media with id $id, a $ttl, and an
- * eventual write permission.
+ * Creates a JWT token for a media entity.
*
* The token will carry the following:
*
@@ -97,6 +142,16 @@ public static function getAccessTokenTtl() {
* - wri: if true, then this token has write permissions.
*
* The signing key is stored in Drupal key management.
+ *
+ * @param int|string $id
+ * Media id, which could be in string form like '123'.
+ * @param int $ttl
+ * Access token TTL in seconds.
+ * @param bool $can_write
+ * TRUE if the token is for an editor in write/edit mode.
+ *
+ * @return string
+ * The access token.
*/
public static function tokenForFileId($id, $ttl, $can_write = FALSE) {
$payload = [
@@ -112,8 +167,7 @@ public static function tokenForFileId($id, $ttl, $can_write = FALSE) {
}
/**
- * List of read only formats. Currently limited to the one Drupal
- * accept.
+ * List of read only formats. Currently limited to the one Drupal accept.
*/
const READ_ONLY = [
'application/x-iwork-keynote-sffkey' => TRUE,
@@ -122,24 +176,48 @@ public static function tokenForFileId($id, $ttl, $can_write = FALSE) {
];
/**
- * Return if we can edit that media file.
+ * Determines if we can edit that media file.
*
* There are few types that Collabora Online only views.
+ *
+ * @param \Drupal\file\Entity\File $file
+ * File entity.
+ *
+ * @return bool
+ * TRUE if the file has a file type that is supported for editing.
+ * FALSE if the file can only be opened as read-only.
*/
public static function canEdit(File $file) {
$mimetype = $file->getMimeType();
return !array_key_exists($mimetype, static::READ_ONLY);
}
- /** Return the mime type for the document.
+ /**
+ * Gets the mime type for the document.
+ *
+ * Drupal will figure it out for us.
+ *
+ * @param \Drupal\file\Entity\File $file
+ * File entity.
*
- * Drupal will figure it out for us.
+ * @return string|null
+ * The mime type, or NULL if it cannot be determined.
*/
public static function getDocumentType(File $file) {
return $file->getMimeType();
}
- /** Return the editor / viewer Drupal URL from the routes configured. */
+ /**
+ * Gets the editor / viewer Drupal URL from the routes configured.
+ *
+ * @param \Drupal\media\Entity\Media $media
+ * Media entity that holds the file to open in the editor.
+ * @param bool $can_write
+ * TRUE for an edit url, FALSE for a read-only preview url.
+ *
+ * @return \Drupal\Core\Url
+ * Editor url to visit as full-page, or to embed in an iframe.
+ */
public static function getEditorUrl(Media $media, $can_write = FALSE) {
if ($can_write) {
return Url::fromRoute('collabora-online.edit', ['media' => $media->id()]);
@@ -150,18 +228,19 @@ public static function getEditorUrl(Media $media, $can_write = FALSE) {
}
/**
- * Get a render array for a cool viewer.
- *
- * @param Media $media
- * The media entity to view / edit
+ * Gets a render array for a cool viewer.
*
+ * @param \Drupal\media\Entity\Media $media
+ * The media entity to view / edit.
* @param bool $can_write
* Whether this is a viewer (false) or an edit (true). Permissions will
* also be checked.
- *
- * @param array $options
+ * @param array{closebutton: bool} $options
* Options for the renderer. Current values:
* - "closebutton" if "true" will add a close box. (see COOL SDK)
+ *
+ * @return array|array{error: string}
+ * A stub render element array, or an array with an error on failure.
*/
public static function getViewerRender(Media $media, bool $can_write, $options = NULL) {
$default_config = \Drupal::config('collabora_online.settings');
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 9831e30b..9d559fd9 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -15,6 +15,9 @@
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
+/**
+ * Form to configure module settings for Collabora.
+ */
class ConfigForm extends ConfigFormBase {
const SETTINGS = 'collabora_online.settings';