diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..51b18f29
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ # Maintain dependencies for Composer
+ - package-ecosystem: "composer"
+ directory: "/"
+ schedule:
+ interval: "daily"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b7a907fb..557a7733 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php-versions: ['7.4', '8.0']
+ php-versions: ['8.1', '8.2', '8.3']
experimental: [false]
steps:
@@ -30,19 +30,15 @@ jobs:
run: composer install --dev --no-interaction
- name: Execute tests without coverage
run: tools/phpunit --testsuite="BigBlueButton unit test suite,BigBlueButton integration test suite"
-
+
PHP:
name: PHP ${{ matrix.php-versions }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
- php-versions: ['7.4','8.0']
+ php-versions: ['8.1', '8.2', '8.3']
experimental: [false]
- include:
- - php-versions: '8.1'
- experimental: true
-
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -65,10 +61,17 @@ jobs:
tools/phpunit --coverage-clover=build/logs/coverage.xml --testsuite="BigBlueButton unit test suite,BigBlueButton integration test suite"
- name: Execute tests without coverage
if: ${{ matrix.experimental }}
- run: tools/phpunit --testsuite="BigBlueButton test suite"
+ run: tools/phpunit --testsuite="BigBlueButton unit test suite,BigBlueButton integration test suite"
continue-on-error: true
- - name: Coveralls
- env:
- COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: ${{ matrix.php-versions == '7.4' && env.COVERALLS_REPO_TOKEN != null }}
- run: tools/php-coveralls --coverage_clover=build/logs/coverage.xml -v
+ - name: Upload coverage
+ if: ${{ matrix.php-versions == '8.1' }}
+ uses: codecov/codecov-action@v3
+ - name: Run rector
+ if: ${{ matrix.php-versions == '8.1' }}
+ run: tools/rector process --dry-run
+ - name: Run psalm
+ if: ${{ matrix.php-versions == '8.1' }}
+ run: tools/psalm
+ - name: Run phpstan
+ if: ${{ matrix.php-versions == '8.1' }}
+ run: tools/phpstan
diff --git a/.gitignore b/.gitignore
index d6bdc7e4..3fdf8edd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,5 @@ reports
#
# See https://github.com/littleredbutton/bigbluebutton-api-php/pull/115 for the discussion.
/composer.lock
+
+/Makefile.iservmake
diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
index a1e6c9dd..93f29942 100644
--- a/.php-cs-fixer.php
+++ b/.php-cs-fixer.php
@@ -5,8 +5,8 @@
$finder = \PhpCsFixer\Finder::create()
->files()
->name('*.php')
- ->in(__DIR__ . '/src')
- ->in(__DIR__ . '/tests');
+ ->in(__DIR__.'/src')
+ ->in(__DIR__.'/tests');
$config = new PhpCsFixer\Config();
@@ -18,6 +18,11 @@
'yoda_style' => false,
'single_line_throw' => false,
'increment_style' => false,
+ 'modernize_strpos' => false,
+ 'get_class_to_class_keyword' => false,
+ 'declare_strict_types' => [
+ 'strategy' => 'enforce'
+ ]
])
->setRiskyAllowed(true)
->setFinder($finder);
diff --git a/README.md b/README.md
index 16290b60..9b29b0ef 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# :tada: Best BigBlueButton API for PHP
The unofficial and easiest to use **BigBlueButton API for PHP**, makes easy for
-developers to use [BigBlueButton API] v2.2+ for **PHP 7.4+**.
+developers to use [BigBlueButton API] v2.2+ for **PHP 8.1+**.

[](https://coveralls.io/github/littleredbutton/bigbluebutton-api-php?branch=master)
@@ -56,7 +56,7 @@ following advantages:
- Development is simplified through git hooks and contributor guidelines
- Documentation is up-to-date and complete
- API is fixed and extended to exploit the full potential
-- Require at least PHP 7.4, which allows to make the code more efficient and
+- Require at least PHP 8.1, which allows to make the code more efficient and
readable
## :gear: Installation and usage
@@ -64,7 +64,7 @@ following advantages:
In order to use this library you have to make sure to meet the following
requirements:
-- PHP 7.4 or above.
+- PHP 8.1 or above.
- curl library installed.
- mbstring library installed.
- xml library installed.
@@ -89,7 +89,7 @@ $bbb = new BigBlueButton($apiUrl, $apiSecret);
If you didn't use composer before, make sure that you include `vendor/autoload.php`.
-In general the usage is closly related to the official [API description](https://docs.bigbluebutton.org/dev/api.html). This means to create a room, you have to create a `CreateMeetingParameters` object and set all required parameters via the related setter method. This means to set the `attendeePW`, you have to call `setAttendeePW` and so on.
+In general the usage is closly related to the official [API description](https://docs.bigbluebutton.org/dev/api.html). This means to create a room, you have to create a `CreateMeetingParameters` object and set all required parameters via the related setter method.
#### Test if API url and secret are valid
```php
@@ -126,8 +126,6 @@ $version = $bbb->getApiVersion()->getVersion();
use BigBlueButton\Parameters\CreateMeetingParameters;
$createMeetingParams = new CreateMeetingParameters($meetingID, $meetingName);
-$createMeetingParams->setAttendeePW($attendee_password);
-$createMeetingParams->setModeratorPW($moderator_password);
$createMeetingResponse = $bbb->createMeeting($createMeetingParams);
@@ -155,10 +153,10 @@ $createMeetingParams->setGuestPolicyAlwaysAcceptAuth();
#### Join a meeting
```php
use BigBlueButton\Parameters\JoinMeetingParameters;
+use BigBlueButton\Enum\Role;
-$joinMeetingParams = new JoinMeetingParameters($room->uid, $displayname, $password);
+$joinMeetingParams = new JoinMeetingParameters($room->uid, $displayname, Role::VIEWER);
$joinMeetingParams->setCreateTime($createMeetingResponse->getCreationTime());
-$joinMeetingParams->setJoinViaHtml5(true);
$joinMeetingParams->setRedirect(true);
$joinUrl = $bbb->getJoinMeetingURL($joinMeetingParams);
@@ -170,7 +168,7 @@ $joinUrl = $bbb->getJoinMeetingURL($joinMeetingParams);
```php
use BigBlueButton\Parameters\EndMeetingParameters;
-$endMeetingParams = new EndMeetingParameters($meetingID, $moderator_password);
+$endMeetingParams = new EndMeetingParameters($meetingID);
$response = $bbb->endMeeting($endMeetingParams);
```
@@ -206,7 +204,7 @@ if ($response->success() && $response->isRunning()) {
```php
use BigBlueButton\Parameters\GetMeetingInfoParameters;
-$getMeetingInfoParams = new GetMeetingInfoParameters($meetingID, $moderator_password);
+$getMeetingInfoParams = new GetMeetingInfoParameters($meetingID);
$response = $bbb->getMeetingInfo($getMeetingInfoParams);
@@ -483,4 +481,3 @@ composer test-integration
Bugs and feature request are tracked on [GitHub](https://github.com/littleredbutton/bigbluebutton-api-php/issues)
[BigBlueButton API]: https://docs.bigbluebutton.org/dev/api.html
-
diff --git a/composer.json b/composer.json
index 0ad3d191..a81e1f04 100644
--- a/composer.json
+++ b/composer.json
@@ -58,11 +58,12 @@
"docs": "https://github.com/littleredbutton/bigbluebutton-api-php/blob/master/README.md"
},
"require": {
- "php": ">=7.4",
+ "php": ">=8.1",
"ext-curl": "*",
"ext-simplexml": "*",
"ext-mbstring": "*",
- "ext-json": "*"
+ "ext-json": "*",
+ "ext-dom": "*"
},
"suggest": {
"psr/http-client-implementation": "To use the PsrHttpClientTransport.",
@@ -74,11 +75,11 @@
"require-dev": {
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
- "psr/http-message": "^1.0",
- "symfony/dotenv": "^3.4|^4.0|^5.0",
- "symfony/http-client-contracts": "^1.1|^2.0",
- "symfony/http-client": "^4.4|^5.0",
- "symfony/process": "^3.4|^4.0|^5.0",
+ "psr/http-message": "^1.0 || ^2.0",
+ "symfony/dotenv": "^5.4|^6.4|^7.0",
+ "symfony/http-client-contracts": "^1.1|^2.0|^3.0",
+ "symfony/http-client": "^5.4|^6.4|^7.0",
+ "symfony/process": "^5.4|^6.4|^7.0",
"nyholm/psr7": "^1.4"
},
"autoload": {
@@ -91,8 +92,17 @@
},
"autoload-dev": {
"psr-4": {
+ "BigBlueButton\\Tests\\Common\\": [
+ "tests/common"
+ ],
"BigBlueButton\\Tests\\Functional\\": [
"tests/functional"
+ ],
+ "BigBlueButton\\Tests\\Integration\\": [
+ "tests/integration"
+ ],
+ "BigBlueButton\\Tests\\Unit\\": [
+ "tests/unit"
]
}
},
@@ -102,9 +112,12 @@
"test-functional": "tools/phpunit --testsuite=\"BigBlueButton functional test suite\" --exclude-group=functional-legacy",
"cs-fix": "tools/php-cs-fixer fix --allow-risky=yes",
"cs-test": "tools/php-cs-fixer fix --dry-run --allow-risky=yes",
- "psalm": "psalm --threads=1",
- "psalm-clear": "psalm --clear-cache && psalm --clear-global-cache",
- "psalm-fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MissingParamType,InvalidFalsableReturnType",
+ "psalm": "tools/psalm --threads=1",
+ "psalm-clear": "tools/psalm --clear-cache && tools/psalm --clear-global-cache",
+ "psalm-fix": "tools/psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MissingParamType,InvalidFalsableReturnType",
+ "phpstan": "tools/phpstan analyse",
+ "rector": "tools/rector process --dry-run src/ tests/",
+ "rector-fix": "tools/rector process src/ tests/",
"post-install-cmd": "tools/composer-git-hooks add --ignore-lock",
"post-update-cmd": "tools/composer-git-hooks update"
},
@@ -115,7 +128,9 @@
],
"pre-push": [
"tools/phpunit --testsuite=\"BigBlueButton unit test suite,BigBlueButton integration test suite\"",
- "tools/psalm --threads=1"
+ "tools/psalm --threads=1",
+ "tools/phpstan analyse",
+ "tools/rector process --dry-run src/ tests/"
],
"post-merge": "composer install",
"post-checkout": "composer install"
@@ -124,13 +139,14 @@
"brainmaestro/composer-git-hooks": "^2.8",
"extensions": {
"phpunit/phpunit": {
- "fakerphp/faker": "^1.14"
+ "fakerphp/faker": "1.20.*"
}
},
"friendsofphp/php-cs-fixer": "^3.3",
- "php-coveralls/php-coveralls": "^2.4",
- "phpunit/phpunit": "^8",
- "vimeo/psalm": "^4.22"
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^9",
+ "rector/rector": "^1.0",
+ "vimeo/psalm": "^5.23"
}
}
}
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 00000000..9110ad71
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,17 @@
+parameters:
+ paths:
+ - src
+ - tests
+ parallel:
+ maximumNumberOfProcesses: 4
+ level: 6
+ inferPrivatePropertyTypeFromConstructor: true
+ bootstrapFiles:
+ - tools/bootstrap.php
+ ignoreErrors:
+ -
+ message: '#^Offset ''input'' does not exist on array\{\}\.$#'
+ path: tests/integration/Http/Transport/CurlTransportTest.php
+ -
+ message: '#^Offset ''vars'' does not exist on array\{\}\.$#'
+ path: tests/integration/Http/Transport/CurlTransportTest.php
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 00000000..ccc8bc0e
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ ./src/
+
+
+
+
+ ./tests/unit/
+
+
+ ./tests/integration/
+
+
+ ./tests/functional/
+
+
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
deleted file mode 100644
index 627dd0e5..00000000
--- a/phpunit.xml.dist
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
- ./src/
-
-
-
-
-
- ./tests/unit/
-
-
- ./tests/integration/
-
-
- ./tests/functional/
-
-
-
-
diff --git a/rector.php b/rector.php
new file mode 100644
index 00000000..814ee5cf
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,34 @@
+withPaths([
+ __DIR__.'/src',
+ __DIR__.'/tests',
+ ])
+ ->withPhpSets()
+ ->withRules([
+ AddVoidReturnTypeWhereNoReturnRector::class,
+ DeclareStrictTypesRector::class,
+ FinalizeTestCaseClassRector::class,
+ RemoveUnusedVariableAssignRector::class,
+ RemoveUselessParamTagRector::class,
+ RemoveUselessReturnTagRector::class,
+ TypedPropertyFromAssignsRector::class,
+ TypedPropertyFromStrictConstructorRector::class,
+ TypedPropertyFromStrictSetUpRector::class,
+ ])
+ ->withImportNames(importShortClasses: false, removeUnusedImports: true)
+;
diff --git a/src/BigBlueButton.php b/src/BigBlueButton.php
index 402a9a2a..8e4431d0 100644
--- a/src/BigBlueButton.php
+++ b/src/BigBlueButton.php
@@ -1,4 +1,7 @@
securitySecret = $secret ?: getenv('BBB_SECURITY_SALT') ?: getenv('BBB_SECRET');
- $this->bbbServerBaseUrl = $baseUrl ?: getenv('BBB_SERVER_BASE_URL');
+ $securitySecret = $secret ?: getenv('BBB_SECURITY_SALT') ?: getenv('BBB_SECRET');
+
+ if (false === $securitySecret) {
+ // @codeCoverageIgnoreStart
+ @trigger_error(\sprintf('Constructing "%s" without passing a secret is deprecated since 6.0 and will throw an exception in 7.0.', self::class), \E_USER_DEPRECATED);
+ $this->securitySecret = ''; // previous behaviour
+ // @codeCoverageIgnoreEnd
+ } else {
+ $this->securitySecret = $securitySecret;
+ }
+
+ $bbbServerBaseUrl = $baseUrl ?: getenv('BBB_SERVER_BASE_URL');
+
+ if (false === $bbbServerBaseUrl) {
+ // @codeCoverageIgnoreStart
+ @trigger_error(\sprintf('Constructing "%s" without passing a server base URL is deprecated since 6.0 and will throw an exception in 7.0.', self::class), \E_USER_DEPRECATED);
+ $this->bbbServerBaseUrl = ''; // previous behaviour
+ // @codeCoverageIgnoreEnd
+ } else {
+ $this->bbbServerBaseUrl = $bbbServerBaseUrl;
+ }
if (empty($this->bbbServerBaseUrl)) {
throw new ConfigException('Base url required');
}
- $this->urlBuilder = new UrlBuilder($this->securitySecret, $this->bbbServerBaseUrl);
+ $this->urlBuilder = new UrlBuilder($this->securitySecret, $this->bbbServerBaseUrl, $this->hashingAlgorithm);
$this->transport = $transport ?? CurlTransport::createWithDefaultOptions();
}
@@ -162,7 +185,7 @@ public function isConnectionWorking(): bool
}
// HTTP exception or XML parse
- } catch (\Exception $e) {
+ } catch (\Exception) {
}
$this->connectionError = self::CONNECTION_ERROR_BASEURL;
@@ -199,7 +222,7 @@ public function getCreateMeetingUrl(CreateMeetingParameters $createMeetingParams
*/
public function createMeeting(CreateMeetingParameters $createMeetingParams): CreateMeetingResponse
{
- $xml = $this->processXmlResponse($this->getCreateMeetingUrl($createMeetingParams), $createMeetingParams->getPresentationsAsXML());
+ $xml = $this->processXmlResponse($this->getCreateMeetingUrl($createMeetingParams), $createMeetingParams->getModules());
return new CreateMeetingResponse($xml);
}
@@ -411,14 +434,14 @@ public function hooksCreate(HooksCreateParameters $hookCreateParams): HooksCreat
return new HooksCreateResponse($xml);
}
- public function getHooksListUrl(): string
+ public function getHooksListUrl(HooksListParameters $hooksListParameters): string
{
- return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_LIST);
+ return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_LIST, $hooksListParameters->getHTTPQuery());
}
- public function hooksList(): HooksListResponse
+ public function hooksList(HooksListParameters $hooksListParameters): HooksListResponse
{
- $xml = $this->processXmlResponse($this->getHooksListUrl());
+ $xml = $this->processXmlResponse($this->getHooksListUrl($hooksListParameters));
return new HooksListResponse($xml);
}
@@ -457,6 +480,23 @@ public function insertDocument(InsertDocumentParameters $insertDocumentParams):
return new InsertDocumentResponse($xml);
}
+ public function getSendChatMessageUrl(SendChatMessageParameters $sendChatMessageParams): string
+ {
+ return $this->urlBuilder->buildUrl(ApiMethod::SEND_CHAT_MESSAGE, $sendChatMessageParams->getHTTPQuery());
+ }
+
+ /**
+ * @throws NetworkException
+ * @throws ParsingException
+ * @throws RuntimeException
+ */
+ public function getSendChatMessage(SendChatMessageParameters $sendChatMessageParams): SendChatMessageResponse
+ {
+ $xml = $this->processXmlResponse($this->getSendChatMessageUrl($sendChatMessageParams));
+
+ return new SendChatMessageResponse($xml);
+ }
+
/* ____________________ SPECIAL METHODS ___________________ */
public function getJSessionId(): ?string
@@ -478,10 +518,10 @@ public function setJSessionId(string $jSessionId): void
* @throws ParsingException
* @throws RuntimeException
*/
- private function processXmlResponse(string $url, string $payload = '', string $contentType = 'application/xml'): SimpleXMLElement
+ private function processXmlResponse(string $url, string $payload = '', string $contentType = 'application/xml'): \SimpleXMLElement
{
try {
- return new SimpleXMLElement($this->requestUrl($url, $payload, $contentType));
+ return new \SimpleXMLElement($this->requestUrl($url, $payload, $contentType));
} catch (NetworkException|RuntimeException $e) {
throw $e;
} catch (\Throwable $e) {
diff --git a/src/Core/ApiMethod.php b/src/Core/ApiMethod.php
deleted file mode 100644
index ba4edf35..00000000
--- a/src/Core/ApiMethod.php
+++ /dev/null
@@ -1,42 +0,0 @@
-.
- */
-
-namespace BigBlueButton\Core;
-
-final class ApiMethod
-{
- public const CREATE = 'create';
- public const JOIN = 'join';
- public const ENTER = 'enter';
- public const END = 'end';
- public const IS_MEETING_RUNNING = 'isMeetingRunning';
- public const GET_MEETING_INFO = 'getMeetingInfo';
- public const GET_MEETINGS = 'getMeetings';
- public const SIGN_OUT = 'signOut';
- public const GET_RECORDINGS = 'getRecordings';
- public const PUBLISH_RECORDINGS = 'publishRecordings';
- public const DELETE_RECORDINGS = 'deleteRecordings';
- public const UPDATE_RECORDINGS = 'updateRecordings';
- public const GET_RECORDING_TEXT_TRACKS = 'getRecordingTextTracks';
- public const PUT_RECORDING_TEXT_TRACK = 'putRecordingTextTrack';
- public const HOOKS_CREATE = 'hooks/create';
- public const HOOKS_LIST = 'hooks/list';
- public const HOOKS_DESTROY = 'hooks/destroy';
- public const INSERT_DOCUMENT = 'insertDocument';
-}
diff --git a/src/Core/Attendee.php b/src/Core/Attendee.php
index b71b4d9d..1ef79b21 100644
--- a/src/Core/Attendee.php
+++ b/src/Core/Attendee.php
@@ -1,4 +1,7 @@
*/
+ private array $customData = [];
+
+ private readonly string $clientType;
public function __construct(\SimpleXMLElement $xml)
{
@@ -124,6 +101,7 @@ public function getClientType(): string
return $this->clientType;
}
+ /** @return array */
public function getCustomData(): array
{
return $this->customData;
diff --git a/src/Core/Hook.php b/src/Core/Hook.php
index 3c173dfe..5cda828c 100644
--- a/src/Core/Hook.php
+++ b/src/Core/Hook.php
@@ -1,5 +1,7 @@
rawXml = $xml;
- $this->hookId = (int) $xml->hookID->__toString();
- $this->callbackUrl = $xml->callbackURL->__toString();
- $this->meetingId = $xml->meetingID->__toString();
- $this->permanentHook = $xml->permanentHook->__toString() === 'true';
- $this->rawData = $xml->rawData->__toString() === 'true';
+ $this->hookId = (int) $this->rawXml->hookID->__toString();
+ $this->callbackUrl = $this->rawXml->callbackURL->__toString();
+ $this->meetingId = $this->rawXml->meetingID->__toString();
+ $this->permanentHook = $this->rawXml->permanentHook->__toString() === 'true';
+ $this->rawData = $this->rawXml->rawData->__toString() === 'true';
}
public function getHookId(): int
diff --git a/src/Core/ImagePreview.php b/src/Core/ImagePreview.php
index 737db8c7..f58d4421 100644
--- a/src/Core/ImagePreview.php
+++ b/src/Core/ImagePreview.php
@@ -23,24 +23,12 @@
class ImagePreview
{
- /** @var int */
- private $width;
-
- /** @var int */
- private $height;
-
- /** @var string */
- private $alt;
-
- /** @var string */
- private $url;
-
- public function __construct(int $width, int $height, string $alt, string $url)
- {
- $this->width = $width;
- $this->height = $height;
- $this->alt = $alt;
- $this->url = $url;
+ public function __construct(
+ private readonly int $width,
+ private readonly int $height,
+ private readonly string $alt,
+ private readonly string $url,
+ ) {
}
public function getWidth(): int
diff --git a/src/Core/Meeting.php b/src/Core/Meeting.php
index 3d1dbc64..84d24ded 100644
--- a/src/Core/Meeting.php
+++ b/src/Core/Meeting.php
@@ -1,5 +1,7 @@
|null */
+ private ?array $metas = null;
- /**
- * @var bool
- */
- private $isBreakout;
+ private readonly bool $isBreakout;
- public function __construct(\SimpleXMLElement $xml)
+ public function __construct(protected \SimpleXMLElement $rawXml)
{
- $this->rawXml = $xml;
- $this->meetingId = $xml->meetingID->__toString();
- $this->meetingName = $xml->meetingName->__toString();
- $this->creationTime = (float) $xml->createTime;
- $this->creationDate = $xml->createDate->__toString();
- $this->voiceBridge = (int) $xml->voiceBridge;
- $this->dialNumber = $xml->dialNumber->__toString();
- $this->attendeePassword = $xml->attendeePW->__toString();
- $this->moderatorPassword = $xml->moderatorPW->__toString();
- $this->hasBeenForciblyEnded = $xml->hasBeenForciblyEnded->__toString() === 'true';
- $this->isRunning = $xml->running->__toString() === 'true';
- $this->participantCount = (int) $xml->participantCount;
- $this->listenerCount = (int) $xml->listenerCount;
- $this->voiceParticipantCount = (int) $xml->voiceParticipantCount;
- $this->videoCount = (int) $xml->videoCount;
- $this->duration = (int) $xml->duration;
- $this->hasUserJoined = $xml->hasUserJoined->__toString() === 'true';
- $this->internalMeetingId = $xml->internalMeetingID->__toString();
- $this->isRecording = $xml->recording->__toString() === 'true';
- $this->startTime = (float) $xml->startTime;
- $this->endTime = (float) $xml->endTime;
- $this->maxUsers = (int) $xml->maxUsers->__toString();
- $this->moderatorCount = (int) $xml->moderatorCount->__toString();
- $this->isBreakout = $xml->isBreakout->__toString() === 'true';
+ $this->meetingId = $this->rawXml->meetingID->__toString();
+ $this->meetingName = $this->rawXml->meetingName->__toString();
+ $this->creationTime = (float) $this->rawXml->createTime;
+ $this->creationDate = $this->rawXml->createDate->__toString();
+ $this->voiceBridge = (int) $this->rawXml->voiceBridge;
+ $this->dialNumber = $this->rawXml->dialNumber->__toString();
+ $this->hasBeenForciblyEnded = $this->rawXml->hasBeenForciblyEnded->__toString() === 'true';
+ $this->isRunning = $this->rawXml->running->__toString() === 'true';
+ $this->participantCount = (int) $this->rawXml->participantCount;
+ $this->listenerCount = (int) $this->rawXml->listenerCount;
+ $this->voiceParticipantCount = (int) $this->rawXml->voiceParticipantCount;
+ $this->videoCount = (int) $this->rawXml->videoCount;
+ $this->duration = (int) $this->rawXml->duration;
+ $this->hasUserJoined = $this->rawXml->hasUserJoined->__toString() === 'true';
+ $this->internalMeetingId = $this->rawXml->internalMeetingID->__toString();
+ $this->parentMeetingID = $this->rawXml->parentMeetingID->__toString();
+ $this->isRecording = $this->rawXml->recording->__toString() === 'true';
+ $this->startTime = (float) $this->rawXml->startTime;
+ $this->endTime = (float) $this->rawXml->endTime;
+ $this->maxUsers = (int) $this->rawXml->maxUsers->__toString();
+ $this->moderatorCount = (int) $this->rawXml->moderatorCount->__toString();
+ $this->isBreakout = $this->rawXml->isBreakout->__toString() === 'true';
}
public function getMeetingId(): string
@@ -213,16 +136,6 @@ public function getDialNumber(): string
return $this->dialNumber;
}
- public function getAttendeePassword(): string
- {
- return $this->attendeePassword;
- }
-
- public function getModeratorPassword(): string
- {
- return $this->moderatorPassword;
- }
-
public function hasBeenForciblyEnded(): bool
{
return $this->hasBeenForciblyEnded;
@@ -268,6 +181,11 @@ public function getInternalMeetingId(): string
return $this->internalMeetingId;
}
+ public function getParentMeetingID(): string
+ {
+ return $this->parentMeetingID;
+ }
+
public function isRecording(): bool
{
return $this->isRecording;
@@ -317,9 +235,7 @@ public function getModerators(): array
{
$attendees = $this->getAttendees();
- $moderators = array_filter($attendees, function ($attendee) {
- return $attendee->getRole() === 'MODERATOR';
- });
+ $moderators = array_filter($attendees, static fn ($attendee) => $attendee->getRole() === Role::MODERATOR->value);
return array_values($moderators);
}
@@ -333,13 +249,12 @@ public function getViewers(): array
{
$attendees = $this->getAttendees();
- $viewers = array_filter($attendees, function ($attendee) {
- return $attendee->getRole() === 'VIEWER';
- });
+ $viewers = array_filter($attendees, static fn ($attendee) => $attendee->getRole() === Role::VIEWER->value);
return array_values($viewers);
}
+ /** @return array */
public function getMetas(): array
{
if ($this->metas === null) {
diff --git a/src/Core/PlaybackFormat.php b/src/Core/PlaybackFormat.php
index bf9cb728..ef1209e1 100644
--- a/src/Core/PlaybackFormat.php
+++ b/src/Core/PlaybackFormat.php
@@ -23,23 +23,18 @@
class PlaybackFormat
{
- /** @var string */
- private $type;
+ private readonly string $type;
- /** @var string */
- private $url;
+ private readonly string $url;
- /** @var int */
- private $processingTime;
+ private readonly int $processingTime;
- /** @var int */
- private $length;
+ private readonly int $length;
/** @var ImagePreview[] */
- private $imagePreviews;
+ private ?array $imagePreviews = null;
- /** @var \SimpleXMLElement */
- private $imagePreviewsRaw;
+ private readonly ?\SimpleXMLElement $imagePreviewsRaw;
public function __construct(\SimpleXMLElement $xml)
{
diff --git a/src/Core/Record.php b/src/Core/Record.php
index dfa15b92..c011bf57 100644
--- a/src/Core/Record.php
+++ b/src/Core/Record.php
@@ -1,4 +1,7 @@
*/
+ private array $metas = [];
/** @var PlaybackFormat[] */
- private $playbackFormats = [];
+ private array $playbackFormats = [];
public function __construct(\SimpleXMLElement $xml)
{
$this->recordId = $xml->recordID->__toString();
$this->meetingId = $xml->meetingID->__toString();
+ $this->internalMeetingId = $xml->internalMeetingID->__toString();
$this->name = $xml->name->__toString();
$this->isPublished = $xml->published->__toString() === 'true';
$this->state = $xml->state->__toString();
$this->startTime = (float) $xml->startTime->__toString();
$this->endTime = (float) $xml->endTime->__toString();
$this->participantCount = (int) $xml->participants->__toString();
- $this->playbackType = $xml->playback->format->type->__toString();
- $this->playbackUrl = $xml->playback->format->url->__toString();
- $this->playbackLength = (int) $xml->playback->format->length->__toString();
foreach ($xml->playback->children() as $format) {
$this->playbackFormats[] = new PlaybackFormat($format);
@@ -70,6 +73,11 @@ public function getMeetingId(): string
return $this->meetingId;
}
+ public function getInternalMeetingId(): string
+ {
+ return $this->internalMeetingId;
+ }
+
public function getName(): string
{
return $this->name;
@@ -100,6 +108,7 @@ public function getParticipantCount(): int
return $this->participantCount;
}
+ /** @return array */
public function getMetas(): array
{
return $this->metas;
diff --git a/src/Core/Track.php b/src/Core/Track.php
index e1807f56..7ef014ac 100644
--- a/src/Core/Track.php
+++ b/src/Core/Track.php
@@ -1,4 +1,7 @@
.
+ */
+
+namespace BigBlueButton\Enum;
+
+/**
+ * @psalm-immutable
+ */
+enum ApiMethod: string
+{
+ case CREATE = 'create';
+ case JOIN = 'join';
+ case ENTER = 'enter';
+ case END = 'end';
+ case IS_MEETING_RUNNING = 'isMeetingRunning';
+ case GET_MEETING_INFO = 'getMeetingInfo';
+ case GET_MEETINGS = 'getMeetings';
+ case SIGN_OUT = 'signOut';
+ case GET_RECORDINGS = 'getRecordings';
+ case PUBLISH_RECORDINGS = 'publishRecordings';
+ case DELETE_RECORDINGS = 'deleteRecordings';
+ case UPDATE_RECORDINGS = 'updateRecordings';
+ case GET_RECORDING_TEXT_TRACKS = 'getRecordingTextTracks';
+ case PUT_RECORDING_TEXT_TRACK = 'putRecordingTextTrack';
+ case HOOKS_CREATE = 'hooks/create';
+ case HOOKS_LIST = 'hooks/list';
+ case HOOKS_DESTROY = 'hooks/destroy';
+ case INSERT_DOCUMENT = 'insertDocument';
+ case SEND_CHAT_MESSAGE = 'sendChatMessage';
+}
diff --git a/src/Enum/Feature.php b/src/Enum/Feature.php
new file mode 100644
index 00000000..05be5571
--- /dev/null
+++ b/src/Enum/Feature.php
@@ -0,0 +1,65 @@
+.
+ */
+
+namespace BigBlueButton\Enum;
+
+/**
+ * @psalm-immutable
+ */
+enum Feature: string
+{
+ case BREAKOUT_ROOMS = 'breakoutRooms';
+ case CAPTIONS = 'captions';
+ case CHAT = 'chat';
+ case PRIVATE_CHAT = 'privateChat';
+ case DOWNLOAD_PRESENTATION_WITH_ANNOTATIONS = 'downloadPresentationWithAnnotations';
+ case EXTERNAL_VIDEOS = 'externalVideos';
+ case IMPORT_PRESENTATION_WITH_ANNOTATIONS_FROM_BREAKOUT_ROOMS = 'importPresentationWithAnnotationsFromBreakoutRooms';
+ case IMPORT_SHARED_NOTES_FROM_BREAKOUT_ROOMS = 'importSharedNotesFromBreakoutRooms';
+ case LAYOUTS = 'layouts';
+ case LEARNING_DASHBOARD = 'learningDashboard';
+ case LEARNING_DASHBOARD_DOWNLOAD_SESSION_DATA = 'learningDashboardDownloadSessionData';
+ case POLLS = 'polls';
+ case SCREENSHARE = 'screenshare';
+ case SHARED_NOTES = 'sharedNotes';
+ case VIRTUAL_BACKGROUNDS = 'virtualBackgrounds';
+ case CUSTOM_VIRTUAL_BACKGROUNDS = 'customVirtualBackgrounds';
+ case LIVE_TRANSCRIPTION = 'liveTranscription';
+ case PRESENTATION = 'presentation';
+ case CAMERA_AS_CONTENT = 'cameraAsContent';
+ case SNAPSHOT_OF_CURRENT_SLIDE = 'snapshotOfCurrentSlide';
+ case DOWNLOAD_PRESENTATION_ORIGINAL_FILE = 'downloadPresentationOriginalFile';
+ case DOWNLOAD_PRESENTATION_CONVERTED_TO_PDF = 'downloadPresentationConvertedToPdf';
+ case TIMER = 'timer';
+ case INFINITE_WHITEBOARD = 'infiniteWhiteboard';
+ case DELETE_CHAT_MESSAGE = 'deleteChatMessage';
+ case EDIT_CHAT_MESSAGE = 'editChatMessage';
+ case REPLY_CHAT_MESSAGE = 'replyChatMessage';
+ case CHAT_MESSAGE_REACTIONS = 'chatMessageReactions';
+ case RAISE_HAND = 'raiseHand';
+ /** @deprecated BC only. Use Feature::USER_REACTIONS instead. */
+ case USER_ACTIONS = 'userActions';
+ case USER_REACTIONS = 'userReactions';
+ case CHAT_EMOJI_PICKER = 'chatEmojiPicker';
+ case QUIZZES = 'quizzes';
+ case PLUGINS = 'plugins';
+}
diff --git a/src/Core/GuestPolicy.php b/src/Enum/GuestPolicy.php
similarity index 77%
rename from src/Core/GuestPolicy.php
rename to src/Enum/GuestPolicy.php
index a9177160..7dbba881 100644
--- a/src/Core/GuestPolicy.php
+++ b/src/Enum/GuestPolicy.php
@@ -20,12 +20,15 @@
* with BigBlueButton; if not, see .
*/
-namespace BigBlueButton\Core;
+namespace BigBlueButton\Enum;
-final class GuestPolicy
+/**
+ * @psalm-immutable
+ */
+enum GuestPolicy: string
{
- public const ALWAYS_ACCEPT = 'ALWAYS_ACCEPT';
- public const ALWAYS_DENY = 'ALWAYS_DENY';
- public const ASK_MODERATOR = 'ASK_MODERATOR';
- public const ALWAYS_ACCEPT_AUTH = 'ALWAYS_ACCEPT_AUTH';
+ case ALWAYS_ACCEPT = 'ALWAYS_ACCEPT';
+ case ALWAYS_DENY = 'ALWAYS_DENY';
+ case ASK_MODERATOR = 'ASK_MODERATOR';
+ case ALWAYS_ACCEPT_AUTH = 'ALWAYS_ACCEPT_AUTH';
}
diff --git a/src/Core/MeetingLayout.php b/src/Enum/HashingAlgorithm.php
similarity index 71%
rename from src/Core/MeetingLayout.php
rename to src/Enum/HashingAlgorithm.php
index 0f499913..a6bd8100 100644
--- a/src/Core/MeetingLayout.php
+++ b/src/Enum/HashingAlgorithm.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-/**
+/*
* BigBlueButton open source conferencing system - https://www.bigbluebutton.org/.
*
- * Copyright (c) 2016-2021 BigBlueButton Inc. and by respective authors (see below).
+ * Copyright (c) 2016-2023 BigBlueButton Inc. and by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -20,12 +20,15 @@
* with BigBlueButton; if not, see .
*/
-namespace BigBlueButton\Core;
+namespace BigBlueButton\Enum;
-final class MeetingLayout
+/**
+ * @psalm-immutable
+ */
+enum HashingAlgorithm: string
{
- public const CUSTOM_LAYOUT = 'CUSTOM_LAYOUT';
- public const SMART_LAYOUT = 'SMART_LAYOUT';
- public const PRESENTATION_FOCUS = 'PRESENTATION_FOCUS';
- public const VIDEO_FOCUS = 'VIDEO_FOCUS';
+ case SHA_1 = 'sha1';
+ case SHA_256 = 'sha256';
+ case SHA_512 = 'sha512';
+ case SHA_384 = 'sha384';
}
diff --git a/src/Enum/MeetingLayout.php b/src/Enum/MeetingLayout.php
new file mode 100644
index 00000000..b359459d
--- /dev/null
+++ b/src/Enum/MeetingLayout.php
@@ -0,0 +1,39 @@
+.
+ */
+
+namespace BigBlueButton\Enum;
+
+/**
+ * @psalm-immutable
+ */
+enum MeetingLayout: string
+{
+ case UNIFIED_LAYOUT = 'UNIFIED_LAYOUT';
+ case CUSTOM_LAYOUT = 'CUSTOM_LAYOUT';
+ case SMART_LAYOUT = 'SMART_LAYOUT';
+ case PRESENTATION_FOCUS = 'PRESENTATION_FOCUS';
+ case VIDEO_FOCUS = 'VIDEO_FOCUS';
+ case CAMERAS_ONLY = 'CAMERAS_ONLY';
+ case PARTICIPANTS_CHAT_ONLY = 'PARTICIPANTS_CHAT_ONLY';
+ case PRESENTATION_ONLY = 'PRESENTATION_ONLY';
+ case MEDIA_ONLY = 'MEDIA_ONLY';
+}
diff --git a/src/Enum/Role.php b/src/Enum/Role.php
new file mode 100644
index 00000000..4ac061ff
--- /dev/null
+++ b/src/Enum/Role.php
@@ -0,0 +1,32 @@
+.
+ */
+
+namespace BigBlueButton\Enum;
+
+/**
+ * @psalm-immutable
+ */
+enum Role: string
+{
+ case MODERATOR = 'MODERATOR';
+ case VIEWER = 'VIEWER';
+}
diff --git a/src/Exceptions/BaseException.php b/src/Exceptions/BaseException.php
index bd6e8576..68f42be0 100644
--- a/src/Exceptions/BaseException.php
+++ b/src/Exceptions/BaseException.php
@@ -21,11 +21,9 @@
namespace BigBlueButton\Exceptions;
-use Exception;
-
/**
* @abstract since 4.0.
*/
-class BaseException extends Exception
+class BaseException extends \Exception
{
}
diff --git a/src/Http/SetCookie.php b/src/Http/SetCookie.php
index b7854496..923ad56f 100644
--- a/src/Http/SetCookie.php
+++ b/src/Http/SetCookie.php
@@ -32,12 +32,10 @@
*
* @internal
*/
-final class SetCookie
+final class SetCookie implements \Stringable
{
- /**
- * @var array
- */
- private static $defaults = [
+ /** @var array */
+ private static array $defaults = [
'Name' => null,
'Value' => null,
'Domain' => null,
@@ -50,9 +48,9 @@ final class SetCookie
];
/**
- * @var array Cookie data
+ * @var array Cookie data
*/
- private $data;
+ private ?array $data;
/**
* Create a new SetCookie object from a string.
@@ -66,7 +64,7 @@ public static function fromString(string $cookie): self
// Explode the cookie string using a series of semicolons
$pieces = array_filter(array_map('trim', explode(';', $cookie)));
// The name of the cookie (first kvp) must exist and include an equal sign.
- if (!isset($pieces[0]) || strpos($pieces[0], '=') === false) {
+ if (!isset($pieces[0]) || !str_contains($pieces[0], '=')) {
return new self($data);
}
@@ -98,19 +96,11 @@ public static function fromString(string $cookie): self
}
/**
- * @param array $data Array of cookie data provided by a Cookie parser
+ * @param array $data Array of cookie data provided by a Cookie parser
*/
public function __construct(array $data = [])
{
- /** @var array|null $replaced will be null in case of replace error */
- $replaced = array_replace(self::$defaults, $data);
- // @codeCoverageIgnoreStart
- if ($replaced === null) {
- throw new \InvalidArgumentException('Unable to replace the default values for the Cookie.');
- }
- // @codeCoverageIgnoreEnd
-
- $this->data = $replaced;
+ $this->data = array_replace(self::$defaults, $data);
// Extract the Expires value and turn it into a UNIX timestamp if needed
if (!$this->getExpires() && $this->getMaxAge()) {
// Calculate the Expires date
@@ -120,13 +110,13 @@ public function __construct(array $data = [])
}
}
- public function __toString()
+ public function __toString(): string
{
$str = $this->data['Name'].'='.$this->data['Value'].'; ';
foreach ($this->data as $k => $v) {
if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
if ($k === 'Expires') {
- $str .= 'Expires='.gmdate('D, d M Y H:i:s \G\M\T', $v).'; ';
+ $str .= 'Expires='.gmdate('D, d M Y H:i:s \G\M\T', (int) $v).'; ';
} else {
$str .= ($v === true ? $k : "{$k}={$v}").'; ';
}
@@ -136,6 +126,7 @@ public function __toString()
return rtrim($str, '; ');
}
+ /** @return array */
public function toArray(): array
{
return $this->data;
@@ -216,7 +207,7 @@ public function setPath(string $path): void
*/
public function getMaxAge(): ?int
{
- return $this->data['Max-Age'] == null ? null : (int) $this->data['Max-Age'];
+ return $this->data['Max-Age'] === null ? null : (int) $this->data['Max-Age'];
}
/**
@@ -231,10 +222,8 @@ public function setMaxAge(int $maxAge): void
/**
* The UNIX timestamp when the cookie Expires.
- *
- * @return string|int|null
*/
- public function getExpires()
+ public function getExpires(): int|string|null
{
return $this->data['Expires'];
}
@@ -244,7 +233,7 @@ public function getExpires()
*
* @param int|string $timestamp unix timestamp or any English textual datetime description
*/
- public function setExpires($timestamp): void
+ public function setExpires(int|string $timestamp): void
{
$this->data['Expires'] = is_numeric($timestamp)
? (int) $timestamp
@@ -325,22 +314,22 @@ public function matchesPath(string $requestPath): bool
$cookiePath = $this->getPath();
// Match on exact matches or when path is the default empty "/"
- if ($cookiePath === '/' || $cookiePath == $requestPath) {
+ if ($cookiePath === '/' || $cookiePath === $requestPath) {
return true;
}
// Ensure that the cookie-path is a prefix of the request path.
- if (0 !== strpos($requestPath, $cookiePath)) {
+ if (!str_starts_with($requestPath, $cookiePath)) {
return false;
}
// Match if the last character of the cookie-path is "/"
- if (substr($cookiePath, -1, 1) === '/') {
+ if (str_ends_with($cookiePath, '/')) {
return true;
}
// Match if the first character not included in cookie path is "/"
- return substr($requestPath, \strlen($cookiePath), 1) === '/';
+ return $requestPath[\strlen($cookiePath)] === '/';
}
/**
@@ -386,7 +375,7 @@ public function isExpired(): bool
*
* @return bool|string Returns true if valid or an error message if invalid
*/
- public function validate()
+ public function validate(): bool|string
{
$name = $this->getName();
if ($name === '') {
diff --git a/src/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransport.php b/src/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransport.php
index a8b10278..befa70d9 100644
--- a/src/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransport.php
+++ b/src/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransport.php
@@ -34,7 +34,7 @@
// @codeCoverageIgnoreStart
if (!interface_exists(ClientInterface::class)) {
- throw new \LogicException(sprintf(
+ throw new \LogicException(\sprintf(
'The "%s" interface was not found. '.
'You cannot use "%s" without it.'.
'Try running "composer require" for a package which provides psr/http-client-implementation.',
@@ -44,7 +44,7 @@
}
if (!interface_exists(RequestFactoryInterface::class)) {
- throw new \LogicException(sprintf(
+ throw new \LogicException(\sprintf(
'The "%s" interface was not found. '.
'You cannot use "%s" without it.'.
'Try running "composer require" for a package which provides psr/http-factory-implementation.',
@@ -54,7 +54,7 @@
}
if (!interface_exists(StreamFactoryInterface::class)) {
- throw new \LogicException(sprintf(
+ throw new \LogicException(\sprintf(
'The "%s" interface was not found. '.
'You cannot use "%s" without it.'.
'Try running "composer require" for a package which provides psr/http-factory-implementation.',
@@ -69,44 +69,13 @@
*/
final class PsrHttpClientTransport implements TransportInterface
{
- /**
- * @var ClientInterface
- */
- private $httpClient;
-
- /**
- * @var RequestFactoryInterface
- */
- private $requestFactory;
-
- /**
- * @var StreamFactoryInterface
- */
- private $streamFactory;
-
- /**
- * @var string[]
- */
- private $defaultHeaders;
-
/**
* @param string[] $defaultHeaders additional headers to pass on each request
*/
- public function __construct(
- ClientInterface $httpClient,
- RequestFactoryInterface $requestFactory,
- StreamFactoryInterface $streamFactory,
- array $defaultHeaders = []
- ) {
- $this->httpClient = $httpClient;
- $this->requestFactory = $requestFactory;
- $this->streamFactory = $streamFactory;
- $this->defaultHeaders = $defaultHeaders;
+ public function __construct(private readonly ClientInterface $httpClient, private readonly RequestFactoryInterface $requestFactory, private readonly StreamFactoryInterface $streamFactory, private readonly array $defaultHeaders = [])
+ {
}
- /**
- * {@inheritDoc}
- */
public function request(TransportRequest $request): TransportResponse
{
if ('' !== $payload = $request->getPayload()) {
@@ -124,7 +93,7 @@ public function request(TransportRequest $request): TransportResponse
try {
$psrResponse = $this->httpClient->sendRequest($psrRequest);
} catch (ClientExceptionInterface $e) {
- throw new RuntimeException(sprintf('HTTP request failed: %s', $e->getMessage()), 0, $e);
+ throw new RuntimeException(\sprintf('HTTP request failed: %s', $e->getMessage()), 0, $e);
}
if ($psrResponse->getStatusCode() < 200 || $psrResponse->getStatusCode() >= 300) {
diff --git a/src/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransport.php b/src/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransport.php
index 943ac80e..0545c74d 100644
--- a/src/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransport.php
+++ b/src/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransport.php
@@ -38,7 +38,7 @@
// @codeCoverageIgnoreStart
if (!interface_exists(HttpClientInterface::class)) {
- throw new \LogicException(sprintf(
+ throw new \LogicException(\sprintf(
'The "%s" interface was not found. '.
'You cannot use "%s" without it.'.
'Try running "composer require" for a package which provides symfony/http-client-implementation.',
@@ -53,30 +53,12 @@
*/
final class SymfonyHttpClientTransport implements TransportInterface
{
- /**
- * @var HttpClientInterface
- */
- private $httpClient;
-
- /**
- * @var string[]
- */
- private $defaultHeaders;
-
- /**
- * @var mixed[]
- */
- private $defaultOptions;
-
/**
* @param string[] $defaultHeaders additional HTTP headers to pass on each request
* @param mixed[] $defaultOptions Options for Symfony HTTP client passed on every request. See {@link https://symfony.com/doc/current/http_client.html} for details.
*/
- public function __construct(HttpClientInterface $httpClient, array $defaultHeaders = [], array $defaultOptions = [])
+ public function __construct(private readonly HttpClientInterface $httpClient, private readonly array $defaultHeaders = [], private readonly array $defaultOptions = [])
{
- $this->httpClient = $httpClient;
- $this->defaultHeaders = $defaultHeaders;
- $this->defaultOptions = $defaultOptions;
}
/**
@@ -89,7 +71,7 @@ public static function create(array $defaultHeaders = [], array $defaultOptions
{
// @codeCoverageIgnoreStart
if (!class_exists(HttpClient::class)) {
- throw new \LogicException(sprintf(
+ throw new \LogicException(\sprintf(
'Cannot create an instance of "%s" when Symfony HttpClient is not installed. '.
'Either instantiate the class by yourself and pass a proper implementation or '.
'try to run "composer require symfony/http-client".',
@@ -101,9 +83,6 @@ public static function create(array $defaultHeaders = [], array $defaultOptions
// @codeCoverageIgnoreEnd
}
- /**
- * {@inheritDoc}
- */
public function request(TransportRequest $request): TransportResponse
{
$headers = $this->defaultHeaders;
@@ -134,7 +113,7 @@ public function request(TransportRequest $request): TransportResponse
return new TransportResponse($symfonyResponse->getContent(), self::extractJsessionCookie($symfonyResponse));
} catch (TransportExceptionInterface $e) {
- throw new RuntimeException(sprintf('HTTP request failed: %s', $e->getMessage()), 0, $e);
+ throw new RuntimeException(\sprintf('HTTP request failed: %s', $e->getMessage()), 0, $e);
} catch (ClientExceptionInterface|RedirectionExceptionInterface|ServerExceptionInterface $e) {
throw new NetworkException('Bad response.', $e->getCode(), $e);
}
diff --git a/src/Http/Transport/CurlTransport.php b/src/Http/Transport/CurlTransport.php
index 40d0b7eb..8f537677 100644
--- a/src/Http/Transport/CurlTransport.php
+++ b/src/Http/Transport/CurlTransport.php
@@ -55,11 +55,6 @@ final class CurlTransport implements TransportInterface
*/
private const DEFAULT_TIMEOUT = 30;
- /**
- * @var mixed[]
- */
- private $curlOptions;
-
/**
* Allows to inject custom cURL options used on dispatching request to BBB.
* Please note that you must ensure on your own that the usage of custom options does not break the transport.
@@ -69,9 +64,8 @@ final class CurlTransport implements TransportInterface
*
* @param mixed[] $curlOptions A list of cURL options to pass to the cURL handle. Option name as key, option value as value.
*/
- public function __construct(array $curlOptions = [])
+ public function __construct(private readonly array $curlOptions = [])
{
- $this->curlOptions = $curlOptions;
}
/**
@@ -84,9 +78,6 @@ public static function createWithDefaultOptions(array $additionalCurlOptions = [
// @codeCoverageIgnoreEnd
}
- /**
- * {@inheritDoc}
- */
public function request(TransportRequest $request): TransportResponse
{
// @codeCoverageIgnoreStart
@@ -98,7 +89,7 @@ public function request(TransportRequest $request): TransportResponse
$ch = curl_init();
// @codeCoverageIgnoreStart
if (!$ch) {
- throw new RuntimeException('Could not create curl instance. Error: '.curl_error($ch));
+ throw new RuntimeException('Could not create curl instance.');
}
// @codeCoverageIgnoreEnd
@@ -130,6 +121,7 @@ public function request(TransportRequest $request): TransportResponse
return new TransportResponse($data, $sessionId);
}
+ /** @return array */
private static function buildPostOptions(TransportRequest $request): array
{
$options = [];
@@ -140,13 +132,14 @@ private static function buildPostOptions(TransportRequest $request): array
$options[\CURLOPT_POSTFIELDS] = $payload;
$options[\CURLOPT_HTTPHEADER] = [
'Content-type: '.$request->getContentType(),
- 'Content-length: '.mb_strlen($payload),
+ 'Content-length: '.mb_strlen((string) $payload),
];
}
return $options;
}
+ /** @return array */
private static function buildUrlOptions(TransportRequest $request): array
{
return [
@@ -160,6 +153,8 @@ private static function buildUrlOptions(TransportRequest $request): array
* The CURLOPT_HTTPHEADER will be treated in a special
* way and merged instead, but on values with same header name
* only the header from the first option set will be preserved.
+ *
+ * @return array
*/
private static function mergeCurlOptions(array ...$options): array
{
@@ -186,26 +181,16 @@ private static function mergeCurlOptions(array ...$options): array
/**
* A raw response as returned from cURL will contain the headers followed by "\r\n\r\n" and the content.
*
- * @param \CurlHandle|resource $curlHandle
+ * @return (string|string[][])[] First key headers, second key is content
+ *
+ * @see https://stackoverflow.com/questions/10589889/returning-header-as-array-using-curl
*
- * @return array{0: string, 1: string[]} First key headers, second key is content
+ * @psalm-return array{0: array>, 1: string}
*
* @throws NetworkException
- *
- * @see https://stackoverflow.com/questions/10589889/returning-header-as-array-using-curl
*/
- private static function getHeadersAndContentFromCurlHandle($curlHandle): array
+ private static function getHeadersAndContentFromCurlHandle(\CurlHandle $curlHandle): array
{
- /* @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
- // @codeCoverageIgnoreStart
- if (\PHP_VERSION_ID >= 80000 && !$curlHandle instanceof \CurlHandle) {
- /* @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
- throw new \InvalidArgumentException(sprintf('$curlHandle must be "%s". "%s" given.', \CurlHandle::class, get_debug_type($curlHandle)));
- } elseif (\PHP_VERSION_ID < 80000 && !\is_resource($curlHandle)) {
- throw new \InvalidArgumentException(sprintf('$curlHandle must be resource. "%s" given.', \is_object($curlHandle) ? \get_class($curlHandle) : \gettype($curlHandle)));
- }
- // @codeCoverageIgnoreEnd
-
$headers = [];
curl_setopt($curlHandle, \CURLOPT_HEADER, 1);
@@ -234,7 +219,7 @@ private static function getHeadersAndContentFromCurlHandle($curlHandle): array
$splitHeader = explode(': ', $line, 2);
// @codeCoverageIgnoreStart
if (!isset($splitHeader[0], $splitHeader[1])) {
- throw new \InvalidArgumentException(sprintf('Header value "%s" is invalid. Expected format is "Header-Name: value".', $line));
+ throw new \InvalidArgumentException(\sprintf('Header value "%s" is invalid. Expected format is "Header-Name: value".', $line));
}
// @codeCoverageIgnoreEnd
diff --git a/src/Http/Transport/Header.php b/src/Http/Transport/Header.php
index 1a38bf2a..ea339ee2 100644
--- a/src/Http/Transport/Header.php
+++ b/src/Http/Transport/Header.php
@@ -43,15 +43,15 @@ public static function mergeCurlHeaders(array ...$headers): array
foreach ($headers as $headerSet) {
foreach ($headerSet as $header) {
if (!\is_string($header)) {
- throw new \InvalidArgumentException(sprintf(
+ throw new \InvalidArgumentException(\sprintf(
'Non-string header with type "%s" passed.',
- \is_object($header) ? \get_class($header) : \gettype($header)
+ get_debug_type($header)
));
}
$splitHeader = explode(': ', $header, 2);
if (!isset($splitHeader[0], $splitHeader[1])) {
- throw new \InvalidArgumentException(sprintf('Header value "%s" is invalid. Expected format is "Header-Name: value".', $header));
+ throw new \InvalidArgumentException(\sprintf('Header value "%s" is invalid. Expected format is "Header-Name: value".', $header));
}
// Enforce lower case for header names to avoid duplicates in mixed case. The case of header names should
@@ -62,7 +62,7 @@ public static function mergeCurlHeaders(array ...$headers): array
$result = [];
foreach ($mergedHeaders as $header => $value) {
- $result[] = sprintf('%s: %s', $header, $value);
+ $result[] = \sprintf('%s: %s', $header, $value);
}
return $result;
diff --git a/src/Http/Transport/TransportRequest.php b/src/Http/Transport/TransportRequest.php
index 0217f1ef..b1ae3ced 100644
--- a/src/Http/Transport/TransportRequest.php
+++ b/src/Http/Transport/TransportRequest.php
@@ -26,26 +26,8 @@
*/
class TransportRequest
{
- /**
- * @var string
- */
- private $url;
-
- /**
- * @var string
- */
- private $payload;
-
- /**
- * @var string
- */
- private $contentType;
-
- public function __construct(string $url, string $payload, string $contentType)
+ public function __construct(private readonly string $url, private readonly string $payload, private readonly string $contentType)
{
- $this->url = $url;
- $this->payload = $payload;
- $this->contentType = $contentType;
}
public function getUrl(): string
diff --git a/src/Http/Transport/TransportResponse.php b/src/Http/Transport/TransportResponse.php
index 650961c0..42a97dd3 100644
--- a/src/Http/Transport/TransportResponse.php
+++ b/src/Http/Transport/TransportResponse.php
@@ -26,20 +26,8 @@
*/
class TransportResponse
{
- /**
- * @var string
- */
- private $body;
-
- /**
- * @var string|null
- */
- private $sessionId;
-
- public function __construct(string $body, ?string $sessionId)
+ public function __construct(private readonly string $body, private readonly ?string $sessionId)
{
- $this->body = $body;
- $this->sessionId = $sessionId;
}
public function getBody(): string
diff --git a/src/Parameters/BaseParameters.php b/src/Parameters/BaseParameters.php
index f87e95c5..6bf144f2 100644
--- a/src/Parameters/BaseParameters.php
+++ b/src/Parameters/BaseParameters.php
@@ -1,4 +1,7 @@
*/
+ protected array $ignoreProperties = [];
/**
+ * @param array $arguments
+ *
* @return $this|bool|mixed|null
*/
public function __call(string $name, array $arguments)
@@ -34,27 +40,28 @@ public function __call(string $name, array $arguments)
if (!preg_match('/^(get|is|set)[A-Z]/', $name)) {
throw new \BadFunctionCallException($name.' does not exist');
}
- if (strpos($name, 'get') === 0) {
+ if (str_starts_with($name, 'get')) {
return $this->getter(lcfirst(substr($name, 3)));
- } elseif (strpos($name, 'is') === 0) {
+ }
+
+ if (str_starts_with($name, 'is')) {
return $this->booleanGetter(lcfirst(substr($name, 2)));
- } elseif (strpos($name, 'set') === 0) {
+ }
+
+ if (str_starts_with($name, 'set')) {
return $this->setter(lcfirst(substr($name, 3)), $arguments);
}
return null;
}
- /**
- * @return mixed
- */
- protected function getter(string $name)
+ protected function getter(string $name): mixed
{
if (property_exists($this, $name)) {
return $this->$name;
- } else {
- throw new \BadFunctionCallException($name.' is not a valid property');
}
+
+ throw new \BadFunctionCallException($name.' is not a valid property');
}
protected function booleanGetter(string $name): ?bool
@@ -68,36 +75,51 @@ protected function booleanGetter(string $name): ?bool
return $value;
}
- protected function setter(string $name, array $arguments): self
+ /** @param array $arguments */
+ protected function setter(string $name, array $arguments): static
{
if (!property_exists($this, $name)) {
throw new \BadFunctionCallException($name.' is not a valid property');
}
+ $property = new \ReflectionProperty($this, $name);
+ $type = $property->getType();
+
+ // Construct enum on demand
+ if ($type instanceof \ReflectionNamedType && enum_exists($type->getName()) && !\is_object($arguments[0])) {
+ /* @phpstan-ignore-next-line */
+ $arguments[0] = ($type->getName())::from($arguments[0]);
+ }
$this->$name = $arguments[0];
return $this;
}
+ /** @return array */
protected function getProperties(): array
{
- return array_filter(get_object_vars($this), function ($name) {
- return $name !== 'ignoreProperties' && !\in_array($name, $this->ignoreProperties);
- }, \ARRAY_FILTER_USE_KEY);
+ return array_filter(get_object_vars($this), fn ($name) => $name !== 'ignoreProperties' && !\in_array(
+ $name,
+ $this->ignoreProperties,
+ true
+ ), \ARRAY_FILTER_USE_KEY);
}
+ /** @return array */
protected function getHTTPQueryArray(): array
{
$properties = $this->getProperties();
- $properties = array_filter($properties, function ($value) {
- return $value !== null;
- });
+ $properties = array_filter($properties, static fn ($value) => $value !== null);
- return array_map(function ($value) {
+ return array_map(static function ($value) {
if (\is_bool($value)) {
return $value ? 'true' : 'false';
}
+ if ($value instanceof \BackedEnum) {
+ $value = $value->value;
+ }
+
return $value;
}, $properties);
}
diff --git a/src/Parameters/CreateMeetingParameters.php b/src/Parameters/CreateMeetingParameters.php
index 0afa4b0d..8e00d7ae 100644
--- a/src/Parameters/CreateMeetingParameters.php
+++ b/src/Parameters/CreateMeetingParameters.php
@@ -1,4 +1,7 @@
}>
+ */
+ private array $breakoutRoomsGroups = [];
+
+ /**
+ * @var array
+ */
+ protected array $disabledFeatures = [];
+
+ /**
+ * @var array
+ */
+ protected array $disabledFeaturesExclude = [];
+
+ protected ?int $meetingCameraCap = null;
+ protected ?int $meetingExpireIfNoUserJoinedInMinutes = null;
+ protected ?int $meetingExpireWhenLastUserLeftInMinutes = null;
+ protected ?bool $preUploadedPresentationOverrideDefault = null;
+ protected ?string $preUploadedPresentation = null;
+ protected ?string $preUploadedPresentationName = null;
+ protected ?bool $notifyRecordingIsOn = null;
+ protected ?bool $remindRecordingIsOn = null;
+ protected ?bool $recordFullDurationMedia = null;
+ protected ?string $presentationUploadExternalUrl = null;
+ protected ?string $presentationUploadExternalDescription = null;
+ protected ?int $maxNumPages = null;
+ protected ?string $pluginManifests = null;
+ protected ?string $pluginManifestsFetchUrl = null;
+ protected ?bool $presentationConversionCacheEnabled = null;
+ protected ?bool $allowOverrideClientSettingsOnCreateCall = null;
+ protected ?string $clientSettingsOverride = null;
+
+ /**
+ * @var array
+ */
+ private array $presentations = [];
+
+ public function __construct(protected string $meetingID, protected string $name)
{
- $this->meetingID = $meetingID;
- $this->name = $name;
+ $this->guestPolicy = GuestPolicy::ALWAYS_ACCEPT;
+
+ $this->ignoreProperties = ['disabledFeatures', 'disabledFeaturesExclude', 'clientSettingsOverride'];
}
public function setEndCallbackUrl(string $endCallbackUrl): self
@@ -487,25 +362,69 @@ public function addPresentation(string $nameOrUrl, ?string $content = null, ?str
return $this;
}
- public function getPresentations(): array
+ /**
+ * @return array}>
+ */
+ public function getBreakoutRoomsGroups(): array
{
- return $this->presentations;
+ return $this->breakoutRoomsGroups;
}
/**
- * @return mixed
+ * @param array $roster
+ *
+ * @return $this
*/
- public function getPresentationsAsXML()
+ public function addBreakoutRoomsGroup(string $id, ?string $name, array $roster): self
{
- $result = '';
+ $this->breakoutRoomsGroups[] = ['id' => $id, 'name' => $name, 'roster' => $roster];
+
+ return $this;
+ }
+ /** @return array */
+ public function getPresentations(): array
+ {
+ return $this->presentations;
+ }
+
+ public function getModules(): string
+ {
+ $xml = new SimpleXMLElementExtended('');
+ // Get empty xml as string
+ $emptyXML = $xml->asXML();
+
+ // Add modules
+ $this->addPresentationsModule($xml);
+ $this->addClientSettingsOverrideModule($xml);
+
+ // Get xml as string after modules have been added
+ $resultXML = $xml->asXML();
+
+ // If xml was not modified (no modules added), return an empty string
+ if ($emptyXML === $resultXML) {
+ return '';
+ }
+
+ return $resultXML;
+ }
+
+ public function addClientSettingsOverrideModule(SimpleXMLElementExtended $xml): void
+ {
+ if (!empty($this->clientSettingsOverride)) {
+ $module = $xml->addChildWithCData('module', $this->clientSettingsOverride);
+ $module->addAttribute('name', 'clientSettingsOverride');
+ }
+ }
+
+ public function addPresentationsModule(SimpleXMLElementExtended $xml): void
+ {
if (!empty($this->presentations)) {
- $xml = new \SimpleXMLElement('');
$module = $xml->addChild('module');
$module->addAttribute('name', 'presentation');
foreach ($this->presentations as $nameOrUrl => $content) {
- if (strpos($nameOrUrl, 'http') === 0) {
+ if (str_starts_with($nameOrUrl, 'http')) {
$presentation = $module->addChild('document');
$presentation->addAttribute('url', $nameOrUrl);
if (\is_string($content)) {
@@ -514,22 +433,41 @@ public function getPresentationsAsXML()
} else {
$document = $module->addChild('document');
$document->addAttribute('name', $nameOrUrl);
+ /* @phpstan-ignore-next-line */
$document[0] = $content;
}
}
- $result = $xml->asXML();
}
-
- return $result;
}
public function getHTTPQuery(): string
{
$queries = $this->getHTTPQueryArray();
+ // Add disabled features if any are set
+ if (!empty($this->disabledFeatures)) {
+ $queries = array_merge($queries, [
+ 'disabledFeatures' => implode(',', array_map(static fn (Feature $disabledFeature): string => $disabledFeature->value, $this->disabledFeatures)),
+ ]);
+ }
+
+ // Add disabled features exclude if any are set
+ if (!empty($this->disabledFeaturesExclude)) {
+ $queries = array_merge($queries, [
+ 'disabledFeaturesExclude' => implode(',', array_map(static fn (Feature $disabledFeatureExclude): string => $disabledFeatureExclude->value, $this->disabledFeaturesExclude)),
+ ]);
+ }
+
+ // Pre-defined groups to automatically assign the students to a given breakout room
+ if (!empty($this->breakoutRoomsGroups)) {
+ $queries = array_merge($queries, [
+ 'groups' => json_encode($this->breakoutRoomsGroups),
+ ]);
+ }
+
if ($this->isBreakout()) {
if ($this->parentMeetingID === null || $this->sequence === null) {
- trigger_error('Breakout rooms require a parentMeetingID and sequence number.', \E_USER_WARNING);
+ throw new \RuntimeException('Breakout rooms require a parentMeetingID and sequence number.');
}
} else {
$queries = $this->filterBreakoutRelatedQueries($queries);
@@ -538,10 +476,13 @@ public function getHTTPQuery(): string
return http_build_query($queries, '', '&', \PHP_QUERY_RFC3986);
}
+ /**
+ * @param array $queries
+ *
+ * @return array
+ */
private function filterBreakoutRelatedQueries(array $queries): array
{
- return array_filter($queries, function ($query) {
- return !\in_array($query, ['isBreakout', 'parentMeetingID', 'sequence', 'freeJoin']);
- });
+ return array_filter($queries, static fn ($query) => !\in_array($query, ['isBreakout', 'parentMeetingID', 'sequence', 'freeJoin']));
}
}
diff --git a/src/Parameters/DeleteRecordingsParameters.php b/src/Parameters/DeleteRecordingsParameters.php
index f5d46b8a..3754105d 100644
--- a/src/Parameters/DeleteRecordingsParameters.php
+++ b/src/Parameters/DeleteRecordingsParameters.php
@@ -1,4 +1,7 @@
recordID = $recordID;
}
}
diff --git a/src/Parameters/EndMeetingParameters.php b/src/Parameters/EndMeetingParameters.php
index 82b19f31..918f5c81 100644
--- a/src/Parameters/EndMeetingParameters.php
+++ b/src/Parameters/EndMeetingParameters.php
@@ -1,4 +1,7 @@
password = $password;
- $this->meetingID = $meetingID;
}
}
diff --git a/src/Parameters/GetMeetingInfoParameters.php b/src/Parameters/GetMeetingInfoParameters.php
index c6fe1a18..c11e1b2e 100644
--- a/src/Parameters/GetMeetingInfoParameters.php
+++ b/src/Parameters/GetMeetingInfoParameters.php
@@ -1,4 +1,7 @@
meetingID = $meetingID;
}
}
diff --git a/src/Parameters/GetRecordingTextTracksParameters.php b/src/Parameters/GetRecordingTextTracksParameters.php
index c7c0443b..59cbf83b 100644
--- a/src/Parameters/GetRecordingTextTracksParameters.php
+++ b/src/Parameters/GetRecordingTextTracksParameters.php
@@ -1,4 +1,7 @@
recordID = $recordID;
}
}
diff --git a/src/Parameters/GetRecordingsParameters.php b/src/Parameters/GetRecordingsParameters.php
index 745ee36b..38cb842c 100644
--- a/src/Parameters/GetRecordingsParameters.php
+++ b/src/Parameters/GetRecordingsParameters.php
@@ -1,4 +1,7 @@
callbackURL = $callbackURL;
}
}
diff --git a/src/Parameters/HooksDestroyParameters.php b/src/Parameters/HooksDestroyParameters.php
index c22e953c..f1134de9 100644
--- a/src/Parameters/HooksDestroyParameters.php
+++ b/src/Parameters/HooksDestroyParameters.php
@@ -1,4 +1,7 @@
hookID = $hookID;
}
}
diff --git a/src/Parameters/HooksListParameters.php b/src/Parameters/HooksListParameters.php
new file mode 100644
index 00000000..0df6305c
--- /dev/null
+++ b/src/Parameters/HooksListParameters.php
@@ -0,0 +1,34 @@
+.
+ */
+
+namespace BigBlueButton\Parameters;
+
+/**
+ * Class HooksListParameters.
+ *
+ * @method string getMeetingID()
+ * @method $this setMeetingID(string $id)
+ */
+final class HooksListParameters extends MetaParameters
+{
+ protected ?string $meetingID = null;
+}
diff --git a/src/Parameters/InsertDocumentParameters.php b/src/Parameters/InsertDocumentParameters.php
index 3542dd9b..538266e6 100644
--- a/src/Parameters/InsertDocumentParameters.php
+++ b/src/Parameters/InsertDocumentParameters.php
@@ -27,19 +27,11 @@
*/
final class InsertDocumentParameters extends MetaParameters
{
- /**
- * @var string
- */
- protected $meetingID;
+ /** @var array */
+ private array $presentations = [];
- /**
- * @var array
- */
- private $presentations = [];
-
- public function __construct(string $meetingID)
+ public function __construct(protected string $meetingID)
{
- $this->meetingID = $meetingID;
}
public function addPresentation(string $url, string $filename, ?bool $downloadable = null, ?bool $removable = null): self
@@ -60,10 +52,7 @@ public function removePresentation(string $url): self
return $this;
}
- /**
- * @return mixed
- */
- public function getPresentationsAsXML()
+ public function getPresentationsAsXML(): string|false
{
$result = '';
diff --git a/src/Parameters/IsMeetingRunningParameters.php b/src/Parameters/IsMeetingRunningParameters.php
index 9c87923c..9244f666 100644
--- a/src/Parameters/IsMeetingRunningParameters.php
+++ b/src/Parameters/IsMeetingRunningParameters.php
@@ -1,4 +1,7 @@
meetingID = $meetingID;
}
}
diff --git a/src/Parameters/JoinMeetingParameters.php b/src/Parameters/JoinMeetingParameters.php
index 4a9dbc4a..a95eb384 100644
--- a/src/Parameters/JoinMeetingParameters.php
+++ b/src/Parameters/JoinMeetingParameters.php
@@ -1,4 +1,7 @@
meetingID = $meetingID;
- $this->fullName = $fullName;
- $this->password = $password;
}
}
diff --git a/src/Parameters/MetaParameters.php b/src/Parameters/MetaParameters.php
index 50ae4910..2adab816 100644
--- a/src/Parameters/MetaParameters.php
+++ b/src/Parameters/MetaParameters.php
@@ -1,4 +1,7 @@
*/
+ private array $meta = [];
- /**
- * @return string|bool
- */
- public function getMeta(string $key)
+ public function getMeta(string $key): string|bool
{
return $this->meta[$key];
}
- /**
- * @param string|bool $value
- */
- public function addMeta(string $key, $value): self
+ public function addMeta(string $key, bool|string $value): static
{
$this->meta[$key] = $value;
diff --git a/src/Parameters/PublishRecordingsParameters.php b/src/Parameters/PublishRecordingsParameters.php
index d003b2ba..fd73ef0d 100644
--- a/src/Parameters/PublishRecordingsParameters.php
+++ b/src/Parameters/PublishRecordingsParameters.php
@@ -1,4 +1,7 @@
recordID = $recordID;
- $this->publish = $publish;
}
}
diff --git a/src/Parameters/PutRecordingTextTrackParameters.php b/src/Parameters/PutRecordingTextTrackParameters.php
index 728ac032..7969bcbc 100644
--- a/src/Parameters/PutRecordingTextTrackParameters.php
+++ b/src/Parameters/PutRecordingTextTrackParameters.php
@@ -1,4 +1,7 @@
ignoreProperties = ['contentType', 'file'];
-
- $this->recordID = $recordID;
- $this->kind = $kind;
- $this->lang = $lang;
- $this->label = $label;
}
}
diff --git a/src/Parameters/SendChatMessageParameters.php b/src/Parameters/SendChatMessageParameters.php
new file mode 100644
index 00000000..3fb30f97
--- /dev/null
+++ b/src/Parameters/SendChatMessageParameters.php
@@ -0,0 +1,39 @@
+.
+ */
+
+namespace BigBlueButton\Parameters;
+
+/**
+ * Class SendChatMessageParameters.
+ *
+ * @method string getMeetingID()
+ * @method $this setMeetingID(string $id)
+ * @method string getMessage()
+ * @method $this setMessage(string $message)
+ * @method string|null getUserName()
+ * @method $this setUserName(string $userName)
+ */
+final class SendChatMessageParameters extends BaseParameters
+{
+ public function __construct(protected string $meetingID, protected string $message, protected ?string $userName = null)
+ {
+ }
+}
diff --git a/src/Parameters/UpdateRecordingsParameters.php b/src/Parameters/UpdateRecordingsParameters.php
index 65c8ec47..1dc2f2a6 100644
--- a/src/Parameters/UpdateRecordingsParameters.php
+++ b/src/Parameters/UpdateRecordingsParameters.php
@@ -1,4 +1,7 @@
recordID = $recordID;
}
}
diff --git a/src/Parameters/UserDataParameters.php b/src/Parameters/UserDataParameters.php
index a412a335..a1f788f0 100644
--- a/src/Parameters/UserDataParameters.php
+++ b/src/Parameters/UserDataParameters.php
@@ -1,4 +1,7 @@
*/
+ private array $userData = [];
- /**
- * @return string|bool
- */
- public function getUserData(string $key)
+ public function getUserData(string $key): bool|string
{
return $this->userData[$key];
}
- /**
- * @param string|bool $value
- */
- public function addUserData(string $key, $value): self
+ public function addUserData(string $key, bool|string $value): self
{
$this->userData[$key] = $value;
diff --git a/src/Responses/ApiVersionResponse.php b/src/Responses/ApiVersionResponse.php
index f747eefd..bbe86ed9 100644
--- a/src/Responses/ApiVersionResponse.php
+++ b/src/Responses/ApiVersionResponse.php
@@ -1,4 +1,7 @@
rawXml = $xml;
}
public function getRawXml(): \SimpleXMLElement
@@ -61,12 +58,12 @@ public function getMessage(): string
return $this->rawXml->message->__toString();
}
- public function success()
+ public function success(): bool
{
return $this->getReturnCode() === self::SUCCESS;
}
- public function failed()
+ public function failed(): bool
{
return $this->getReturnCode() === self::FAILED;
}
@@ -76,6 +73,6 @@ public function failed()
*/
public function hasChecksumError(): bool
{
- return $this->failed() && $this->getMessageKey() == self::CHECKSUM_ERROR;
+ return $this->failed() && $this->getMessageKey() === self::CHECKSUM_ERROR;
}
}
diff --git a/src/Responses/BaseResponseAsJson.php b/src/Responses/BaseResponseAsJson.php
index 7d45bba9..77b8fa56 100644
--- a/src/Responses/BaseResponseAsJson.php
+++ b/src/Responses/BaseResponseAsJson.php
@@ -1,4 +1,7 @@
data);
}
+ /**
+ * @return array
+ */
public function getRawArray(): array
{
return json_decode(json_encode($this->data), true);
}
- public function getMessage(): ?string
+ public function getMessage(): string
{
- if ($this->failed()) {
- return $this->data->response->message;
- }
-
- return null;
+ return $this->data->response->message ?? '';
}
- public function getMessageKey(): ?string
+ public function getMessageKey(): string
{
- if ($this->failed()) {
- return $this->data->response->messageKey;
- }
-
- return null;
+ return $this->data->response->messageKey ?? '';
}
public function getReturnCode(): string
{
- return $this->data->response->returncode;
+ return $this->data->response->returncode ?? '';
}
public function success(): bool
diff --git a/src/Responses/CreateMeetingResponse.php b/src/Responses/CreateMeetingResponse.php
index 89b063fb..2c5f350a 100644
--- a/src/Responses/CreateMeetingResponse.php
+++ b/src/Responses/CreateMeetingResponse.php
@@ -1,4 +1,7 @@
rawXml->parentMeetingID->__toString();
}
- public function getAttendeePassword(): string
- {
- return $this->rawXml->attendeePW->__toString();
- }
-
- public function getModeratorPassword(): string
- {
- return $this->rawXml->moderatorPW->__toString();
- }
-
/**
* Creation timestamp.
*
diff --git a/src/Responses/DeleteRecordingsResponse.php b/src/Responses/DeleteRecordingsResponse.php
index 9cba904c..2df97a4a 100644
--- a/src/Responses/DeleteRecordingsResponse.php
+++ b/src/Responses/DeleteRecordingsResponse.php
@@ -1,4 +1,7 @@
rawXml->deleted->__toString() == 'true';
}
- public function isInvalidId(): bool
+ public function isNotFound(): bool
{
- return $this->getMessageKey() === self::KEY_INVALID_ID;
+ return $this->getMessageKey() === self::KEY_NOT_FOUND;
}
}
diff --git a/src/Responses/EndMeetingResponse.php b/src/Responses/EndMeetingResponse.php
index 03565545..a1b8e283 100644
--- a/src/Responses/EndMeetingResponse.php
+++ b/src/Responses/EndMeetingResponse.php
@@ -1,4 +1,7 @@
rawXml->removed->__toString() === 'true';
}
+
+ public function isMissingHook(): bool
+ {
+ return $this->getMessageKey() === self::KEY_MISSING_HOOK;
+ }
+
+ public function isHookError(): bool
+ {
+ return $this->getMessageKey() === self::KEY_HOOK_ERROR;
+ }
}
diff --git a/src/Responses/HooksListResponse.php b/src/Responses/HooksListResponse.php
index 0441962f..4edb0ee5 100644
--- a/src/Responses/HooksListResponse.php
+++ b/src/Responses/HooksListResponse.php
@@ -1,4 +1,7 @@
rawXml->published->__toString() === 'true';
}
+
+ public function isNotFound(): bool
+ {
+ return $this->getMessageKey() === self::KEY_NOT_FOUND;
+ }
}
diff --git a/src/Responses/PutRecordingTextTrackResponse.php b/src/Responses/PutRecordingTextTrackResponse.php
index b512a635..27aa1cf0 100644
--- a/src/Responses/PutRecordingTextTrackResponse.php
+++ b/src/Responses/PutRecordingTextTrackResponse.php
@@ -1,4 +1,7 @@
data->response->recordId;
+ return $this->data->response->recordId ?? '';
}
public function isUploadTrackSuccess(): bool
@@ -49,6 +55,21 @@ public function isUploadTrackEmpty(): bool
return $this->getMessageKey() === self::KEY_EMPTY;
}
+ public function isNoRecordings(): bool
+ {
+ return $this->getMessageKey() === self::KEY_NO_RECORDINGS;
+ }
+
+ public function isInvalidLang(): bool
+ {
+ return $this->getMessageKey() === self::KEY_INVALID_LANG;
+ }
+
+ public function isInvalidKind(): bool
+ {
+ return $this->getMessageKey() === self::KEY_INVALID_KIND;
+ }
+
public function isKeyParamError(): bool
{
return $this->getMessageKey() === self::KEY_PARAM_ERROR;
diff --git a/src/Responses/SendChatMessageResponse.php b/src/Responses/SendChatMessageResponse.php
new file mode 100644
index 00000000..95ee4ebd
--- /dev/null
+++ b/src/Responses/SendChatMessageResponse.php
@@ -0,0 +1,26 @@
+.
+ */
+
+namespace BigBlueButton\Responses;
+
+final class SendChatMessageResponse extends BaseResponse
+{
+}
diff --git a/src/Responses/UpdateRecordingsResponse.php b/src/Responses/UpdateRecordingsResponse.php
index c30ceaef..acbc7271 100644
--- a/src/Responses/UpdateRecordingsResponse.php
+++ b/src/Responses/UpdateRecordingsResponse.php
@@ -1,4 +1,7 @@
rawXml->updated->__toString() === 'true';
}
+
+ public function isNotFound(): bool
+ {
+ return $this->getMessageKey() === self::KEY_NOT_FOUND;
+ }
}
diff --git a/src/Util/ArrayHelper.php b/src/Util/ArrayHelper.php
index a4d3d930..140e7119 100644
--- a/src/Util/ArrayHelper.php
+++ b/src/Util/ArrayHelper.php
@@ -31,7 +31,10 @@ final class ArrayHelper
*
* @see https://www.php.net/manual/en/function.array-merge-recursive.php
*
- * @param bool $reorderNested reorder nested array starting from the second level instead of merging them
+ * @param array $arrays
+ * @param bool $reorderNested reorder nested array starting from the second level instead of merging them
+ *
+ * @return array
*/
public static function mergeRecursive(bool $reorderNested, array ...$arrays): array
{
@@ -51,6 +54,12 @@ public static function mergeRecursive(bool $reorderNested, array ...$arrays): ar
return $merged;
}
+ /**
+ * @param array $array1
+ * @param array $array2
+ *
+ * @return array
+ */
private static function mergeArrays(array $array1, array $array2): array
{
$newArray = [];
diff --git a/src/Util/SimpleXMLElementExtended.php b/src/Util/SimpleXMLElementExtended.php
new file mode 100644
index 00000000..d78c9e20
--- /dev/null
+++ b/src/Util/SimpleXMLElementExtended.php
@@ -0,0 +1,24 @@
+ownerDocument;
+ $element->appendChild($docOwner->createCDATASection($value));
+
+ return $child;
+ }
+}
diff --git a/src/Util/UrlBuilder.php b/src/Util/UrlBuilder.php
index f2b58b8c..822e04a9 100644
--- a/src/Util/UrlBuilder.php
+++ b/src/Util/UrlBuilder.php
@@ -1,4 +1,7 @@
securitySalt = $secret;
- $this->bbbServerBaseUrl = $serverBaseUrl;
+ public function __construct(
+ private readonly string $securitySalt,
+ private readonly string $bbbServerBaseUrl,
+ private readonly HashingAlgorithm $hashingAlgorithm,
+ ) {
}
/**
* Builds an API method URL that includes the url + params + its generated checksum.
*/
- public function buildUrl(string $method = '', string $params = '', bool $append = true): string
+ public function buildUrl(string|ApiMethod $method = '', string $params = '', bool $append = true): string
{
+ if ($method instanceof ApiMethod) {
+ $method = $method->value;
+ }
+
return $this->bbbServerBaseUrl.'api/'.$method.($append ? '?'.$this->buildQs($method, $params) : '');
}
@@ -61,6 +63,6 @@ public function buildQs(string $method = '', string $params = ''): string
$checksumParam = 'checksum=';
}
- return $params.$checksumParam.sha1($method.$params.$this->securitySalt);
+ return $params.$checksumParam.hash($this->hashingAlgorithm->value, $method.$params.$this->securitySalt);
}
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 64a63992..d22a1a3c 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,4 +1,7 @@
load(...$files);
}
-
-// Include custom test class
-require_once __DIR__.'/TestCase.php';
diff --git a/tests/TestCase.php b/tests/common/TestCase.php
similarity index 59%
rename from tests/TestCase.php
rename to tests/common/TestCase.php
index d66e4bb0..19c792fc 100644
--- a/tests/TestCase.php
+++ b/tests/common/TestCase.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton;
+namespace BigBlueButton\Tests\Common;
-use BigBlueButton\Core\GuestPolicy;
-use BigBlueButton\Core\MeetingLayout;
+use BigBlueButton\BigBlueButton;
+use BigBlueButton\Enum\Feature;
+use BigBlueButton\Enum\GuestPolicy;
+use BigBlueButton\Enum\MeetingLayout;
+use BigBlueButton\Enum\Role;
use BigBlueButton\Parameters\CreateMeetingParameters;
use BigBlueButton\Parameters\EndMeetingParameters;
use BigBlueButton\Parameters\JoinMeetingParameters;
@@ -33,29 +39,16 @@
/**
* Class TestCase.
*/
-class TestCase extends \PHPUnit\Framework\TestCase
+abstract class TestCase extends \PHPUnit\Framework\TestCase
{
- /**
- * @var Generator
- */
- protected $faker;
+ protected Generator $faker;
- /**
- * {@inheritdoc}
- */
protected function setUp(): void
{
- parent::setUp();
-
$this->faker = Faker::create();
}
- /**
- * @param $bbb BigBlueButton
- *
- * @return CreateMeetingResponse
- */
- protected function createRealMeeting($bbb)
+ protected function createRealMeeting(BigBlueButton $bbb): CreateMeetingResponse
{
$createMeetingParams = $this->generateCreateParams();
$createMeetingMock = $this->getCreateMock($createMeetingParams);
@@ -63,19 +56,15 @@ protected function createRealMeeting($bbb)
return $bbb->createMeeting($createMeetingMock);
}
- /**
- * @return array
- */
- protected function generateCreateParams()
+ /** @return array */
+ protected function generateCreateParams(): array
{
return [
'name' => $this->faker->name,
'meetingID' => $this->faker->uuid,
- 'attendeePW' => $this->faker->password,
- 'moderatorPW' => $this->faker->password,
'autoStartRecording' => $this->faker->boolean(50),
'dialNumber' => $this->faker->phoneNumber,
- 'voiceBridge' => $this->faker->randomNumber(5),
+ 'voiceBridge' => $this->faker->randomNumber(5, true),
'webVoice' => $this->faker->word,
'logoutURL' => $this->faker->url,
'maxParticipants' => $this->faker->numberBetween(2, 100),
@@ -86,6 +75,7 @@ protected function generateCreateParams()
'moderatorOnlyMessage' => $this->faker->sentence,
'webcamsOnlyForModerator' => $this->faker->boolean(50),
'logo' => $this->faker->imageUrl(330, 70),
+ 'darklogo' => $this->faker->imageUrl(330, 70),
'copyright' => $this->faker->text,
'guestPolicy' => $this->faker->randomElement([GuestPolicy::ALWAYS_ACCEPT, GuestPolicy::ALWAYS_DENY, GuestPolicy::ASK_MODERATOR]),
'muteOnStart' => $this->faker->boolean(50),
@@ -93,28 +83,30 @@ protected function generateCreateParams()
'lockSettingsDisableMic' => $this->faker->boolean(50),
'lockSettingsDisablePrivateChat' => $this->faker->boolean(50),
'lockSettingsDisablePublicChat' => $this->faker->boolean(50),
- 'lockSettingsDisableNote' => $this->faker->boolean(50),
+ 'lockSettingsDisableNotes' => $this->faker->boolean(50),
'lockSettingsHideUserList' => $this->faker->boolean(50),
'lockSettingsLockedLayout' => $this->faker->boolean(50),
'lockSettingsLockOnJoin' => $this->faker->boolean(50),
'lockSettingsLockOnJoinConfigurable' => $this->faker->boolean(50),
'allowModsToUnmuteUsers' => $this->faker->boolean(50),
'allowModsToEjectCameras' => $this->faker->boolean(50),
+ 'disabledFeatures' => $this->faker->randomElements(Feature::cases(), 3),
+ 'disabledFeaturesExclude' => $this->faker->randomElements(Feature::cases(), 2),
+ 'allowPromoteGuestToModerator' => $this->faker->boolean(50),
'meta_presenter' => $this->faker->name,
'meta_endCallbackUrl' => $this->faker->url,
'meta_bbb-recording-ready-url' => $this->faker->url,
'bannerText' => $this->faker->sentence,
- 'bannerColor' => $this->faker->hexcolor,
+ 'bannerColor' => $this->faker->hexColor,
'meetingKeepEvents' => $this->faker->boolean(50),
'endWhenNoModerator' => $this->faker->boolean(50),
'endWhenNoModeratorDelayInMinutes' => $this->faker->numberBetween(1, 100),
'meetingLayout' => $this->faker->randomElement([
- MeetingLayout::CUSTOM_LAYOUT,
- MeetingLayout::SMART_LAYOUT,
- MeetingLayout::PRESENTATION_FOCUS,
- MeetingLayout::VIDEO_FOCUS,
- ]),
- 'learningDashboardEnabled' => $this->faker->boolean(50),
+ MeetingLayout::CUSTOM_LAYOUT,
+ MeetingLayout::SMART_LAYOUT,
+ MeetingLayout::PRESENTATION_FOCUS,
+ MeetingLayout::VIDEO_FOCUS,
+ ]),
'learningDashboardCleanupDelayInMinutes' => $this->faker->numberBetween(1, 100),
'breakoutRoomsEnabled' => $this->faker->boolean(50),
'breakoutRoomsPrivateChatEnabled' => $this->faker->boolean(50),
@@ -123,15 +115,30 @@ protected function generateCreateParams()
'allowRequestsWithoutSession' => $this->faker->boolean(50),
'virtualBackgroundsDisabled' => $this->faker->boolean(50),
'userCameraCap' => $this->faker->numberBetween(1, 5),
+ 'groups' => $this->generateBreakoutRoomsGroups(),
];
}
/**
- * @param $createParams
+ * @return array}>
+ */
+ protected function generateBreakoutRoomsGroups(): array
+ {
+ $br = $this->faker->numberBetween(0, 8);
+ $groups = [];
+ for ($i = 0; $i <= $br; ++$i) {
+ $groups[] = ['id' => $this->faker->uuid, 'name' => $this->faker->name, 'roster' => $this->faker->randomElements];
+ }
+
+ return $groups;
+ }
+
+ /**
+ * @param array $createParams
*
- * @return array
+ * @return array
*/
- protected function generateBreakoutCreateParams($createParams)
+ protected function generateBreakoutCreateParams(array $createParams): array
{
return array_merge($createParams, [
'isBreakout' => true,
@@ -141,18 +148,12 @@ protected function generateBreakoutCreateParams($createParams)
]);
}
- /**
- * @param $params array
- *
- * @return CreateMeetingParameters
- */
- protected function getCreateMock($params)
+ /** @param array $params */
+ protected function getCreateMock(array $params): CreateMeetingParameters
{
$createMeetingParams = new CreateMeetingParameters($params['meetingID'], $params['name']);
- return $createMeetingParams->setAttendeePW($params['attendeePW'])
- ->setModeratorPW($params['moderatorPW'])
- ->setDialNumber($params['dialNumber'])
+ $createMeetingParams->setDialNumber($params['dialNumber'])
->setVoiceBridge($params['voiceBridge'])
->setWebVoice($params['webVoice'])
->setLogoutURL($params['logoutURL'])
@@ -165,6 +166,7 @@ protected function getCreateMock($params)
->setModeratorOnlyMessage($params['moderatorOnlyMessage'])
->setWebcamsOnlyForModerator($params['webcamsOnlyForModerator'])
->setLogo($params['logo'])
+ ->setDarklogo($params['darklogo'])
->setCopyright($params['copyright'])
->setEndCallbackUrl($params['meta_endCallbackUrl'])
->setRecordingReadyCallbackUrl($params['meta_bbb-recording-ready-url'])
@@ -173,7 +175,7 @@ protected function getCreateMock($params)
->setLockSettingsDisableMic($params['lockSettingsDisableMic'])
->setLockSettingsDisablePrivateChat($params['lockSettingsDisablePrivateChat'])
->setLockSettingsDisablePublicChat($params['lockSettingsDisablePublicChat'])
- ->setLockSettingsDisableNote($params['lockSettingsDisableNote'])
+ ->setLockSettingsDisableNotes($params['lockSettingsDisableNotes'])
->setLockSettingsHideUserList($params['lockSettingsHideUserList'])
->setLockSettingsLockedLayout($params['lockSettingsLockedLayout'])
->setLockSettingsLockOnJoin($params['lockSettingsLockOnJoin'])
@@ -190,86 +192,79 @@ protected function getCreateMock($params)
->setMeetingEndedURL($params['meetingEndedURL'])
->setMeetingLayout($params['meetingLayout'])
->setMeetingKeepEvents($params['meetingKeepEvents'])
- ->setLearningDashboardEnabled($params['learningDashboardEnabled'])
->setLearningDashboardCleanupDelayInMinutes($params['learningDashboardCleanupDelayInMinutes'])
->setAllowModsToEjectCameras($params['allowModsToEjectCameras'])
- ->setBreakoutRoomsEnabled($params['breakoutRoomsEnabled'])
->setBreakoutRoomsPrivateChatEnabled($params['breakoutRoomsPrivateChatEnabled'])
->setBreakoutRoomsRecord($params['breakoutRoomsRecord'])
->setAllowRequestsWithoutSession($params['allowRequestsWithoutSession'])
- ->setVirtualBackgroundsDisabled($params['virtualBackgroundsDisabled'])
- ->setUserCameraCap($params['userCameraCap']);
+ ->setAllowPromoteGuestToModerator($params['allowPromoteGuestToModerator'])
+ ->setUserCameraCap($params['userCameraCap'])
+ ->setDisabledFeatures($params['disabledFeatures'])
+ ->setDisabledFeaturesExclude($params['disabledFeaturesExclude']);
+
+ foreach ($params['groups'] as $group) {
+ $createMeetingParams->addBreakoutRoomsGroup($group['id'], $group['name'], $group['roster']);
+ }
+
+ return $createMeetingParams;
}
- /**
- * @param $params
- *
- * @return CreateMeetingParameters
- */
- protected function getBreakoutCreateMock($params)
+ /** @param array $params */
+ protected function getBreakoutCreateMock(array $params): CreateMeetingParameters
{
$createMeetingParams = $this->getCreateMock($params);
- return $createMeetingParams->setBreakout($params['isBreakout'])->setParentMeetingID($params['parentMeetingId'])->
- setSequence($params['sequence'])->setFreeJoin($params['freeJoin']);
+ return $createMeetingParams->setBreakout($params['isBreakout'])->setParentMeetingID($params['parentMeetingId'])->setSequence($params['sequence'])->setFreeJoin($params['freeJoin']);
}
- /**
- * @return array
- */
- protected function generateJoinMeetingParams()
+ /** @return array */
+ protected function generateJoinMeetingParams(): array
{
return ['meetingID' => $this->faker->uuid,
- 'fullName' => $this->faker->name,
- 'password' => $this->faker->password,
- 'userID' => $this->faker->numberBetween(1, 1000),
- 'webVoiceConf' => $this->faker->word,
- 'createTime' => $this->faker->unixTime,
- 'userdata-countrycode' => $this->faker->countryCode,
- 'userdata-email' => $this->faker->email,
- 'userdata-commercial' => false,
+ 'fullName' => $this->faker->name,
+ 'role' => $this->faker->randomElement(Role::cases()),
+ 'userID' => (string) $this->faker->numberBetween(1, 1000),
+ 'webVoiceConf' => $this->faker->word,
+ 'createTime' => $this->faker->unixTime,
+ 'errorRedirectUrl' => $this->faker->url,
+ 'userdata-countrycode' => $this->faker->countryCode,
+ 'userdata-email' => $this->faker->email,
+ 'userdata-commercial' => false,
];
}
- /**
- * @param $params array
- *
- * @return JoinMeetingParameters
- */
- protected function getJoinMeetingMock($params)
+ /** @param array $params */
+ protected function getJoinMeetingMock(array $params): JoinMeetingParameters
{
- $joinMeetingParams = new JoinMeetingParameters($params['meetingID'], $params['fullName'], $params['password']);
-
- return $joinMeetingParams->setUserID($params['userID'])->setWebVoiceConf($params['webVoiceConf'])
- ->setCreateTime($params['createTime'])->addUserData('countrycode', $params['userdata-countrycode'])
- ->addUserData('email', $params['userdata-email'])->addUserData('commercial', $params['userdata-commercial']);
+ $joinMeetingParams = new JoinMeetingParameters($params['meetingID'], $params['fullName'], $params['role']);
+
+ $joinMeetingParams
+ ->setUserID($params['userID'])
+ ->setWebVoiceConf($params['webVoiceConf'])
+ ->setCreateTime($params['createTime'])
+ ->setErrorRedirectUrl($params['errorRedirectUrl'])
+ ->addUserData('countrycode', $params['userdata-countrycode'])
+ ->addUserData('email', $params['userdata-email'])
+ ->addUserData('commercial', $params['userdata-commercial']);
+
+ return $joinMeetingParams;
}
- /**
- * @return array
- */
- protected function generateEndMeetingParams()
+ /** @return array */
+ protected function generateEndMeetingParams(): array
{
- return ['meetingID' => $this->faker->uuid,
- 'password' => $this->faker->password, ];
+ return [
+ 'meetingID' => $this->faker->uuid,
+ ];
}
- /**
- * @param $params array
- *
- * @return EndMeetingParameters
- */
- protected function getEndMeetingMock($params)
+ /** @param array $params */
+ protected function getEndMeetingMock(array $params): EndMeetingParameters
{
- return new EndMeetingParameters($params['meetingID'], $params['password']);
+ return new EndMeetingParameters($params['meetingID']);
}
- /**
- * @param $bbb BigBlueButton
- *
- * @return UpdateRecordingsResponse
- */
- protected function updateRecordings($bbb)
+ protected function updateRecordings(BigBlueButton $bbb): UpdateRecordingsResponse
{
$updateRecordingsParams = $this->generateUpdateRecordingsParams();
$updateRecordingsMock = $this->getUpdateRecordingsParamsMock($updateRecordingsParams);
@@ -277,10 +272,8 @@ protected function updateRecordings($bbb)
return $bbb->updateRecordings($updateRecordingsMock);
}
- /**
- * @return array
- */
- protected function generateUpdateRecordingsParams()
+ /** @return array */
+ protected function generateUpdateRecordingsParams(): array
{
return [
'recordID' => $this->faker->uuid,
@@ -288,62 +281,91 @@ protected function generateUpdateRecordingsParams()
];
}
- /**
- * @param $params array
- *
- * @return UpdateRecordingsParameters
- */
- protected function getUpdateRecordingsParamsMock($params)
+ /** @param array $params */
+ protected function getUpdateRecordingsParamsMock(array $params): UpdateRecordingsParameters
{
- $updateRecordingsParams = new UpdateRecordingsParameters($params['recordID']);
+ $updateRecordingParameters = new UpdateRecordingsParameters($params['recordID']);
+ $updateRecordingParameters->addMeta('presenter', $params['meta_presenter']);
- return $updateRecordingsParams->addMeta('presenter', $params['meta_presenter']);
+ return $updateRecordingParameters;
}
// Load fixtures
- protected function loadXmlFile($path)
+ protected function loadXmlFile(string $path): \SimpleXMLElement
{
return simplexml_load_string(file_get_contents($path));
}
- protected function loadJsonFile($path)
+ protected function loadJsonFile(string $path): string
{
return file_get_contents($path);
}
- protected function minifyString($string)
+ protected function minifyString(string $string): string
{
- return str_replace(["\r\n", "\r", "\n", "\t", ' '], '', $string);
+ return str_replace(["\r\n", "\r", "\n", "\t", ' '], '', (string) $string);
}
// Additional assertions
- public function assertEachGetterValueIsString($obj, $getters)
+ /**
+ * @param array $getters
+ */
+ public function assertEachGetterValueIsString(object $obj, array $getters): void
{
foreach ($getters as $getterName) {
$this->assertIsString($obj->$getterName(), 'Got a '.\gettype($obj->$getterName()).' instead of a string for property -> '.$getterName);
}
}
- public function assertEachGetterValueIsInteger($obj, $getters)
+ /**
+ * @param array $getters
+ */
+ public function assertEachGetterValueIsInteger(object $obj, array $getters): void
{
foreach ($getters as $getterName) {
$this->assertIsInt($obj->$getterName(), 'Got a '.\gettype($obj->$getterName()).' instead of an integer for property -> '.$getterName);
}
}
- public function assertEachGetterValueIsDouble($obj, $getters)
+ /**
+ * @param array $getters
+ */
+ public function assertEachGetterValueIsDouble(object $obj, array $getters): void
{
foreach ($getters as $getterName) {
$this->assertIsFloat($obj->$getterName(), 'Got a '.\gettype($obj->$getterName()).' instead of a double for property -> '.$getterName);
}
}
- public function assertEachGetterValueIsBoolean($obj, $getters)
+ /**
+ * @param array $getters
+ */
+ public function assertEachGetterValueIsBoolean(object $obj, array $getters): void
{
foreach ($getters as $getterName) {
$this->assertIsBool($obj->$getterName(), 'Got a '.\gettype($obj->$getterName()).' instead of a boolean for property -> '.$getterName);
}
}
+
+ /** @param array $parameters */
+ public function assertUrlContainsAllRequestParameters(string $url, array $parameters): void
+ {
+ foreach ($parameters as $parameter) {
+ if (\is_bool($parameter)) {
+ $parameter = $parameter ? 'true' : 'false';
+ }
+
+ if ($parameter instanceof \BackedEnum) {
+ $parameter = $parameter->value;
+ }
+
+ if (!\is_array($parameter)) {
+ $this->assertStringContainsString((string) $parameter, urldecode($url));
+ } else {
+ $this->assertUrlContainsAllRequestParameters($url, $parameter);
+ }
+ }
+ }
}
diff --git a/tests/fixtures/client_settings.xml b/tests/fixtures/client_settings.xml
new file mode 100644
index 00000000..6ef5db4b
--- /dev/null
+++ b/tests/fixtures/client_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/fixtures/create_meeting_not_unique_error.xml b/tests/fixtures/create_meeting_not_unique_error.xml
new file mode 100644
index 00000000..1575d544
--- /dev/null
+++ b/tests/fixtures/create_meeting_not_unique_error.xml
@@ -0,0 +1,5 @@
+
+ FAILED
+ idNotUnique
+ A meeting already exists with that meeting ID. Please use a different meeting ID.
+
diff --git a/tests/fixtures/not_found_error.xml b/tests/fixtures/not_found_error.xml
new file mode 100644
index 00000000..4a5d46b7
--- /dev/null
+++ b/tests/fixtures/not_found_error.xml
@@ -0,0 +1,5 @@
+
+ FAILED
+ notFound
+ We could not find recordings
+
diff --git a/tests/functional/AbstractBigBlueButtonFunctionalTest.php b/tests/functional/AbstractBigBlueButtonFunctionalTest.php
index fdceead1..074963ff 100644
--- a/tests/functional/AbstractBigBlueButtonFunctionalTest.php
+++ b/tests/functional/AbstractBigBlueButtonFunctionalTest.php
@@ -1,4 +1,7 @@
bbb->isConnectionWorking();
@@ -89,7 +88,7 @@ public function testIsConnectionWorking()
/**
* Test API version call.
*/
- public function testApiVersion()
+ public function testApiVersion(): void
{
$apiVersion = $this->bbb->getApiVersion();
$this->assertEquals('SUCCESS', $apiVersion->getReturnCode());
@@ -99,36 +98,23 @@ public function testApiVersion()
/* Create Meeting */
- /**
- * Test create meeting URL.
- */
- public function testCreateMeetingUrl(): void
- {
- $params = $this->generateCreateParams();
- $url = $this->bbb->getCreateMeetingUrl($this->getCreateMock($params));
- foreach ($params as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString($key.'='.rawurlencode($value), $url);
- }
- }
-
/**
* Test create meeting.
*/
- public function testCreateMeeting()
+ public function testCreateMeeting(): void
{
- $params = $this->generateCreateParams();
- $result = $this->bbb->createMeeting($this->getCreateMock($params));
+ $result = $this->createRealMeeting($this->bbb);
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($result->getMeetingId()));
}
/**
* Test create meeting with a document URL.
*/
- public function testCreateMeetingWithDocumentUrl()
+ public function testCreateMeetingWithDocumentUrl(): void
{
$params = $this->getCreateMock($this->generateCreateParams());
$params->addPresentation('https://picsum.photos/3840/2160/?random');
@@ -138,12 +124,15 @@ public function testCreateMeetingWithDocumentUrl()
$this->assertCount(1, $params->getPresentations());
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($result->getMeetingId()));
}
/**
* Test create meeting with a document URL and filename.
*/
- public function testCreateMeetingWithDocumentUrlAndFileName()
+ public function testCreateMeetingWithDocumentUrlAndFileName(): void
{
$params = $this->getCreateMock($this->generateCreateParams());
$params->addPresentation('https://picsum.photos/3840/2160/?random', null, 'placeholder.png');
@@ -153,12 +142,15 @@ public function testCreateMeetingWithDocumentUrlAndFileName()
$this->assertCount(1, $params->getPresentations());
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($result->getMeetingId()));
}
/**
* Test create meeting with a document URL.
*/
- public function testCreateMeetingWithDocumentEmbedded()
+ public function testCreateMeetingWithDocumentEmbedded(): void
{
$params = $this->getCreateMock($this->generateCreateParams());
$params->addPresentation('bbb_logo.png', file_get_contents(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'bbb_logo.png'));
@@ -168,12 +160,15 @@ public function testCreateMeetingWithDocumentEmbedded()
$this->assertCount(1, $params->getPresentations());
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($result->getMeetingId()));
}
/**
* Test create meeting with a multiple documents.
*/
- public function testCreateMeetingWithMultiDocument()
+ public function testCreateMeetingWithMultiDocument(): void
{
$params = $this->getCreateMock($this->generateCreateParams());
$params->addPresentation('https://picsum.photos/3840/2160/?random', null, 'presentation.png');
@@ -184,39 +179,25 @@ public function testCreateMeetingWithMultiDocument()
$this->assertCount(2, $params->getPresentations());
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($result->getMeetingId()));
}
/* Join Meeting */
- /**
- * Test create join meeting URL.
- */
- public function testCreateJoinMeetingUrl(): void
- {
- $joinMeetingParams = $this->generateJoinMeetingParams();
- $joinMeetingMock = $this->getJoinMeetingMock($joinMeetingParams);
-
- $url = $this->bbb->getJoinMeetingURL($joinMeetingMock);
-
- foreach ($joinMeetingParams as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString('='.rawurlencode($value), $url);
- }
- }
-
- public function testJoinMeeting()
+ public function testJoinMeeting(): void
{
- $params = $this->generateCreateParams();
- $result = $this->bbb->createMeeting($this->getCreateMock($params));
+ $params = $this->getCreateMock($this->generateCreateParams());
+ $params->setGuestPolicy('ALWAYS_ACCEPT');
+ $result = $this->bbb->createMeeting($params);
$this->assertEquals('SUCCESS', $result->getReturnCode(), 'Create meeting');
$creationTime = $result->getCreationTime();
- $joinMeetingParams = $this->generateJoinMeetingParams();
- $joinMeetingParams = new JoinMeetingParameters($result->getMeetingId(), 'Foobar', $result->getAttendeePassword());
+ $params = $this->generateJoinMeetingParams();
+ $joinMeetingParams = new JoinMeetingParameters($result->getMeetingId(), $params['fullName'], $params['role']);
$joinMeetingParams->setRedirect(false);
- $joinMeetingParams->setCreateTime(sprintf('%.0f', $creationTime));
+ $joinMeetingParams->setCreateTime((int) \sprintf('%.0f', $creationTime));
$joinMeeting = $this->bbb->joinMeeting($joinMeetingParams);
$this->assertEquals('SUCCESS', $joinMeeting->getReturnCode(), 'Join meeting');
@@ -226,36 +207,24 @@ public function testJoinMeeting()
$this->assertNotEmpty($joinMeeting->getSessionToken());
$this->assertNotEmpty($joinMeeting->getGuestStatus());
$this->assertNotEmpty($joinMeeting->getUrl());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($result->getMeetingId()));
}
/* End Meeting */
- /**
- * Test generate end meeting URL.
- */
- public function testCreateEndMeetingUrl(): void
- {
- $params = $this->generateEndMeetingParams();
- $url = $this->bbb->getEndMeetingURL($this->getEndMeetingMock($params));
- foreach ($params as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString('='.rawurlencode($value), $url);
- }
- }
-
- public function testEndMeeting()
+ public function testEndMeeting(): void
{
$meeting = $this->createRealMeeting($this->bbb);
- $endMeeting = new EndMeetingParameters($meeting->getMeetingId(), $meeting->getModeratorPassword());
+ $endMeeting = new EndMeetingParameters($meeting->getMeetingId());
$result = $this->bbb->endMeeting($endMeeting);
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
}
- public function testEndNonExistingMeeting()
+ public function testEndNonExistingMeeting(): void
{
$params = $this->generateEndMeetingParams();
$result = $this->bbb->endMeeting($this->getEndMeetingMock($params));
@@ -265,7 +234,7 @@ public function testEndNonExistingMeeting()
/* Is Meeting Running */
- public function testIsMeetingRunning()
+ public function testIsMeetingRunning(): void
{
$result = $this->bbb->isMeetingRunning(new IsMeetingRunningParameters($this->faker->uuid));
$this->assertEquals('SUCCESS', $result->getReturnCode());
@@ -275,16 +244,15 @@ public function testIsMeetingRunning()
/* Get Meetings */
- public function testGetMeetingsUrl(): void
+ public function testGetMeetings(): void
{
- $url = $this->bbb->getMeetingsUrl();
- $this->assertStringContainsString(ApiMethod::GET_MEETINGS, $url);
- }
+ $meeting = $this->createRealMeeting($this->bbb);
- public function testGetMeetings()
- {
$result = $this->bbb->getMeetings();
$this->assertNotEmpty($result->getMeetings());
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($meeting->getMeetingId()));
}
/* Get meeting info */
@@ -295,69 +263,45 @@ public function testGetMeetingInfoUrl(): void
$url = $this->bbb->getMeetingInfoUrl(new GetMeetingInfoParameters($meeting->getMeetingId()));
$this->assertStringContainsString('='.rawurlencode($meeting->getMeetingId()), $url);
+
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($meeting->getMeetingId()));
}
- public function testGetMeetingInfo()
+ public function testGetMeetingInfo(): void
{
$meeting = $this->createRealMeeting($this->bbb);
- $result = $this->bbb->getMeetingInfo(new GetMeetingInfoParameters($meeting->getMeetingId(), $meeting->getModeratorPassword()));
+ $result = $this->bbb->getMeetingInfo(new GetMeetingInfoParameters($meeting->getMeetingId()));
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
- }
- public function testGetRecordingsUrl(): void
- {
- $url = $this->bbb->getRecordingsUrl(new GetRecordingsParameters());
- $this->assertStringContainsString(ApiMethod::GET_RECORDINGS, $url);
+ // Cleanup
+ $this->bbb->endMeeting(new EndMeetingParameters($meeting->getMeetingId()));
}
- public function testGetRecordings()
+ public function testGetRecordings(): void
{
$result = $this->bbb->getRecordings(new GetRecordingsParameters());
$this->assertEquals('SUCCESS', $result->getReturnCode());
$this->assertTrue($result->success());
}
- public function testPublishRecordingsUrl(): void
- {
- $url = $this->bbb->getPublishRecordingsUrl(new PublishRecordingsParameters($this->faker->sha1, true));
- $this->assertStringContainsString(ApiMethod::PUBLISH_RECORDINGS, $url);
- }
-
- public function testPublishRecordings()
+ public function testPublishRecordings(): void
{
$result = $this->bbb->publishRecordings(new PublishRecordingsParameters('non-existing-id-'.$this->faker->sha1, true));
$this->assertEquals('FAILED', $result->getReturnCode());
$this->assertTrue($result->failed());
}
- public function testDeleteRecordingsUrl(): void
- {
- $url = $this->bbb->getDeleteRecordingsUrl(new DeleteRecordingsParameters($this->faker->sha1));
- $this->assertStringContainsString(ApiMethod::DELETE_RECORDINGS, $url);
- }
-
- public function testDeleteRecordings()
+ public function testDeleteRecordings(): void
{
$result = $this->bbb->deleteRecordings(new DeleteRecordingsParameters('non-existing-id-'.$this->faker->sha1));
$this->assertEquals('FAILED', $result->getReturnCode());
$this->assertTrue($result->failed());
}
- public function testUpdateRecordingsUrl(): void
- {
- $params = $this->generateUpdateRecordingsParams();
- $url = $this->bbb->getUpdateRecordingsUrl($this->getUpdateRecordingsParamsMock($params));
- foreach ($params as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString('='.rawurlencode($value), $url);
- }
- }
-
- public function testUpdateRecordings()
+ public function testUpdateRecordings(): void
{
$params = $this->generateUpdateRecordingsParams();
$result = $this->bbb->updateRecordings($this->getUpdateRecordingsParamsMock($params));
diff --git a/tests/functional/BigBlueButtonWithCurlTransportTest.php b/tests/functional/BigBlueButtonWithCurlTransportTest.php
index 9bfc9a0f..61d40766 100644
--- a/tests/functional/BigBlueButtonWithCurlTransportTest.php
+++ b/tests/functional/BigBlueButtonWithCurlTransportTest.php
@@ -26,9 +26,6 @@
final class BigBlueButtonWithCurlTransportTest extends AbstractBigBlueButtonFunctionalTest
{
- /**
- * {@inheritDoc}
- */
protected static function createTransport(): TransportInterface
{
return CurlTransport::createWithDefaultOptions();
diff --git a/tests/functional/BigBlueButtonWithPsrHttpClientTransport.php b/tests/functional/BigBlueButtonWithPsrHttpClientTransport.php
index 3bebccef..cd5bd19c 100644
--- a/tests/functional/BigBlueButtonWithPsrHttpClientTransport.php
+++ b/tests/functional/BigBlueButtonWithPsrHttpClientTransport.php
@@ -29,9 +29,6 @@
final class BigBlueButtonWithPsrHttpClientTransport extends AbstractBigBlueButtonFunctionalTest
{
- /**
- * {@inheritDoc}
- */
protected static function createTransport(): TransportInterface
{
$psr17Factory = new Psr17Factory();
diff --git a/tests/functional/BigBlueButtonWithSymfonyHttpClientTransportTest.php b/tests/functional/BigBlueButtonWithSymfonyHttpClientTransportTest.php
index 0dc733b8..3f75ce6f 100644
--- a/tests/functional/BigBlueButtonWithSymfonyHttpClientTransportTest.php
+++ b/tests/functional/BigBlueButtonWithSymfonyHttpClientTransportTest.php
@@ -26,9 +26,6 @@
final class BigBlueButtonWithSymfonyHttpClientTransportTest extends AbstractBigBlueButtonFunctionalTest
{
- /**
- * {@inheritDoc}
- */
protected static function createTransport(): TransportInterface
{
return SymfonyHttpClientTransport::create();
diff --git a/tests/integration/Http/Transport/CurlTransportTest.php b/tests/integration/Http/Transport/CurlTransportTest.php
index 8517e011..0980173b 100644
--- a/tests/integration/Http/Transport/CurlTransportTest.php
+++ b/tests/integration/Http/Transport/CurlTransportTest.php
@@ -19,9 +19,11 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http\Transport;
+namespace BigBlueButton\Tests\Integration\Http\Transport;
use BigBlueButton\Exceptions\NetworkException;
+use BigBlueButton\Http\Transport\CurlTransport;
+use BigBlueButton\Http\Transport\TransportRequest;
use PHPUnit\Framework\TestCase;
/**
@@ -34,20 +36,18 @@
*/
final class CurlTransportTest extends TestCase
{
- /**
- * {@inheritDoc}
- */
public static function setUpBeforeClass(): void
{
TestHttpServer::start();
}
+ /** @return array> */
public function provideBadResponseCodes(): iterable
{
// cURL does not understand codes below 200 properly.
-// foreach (range(100, 199) as $badCode) {
-// yield 'HTTP code ' . $badCode => [$badCode];
-// }
+ // foreach (range(100, 199) as $badCode) {
+ // yield 'HTTP code ' . $badCode => [$badCode];
+ // }
foreach (range(300, 599) as $badCode) {
yield 'HTTP code '.$badCode => [$badCode];
@@ -80,6 +80,13 @@ public function testRequestWithPayloadAndAdditionalHeader(): void
// BEWARE: Never do this in any production code. You have been warned.
eval('$dump = '.$response->getBody().';');
+ $this->assertArrayHasKey('input', $dump);
+ $this->assertArrayHasKey('vars', $dump);
+ $this->assertArrayHasKey('HTTP_CONTENT_LENGTH', $dump['vars']);
+ $this->assertArrayHasKey('HTTP_X_FOO', $dump['vars']);
+ $this->assertArrayHasKey('HTTP_X_BAR', $dump['vars']);
+ $this->assertArrayHasKey('REQUEST_METHOD', $dump['vars']);
+
$this->assertSame('FOO', $dump['input'], 'input echo is correct');
$this->assertSame('3', $dump['vars']['HTTP_CONTENT_LENGTH'], 'Content-Length echo is correct');
$this->assertSame('application/xml', $dump['vars']['HTTP_CONTENT_TYPE'], 'Content-Type echo is correct');
@@ -99,6 +106,11 @@ public function testRequestWithPayload(): void
// BEWARE: Never do this in any production code. You have been warned.
eval('$dump = '.$response->getBody().';');
+ $this->assertArrayHasKey('input', $dump);
+ $this->assertArrayHasKey('vars', $dump);
+ $this->assertArrayHasKey('HTTP_CONTENT_LENGTH', $dump['vars']);
+ $this->assertArrayHasKey('REQUEST_METHOD', $dump['vars']);
+
$this->assertSame('FOO', $dump['input'], 'input echo is correct');
$this->assertSame('3', $dump['vars']['HTTP_CONTENT_LENGTH'], 'Content-Length echo is correct');
$this->assertSame('application/xml', $dump['vars']['HTTP_CONTENT_TYPE'], 'Content-Type echo is correct');
@@ -116,6 +128,10 @@ public function testRequestWithoutPayload(): void
// BEWARE: Never do this in any production code. You have been warned.
eval('$dump = '.$response->getBody().';');
+ $this->assertArrayHasKey('input', $dump);
+ $this->assertArrayHasKey('vars', $dump);
+ $this->assertArrayHasKey('REQUEST_METHOD', $dump['vars']);
+
$this->assertSame('', $dump['input'], 'input echo is correct');
$this->assertSame('GET', $dump['vars']['REQUEST_METHOD'], 'request method echo is correct');
}
@@ -153,6 +169,10 @@ public function testRequestWithDuplicatedHeader(): void
// BEWARE: Never do this in any production code. You have been warned.
eval('$dump = '.$response->getBody().';');
+ $this->assertArrayHasKey('input', $dump);
+ $this->assertArrayHasKey('vars', $dump);
+ $this->assertArrayHasKey('HTTP_CONTENT_LENGTH', $dump['vars']);
+
$this->assertSame('FOO', $dump['input'], 'input echo is correct');
$this->assertSame('3', $dump['vars']['HTTP_CONTENT_LENGTH'], 'Content-Length echo is correct');
}
diff --git a/tests/integration/Http/Transport/Fixtures/web/cookie.php b/tests/integration/Http/Transport/Fixtures/web/cookie.php
index 51858fc3..d808ab0b 100644
--- a/tests/integration/Http/Transport/Fixtures/web/cookie.php
+++ b/tests/integration/Http/Transport/Fixtures/web/cookie.php
@@ -20,7 +20,7 @@
*/
if ('cli-server' !== \PHP_SAPI) {
// safe guard against unwanted execution
- throw new \Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
+ throw new Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
}
setcookie('JSESSIONID', 'Monkey');
diff --git a/tests/integration/Http/Transport/Fixtures/web/double-newline.php b/tests/integration/Http/Transport/Fixtures/web/double-newline.php
index 2a1e4999..bbc5f7fa 100644
--- a/tests/integration/Http/Transport/Fixtures/web/double-newline.php
+++ b/tests/integration/Http/Transport/Fixtures/web/double-newline.php
@@ -20,7 +20,7 @@
*/
if ('cli-server' !== \PHP_SAPI) {
// safe guard against unwanted execution
- throw new \Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
+ throw new Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
}
echo "Foo\r\n\r\n";
diff --git a/tests/integration/Http/Transport/Fixtures/web/dump.php b/tests/integration/Http/Transport/Fixtures/web/dump.php
index a74efeaa..31445fdc 100644
--- a/tests/integration/Http/Transport/Fixtures/web/dump.php
+++ b/tests/integration/Http/Transport/Fixtures/web/dump.php
@@ -29,7 +29,7 @@
if ('cli-server' !== \PHP_SAPI) {
// safe guard against unwanted execution
- throw new \Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
+ throw new Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
}
$vars = [];
@@ -38,7 +38,7 @@
foreach ($_SERVER as $k => $v) {
switch ($k) {
default:
- if (0 !== strpos($k, 'HTTP_')) {
+ if (!str_starts_with($k, 'HTTP_')) {
continue 2;
}
// no break
diff --git a/tests/integration/Http/Transport/Fixtures/web/no-cookie.php b/tests/integration/Http/Transport/Fixtures/web/no-cookie.php
index 553afb62..6dae060f 100644
--- a/tests/integration/Http/Transport/Fixtures/web/no-cookie.php
+++ b/tests/integration/Http/Transport/Fixtures/web/no-cookie.php
@@ -20,7 +20,7 @@
*/
if ('cli-server' !== \PHP_SAPI) {
// safe guard against unwanted execution
- throw new \Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
+ throw new Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
}
echo 'Hello from the other side!';
diff --git a/tests/integration/Http/Transport/Fixtures/web/response-code.php b/tests/integration/Http/Transport/Fixtures/web/response-code.php
index e09e412d..bfc48b46 100644
--- a/tests/integration/Http/Transport/Fixtures/web/response-code.php
+++ b/tests/integration/Http/Transport/Fixtures/web/response-code.php
@@ -20,7 +20,7 @@
*/
if ('cli-server' !== \PHP_SAPI) {
// safe guard against unwanted execution
- throw new \Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
+ throw new Exception("You cannot run this script directly, it's a fixture for TestHttpServer.");
}
http_response_code((int) ($_GET['code'] ?? 200));
diff --git a/tests/integration/Http/Transport/TestHttpServer.php b/tests/integration/Http/Transport/TestHttpServer.php
index 35192f2d..f5895d21 100644
--- a/tests/integration/Http/Transport/TestHttpServer.php
+++ b/tests/integration/Http/Transport/TestHttpServer.php
@@ -26,7 +26,7 @@
* THE SOFTWARE.
*/
-namespace BigBlueButton\Http\Transport;
+namespace BigBlueButton\Tests\Integration\Http\Transport;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
@@ -38,9 +38,10 @@
*/
final class TestHttpServer
{
- private static $process = [];
+ /** @var array */
+ private static array $process = [];
- public static function start(int $port = 8057)
+ public static function start(int $port = 8057): Process
{
if (isset(self::$process[$port])) {
self::$process[$port]->stop();
diff --git a/tests/unit/BigBlueButtonTest.php b/tests/unit/BigBlueButtonTest.php
index 045cb7fb..944639c9 100644
--- a/tests/unit/BigBlueButtonTest.php
+++ b/tests/unit/BigBlueButtonTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton;
+namespace BigBlueButton\Tests\Unit;
-use BigBlueButton\Core\ApiMethod;
+use BigBlueButton\BigBlueButton;
+use BigBlueButton\Enum\ApiMethod;
+use BigBlueButton\Enum\HashingAlgorithm;
use BigBlueButton\Exceptions\ConfigException;
use BigBlueButton\Exceptions\NetworkException;
use BigBlueButton\Exceptions\ParsingException;
use BigBlueButton\Http\Transport\TransportInterface;
use BigBlueButton\Http\Transport\TransportResponse;
use BigBlueButton\Parameters\DeleteRecordingsParameters;
+use BigBlueButton\Parameters\GetMeetingInfoParameters;
use BigBlueButton\Parameters\GetRecordingsParameters;
+use BigBlueButton\Parameters\GetRecordingTextTracksParameters;
+use BigBlueButton\Parameters\HooksCreateParameters;
+use BigBlueButton\Parameters\HooksDestroyParameters;
+use BigBlueButton\Parameters\HooksListParameters;
use BigBlueButton\Parameters\InsertDocumentParameters;
use BigBlueButton\Parameters\PublishRecordingsParameters;
+use BigBlueButton\Parameters\PutRecordingTextTrackParameters;
+use BigBlueButton\Tests\Common\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
/**
* Class BigBlueButtonTest.
*/
-class BigBlueButtonTest extends TestCase
+final class BigBlueButtonTest extends TestCase
{
- /** @var MockObject */
- private $transport;
-
- /**
- * @var BigBlueButton
- */
- private $bbb;
+ private MockObject $transport;
+ private BigBlueButton $bbb;
/**
* Setup test class.
@@ -55,7 +62,7 @@ protected function setUp(): void
$this->bbb = new BigBlueButton('http://localhost/', null, $this->transport);
}
- public function testMissingUrl()
+ public function testMissingUrl(): void
{
$this->expectException(ConfigException::class);
@@ -69,7 +76,7 @@ public function testMissingUrl()
}
}
- public function testNetworkFailure()
+ public function testNetworkFailure(): void
{
$this->expectException(NetworkException::class);
@@ -80,7 +87,7 @@ public function testNetworkFailure()
$this->bbb->createMeeting($this->getCreateMock($params));
}
- public function testInvalidXMLResponse()
+ public function testInvalidXMLResponse(): void
{
$this->expectException(ParsingException::class);
@@ -91,7 +98,7 @@ public function testInvalidXMLResponse()
$this->bbb->createMeeting($this->getCreateMock($params));
}
- public function testJSessionId()
+ public function testJSessionId(): void
{
$id = 'foobar';
$this->transport->method('request')->willReturn(new TransportResponse('', $id));
@@ -103,7 +110,7 @@ public function testJSessionId()
$this->assertEquals($id, $this->bbb->getJSessionId());
}
- public function testApiVersion()
+ public function testApiVersion(): void
{
$apiVersion = '2.0';
$xml = "
@@ -119,7 +126,7 @@ public function testApiVersion()
$this->assertEquals($apiVersion, $response->getVersion());
}
- public function testIsConnectionWorking()
+ public function testIsConnectionWorking(): void
{
$xmlSuccess = '
SUCCESS
@@ -152,21 +159,156 @@ public function testIsConnectionWorking()
$this->assertEquals(BigBlueButton::CONNECTION_ERROR_BASEURL, $this->bbb->getConnectionError());
}
+ /* Get meeting info */
+
+ public function testGetMeetingInfoUrl(): void
+ {
+ $meetingId = $this->faker->uuid;
+
+ $url = $this->bbb->getMeetingInfoUrl(new GetMeetingInfoParameters($meetingId));
+ $this->assertStringContainsString('='.rawurlencode((string) $meetingId), $url);
+ }
+
+ public function testGetMeetingInfo(): void
+ {
+ $meetingId = $this->faker->uuid;
+
+ $xml = '
+ SUCCESS
+ Demo Meeting
+ '.$meetingId.'
+ 79fd9d83ffdfe7d1fcfb19feab08d283ad518e49-1710416871174
+ 1710416871174
+ Thu Mar 14 11:47:51 UTC 2024
+ 180621383
+ 18632080022
+ ap
+ mp
+ false
+ 540
+ false
+ false
+ false
+ 1710416871176
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+ false
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $result = $this->bbb->getMeetingInfo(new GetMeetingInfoParameters($meetingId));
+ $this->assertEquals('SUCCESS', $result->getReturnCode());
+ $this->assertTrue($result->success());
+
+ $meeting = $result->getMeeting();
+
+ $this->assertEquals($meetingId, $meeting->getMeetingId());
+ $this->assertEquals('Demo Meeting', $meeting->getMeetingName());
+ }
+
/* Create Meeting */
/**
* Test create meeting URL.
*/
- public function testCreateMeetingUrl()
+ public function testCreateMeetingUrl(): void
{
$params = $this->generateCreateParams();
$url = $this->bbb->getCreateMeetingUrl($this->getCreateMock($params));
- foreach ($params as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString(rawurlencode($key).'='.rawurlencode($value), $url);
- }
+
+ $this->assertUrlContainsAllRequestParameters($url, $params);
+ }
+
+ /**
+ * Test create meeting without modules.
+ */
+ public function testCreate(): void
+ {
+ $createMeetingParams = $this->generateCreateParams();
+ $params = $this->getCreateMock($createMeetingParams);
+
+ $xml = '
+ SUCCESS
+ '.$params->getMeetingID().'
+ 1a6938c707cdf5d052958672d66c219c30690c47-1524212045514
+ 1453283819419
+ '.$params->getVoiceBridge().'
+ 613-555-1234
+ Wed Jan 20 04:56:59 EST 2016
+ false
+ 20
+ false
+ ';
+
+ $this->transport->method('request')
+ ->with(self::callback(static function ($request) {
+ $payload = $request->getPayload();
+
+ return $payload === '';
+ }))
+ ->willReturn(new TransportResponse($xml, null));
+
+ $response = $this->bbb->createMeeting($params);
+
+ $this->assertTrue($response->success());
+ $this->assertFalse($response->isDuplicate());
+ $this->assertFalse($response->isIdNotUnique());
+ }
+
+ /**
+ * Test create meeting with modules (presentations and clientSettingsOverride).
+ */
+ public function testCreateWithPresentation(): void
+ {
+ $createMeetingParams = $this->generateCreateParams();
+ $params = $this->getCreateMock($createMeetingParams);
+ $params->addPresentation('http://test-install.blindsidenetworks.com/default.pdf', null, 'presentation.pdf');
+ $params->addPresentation('http://test-install.blindsidenetworks.com/file.pdf');
+ $params->setClientSettingsOverride('{ "public": { "app": { "appName": "Test" } } }');
+
+ $xml = '
+ SUCCESS
+ '.$params->getMeetingID().'
+ 1a6938c707cdf5d052958672d66c219c30690c47-1524212045514
+ 1453283819419
+ '.$params->getVoiceBridge().'
+ 613-555-1234
+ Wed Jan 20 04:56:59 EST 2016
+ false
+ 20
+ false
+ ';
+
+ $this->transport->method('request')
+ ->with(self::callback(static function ($request) {
+ $payload = $request->getPayload();
+ $xml = simplexml_load_string($payload);
+
+ $presentations = $xml->module[0];
+ $clientSettingsOverride = $xml->module[1];
+
+ return \count($xml->module) == 2
+ && $presentations->attributes()['name']->__toString() == 'presentation'
+ && $clientSettingsOverride->attributes()['name']->__toString() == 'clientSettingsOverride'
+ && $presentations->children()[0]->attributes()['url']->__toString() == 'http://test-install.blindsidenetworks.com/default.pdf'
+ && $presentations->children()[0]->attributes()['filename']->__toString() == 'presentation.pdf'
+ && $presentations->children()[1]->attributes()['url']->__toString() == 'http://test-install.blindsidenetworks.com/file.pdf';
+ }))
+ ->willReturn(new TransportResponse($xml, null));
+
+ $response = $this->bbb->createMeeting($params);
+
+ $this->assertTrue($response->success());
+ $this->assertFalse($response->isDuplicate());
+ $this->assertFalse($response->isIdNotUnique());
}
/* Join Meeting */
@@ -174,22 +316,17 @@ public function testCreateMeetingUrl()
/**
* Test create join meeting URL.
*/
- public function testCreateJoinMeetingUrl()
+ public function testCreateJoinMeetingUrl(): void
{
$joinMeetingParams = $this->generateJoinMeetingParams();
$joinMeetingMock = $this->getJoinMeetingMock($joinMeetingParams);
$url = $this->bbb->getJoinMeetingURL($joinMeetingMock);
- foreach ($joinMeetingParams as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString(rawurlencode($key).'='.rawurlencode($value), $url);
- }
+ $this->assertUrlContainsAllRequestParameters($url, $joinMeetingParams);
}
- public function testJoinMeeting()
+ public function testJoinMeeting(): void
{
$joinMeetingParams = $this->generateJoinMeetingParams();
$params = $this->getJoinMeetingMock($joinMeetingParams);
@@ -225,19 +362,15 @@ public function testJoinMeeting()
/**
* Test generate end meeting URL.
*/
- public function testCreateEndMeetingUrl()
+ public function testCreateEndMeetingUrl(): void
{
$params = $this->generateEndMeetingParams();
$url = $this->bbb->getEndMeetingURL($this->getEndMeetingMock($params));
- foreach ($params as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString(rawurlencode($key).'='.rawurlencode($value), $url);
- }
+
+ $this->assertUrlContainsAllRequestParameters($url, $params);
}
- public function testEndMeeting()
+ public function testEndMeeting(): void
{
$data = $this->generateEndMeetingParams();
$params = $this->getEndMeetingMock($data);
@@ -257,13 +390,13 @@ public function testEndMeeting()
/* Get Meetings */
- public function testGetMeetingsUrl()
+ public function testGetMeetingsUrl(): void
{
$url = $this->bbb->getMeetingsUrl();
- $this->assertStringContainsString(ApiMethod::GET_MEETINGS, $url);
+ $this->assertStringContainsString(ApiMethod::GET_MEETINGS->value, $url);
}
- public function testGetMeetings()
+ public function testGetMeetings(): void
{
$xml = '
SUCCESS
@@ -308,56 +441,158 @@ public function testGetMeetings()
$this->assertEquals('12345', $response->getMeetings()[0]->getInternalMeetingId());
$this->assertEquals(1531241258036, $response->getMeetings()[0]->getCreationTime());
$this->assertEquals('Tue Jul 10 16:47:38 UTC 2018', $response->getMeetings()[0]->getCreationDate());
- $this->assertEquals('70066', $response->getMeetings()[0]->getVoiceBridge());
+ $this->assertEquals(70066, $response->getMeetings()[0]->getVoiceBridge());
$this->assertEquals('613-555-1234', $response->getMeetings()[0]->getDialNumber());
- $this->assertEquals('ap', $response->getMeetings()[0]->getAttendeePassword());
- $this->assertEquals('mp', $response->getMeetings()[0]->getModeratorPassword());
$this->assertFalse($response->getMeetings()[0]->isRunning());
$this->assertEquals(0, $response->getMeetings()[0]->getDuration());
$this->assertFalse($response->getMeetings()[0]->hasUserJoined());
}
- /* Get meeting info */
+ /* Get recordings */
- public function testGetRecordingsUrl()
+ public function testGetRecordingsUrl(): void
{
$url = $this->bbb->getRecordingsUrl(new GetRecordingsParameters());
- $this->assertStringContainsString(ApiMethod::GET_RECORDINGS, $url);
+ $this->assertStringContainsString(ApiMethod::GET_RECORDINGS->value, $url);
}
- public function testPublishRecordingsUrl()
+ public function testGetRecordings(): void
+ {
+ $xml = '
+ SUCCESS
+
+
+ f71d810b6e90a4a34ae02b8c7143e8733178578e-1462807897120
+ 9d287cf50490ca856ca5273bd303a7e321df6051-4-119
+ c654308ef4b71eeb74eb8436dc52a31415d9a911-1724671588959
+
+ true
+ published
+ 1462807897120
+ 1462812873004
+
+
+
+
+
+
+
+
+
+
+
+
+
+ presentation
+ http://test-install.blindsidenetworks.com/playback/presentation/0.9.0/playback.html?meetingId=f71d810b6e90a4a34ae02b8c7143e8733178578e-1462807897120
+ 44
+
+
+
+
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $response = $this->bbb->getRecordings(new GetRecordingsParameters());
+
+ $this->assertCount(1, $response->getRecords());
+ $recording = $response->getRecords()[0];
+ $this->assertEquals('f71d810b6e90a4a34ae02b8c7143e8733178578e-1462807897120', $recording->getRecordID());
+ $this->assertEquals('9d287cf50490ca856ca5273bd303a7e321df6051-4-119', $recording->getMeetingID());
+ $this->assertEquals('c654308ef4b71eeb74eb8436dc52a31415d9a911-1724671588959', $recording->getInternalMeetingID());
+ $this->assertEquals('SAT- Writing-Humanities (All participants)', $recording->getName());
+ }
+
+ /* Publish recordings */
+
+ public function testPublishRecordingsUrl(): void
{
$url = $this->bbb->getPublishRecordingsUrl(new PublishRecordingsParameters($this->faker->sha1, true));
- $this->assertStringContainsString(ApiMethod::PUBLISH_RECORDINGS, $url);
+ $this->assertStringContainsString(ApiMethod::PUBLISH_RECORDINGS->value, $url);
+ }
+
+ public function testPublishRecordings(): void
+ {
+ $xml = '
+ SUCCESS
+ true
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $result = $this->bbb->publishRecordings(new PublishRecordingsParameters($this->faker->sha1, true));
+
+ $this->assertTrue($result->isPublished());
}
- public function testDeleteRecordingsUrl()
+ /* Delete recordings */
+
+ public function testDeleteRecordingsUrl(): void
{
$url = $this->bbb->getDeleteRecordingsUrl(new DeleteRecordingsParameters($this->faker->sha1));
- $this->assertStringContainsString(ApiMethod::DELETE_RECORDINGS, $url);
+ $this->assertStringContainsString(ApiMethod::DELETE_RECORDINGS->value, $url);
}
- public function testUpdateRecordingsUrl()
+ public function testDeleteRecordings(): void
+ {
+ $xml = '
+ SUCCESS
+ true
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $result = $this->bbb->deleteRecordings(new DeleteRecordingsParameters($this->faker->sha1));
+
+ $this->assertTrue($result->isDeleted());
+ }
+
+ /* Update recordings */
+
+ public function testUpdateRecordingsUrl(): void
{
$params = $this->generateUpdateRecordingsParams();
$url = $this->bbb->getUpdateRecordingsUrl($this->getUpdateRecordingsParamsMock($params));
- foreach ($params as $key => $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
- $this->assertStringContainsString(rawurlencode($key).'='.rawurlencode($value), $url);
- }
+
+ $this->assertUrlContainsAllRequestParameters($url, $params);
+ }
+
+ public function testUpdateRecordings(): void
+ {
+ $params = $this->generateUpdateRecordingsParams();
+
+ $xml = '
+ SUCCESS
+ true
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $result = $this->bbb->updateRecordings($this->getUpdateRecordingsParamsMock($params));
+
+ $this->assertTrue($result->isUpdated());
}
public function testBuildUrl(): void
{
- $bigBlueButton = new BigBlueButton('https://bbb.example/bigbluebutton/', 'S3cr3t');
+ // Test with default hash algorithm (sha1)
+ $bigBlueButton = new BigBlueButton('https://bbb.example/bigbluebutton/', 'S3cr3t', null, HashingAlgorithm::SHA_1);
$this->assertSame(
'https://bbb.example/bigbluebutton/api/foo?foo=bar&baz=bazinga&checksum=694ad46bc5a79a572bab6c8b9a939527c39ac7f6',
$bigBlueButton->buildUrl('foo', 'foo=bar&baz=bazinga'),
'URL is not ok'
);
+
+ // Test with different hash algorithm (sha256)
+ $bigBlueButton = new BigBlueButton('https://bbb.example/bigbluebutton/', 'S3cr3t', null, HashingAlgorithm::SHA_256);
+
+ $this->assertSame(
+ 'https://bbb.example/bigbluebutton/api/foo?foo=bar&baz=bazinga&checksum=0ce0d779a8220be9824c7eab055b36b59ac504ba899a76d7c528b8473960025e',
+ $bigBlueButton->buildUrl('foo', 'foo=bar&baz=bazinga'),
+ 'URL is not ok'
+ );
}
public function testGetInsertDocument(): void
@@ -372,4 +607,178 @@ public function testGetInsertDocument(): void
$this->assertTrue($response->success());
}
+
+ public function testGetRecordingTextTracks(): void
+ {
+ $params = new GetRecordingTextTracksParameters('foobar');
+
+ $json = '{
+ "response": {
+ "returncode": "SUCCESS",
+ "tracks": [
+ {
+ "href": "https://captions.example.com/textTrack/0ab39e419c9bcb63233168daefe390f232c71343/183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1554230749920/subtitles_en-US.vtt",
+ "kind": "subtitles",
+ "label": "English",
+ "lang": "en-US",
+ "source": "upload"
+ },
+ {
+ "href": "https://captions.example.com/textTrack/95b62d1b762700b9d5366a9e71d5fcc5086f2723/183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1554230749920/subtitles_pt-BR.vtt",
+ "kind": "subtitles",
+ "label": "Brazil",
+ "lang": "pt-BR",
+ "source": "upload"
+ }
+ ]
+ }
+ }';
+ $this->transport->method('request')->willReturn(new TransportResponse($json, null));
+
+ $response = $this->bbb->getRecordingTextTracks($params);
+
+ $this->assertTrue($response->success());
+ $this->assertSame('SUCCESS', $response->getReturnCode());
+
+ $tracks = $response->getTracks();
+ $this->assertCount(2, $tracks);
+ $this->assertArrayHasKey(0, $tracks);
+ $this->assertArrayHasKey(1, $tracks);
+
+ $this->assertSame('https://captions.example.com/textTrack/0ab39e419c9bcb63233168daefe390f232c71343/183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1554230749920/subtitles_en-US.vtt', $tracks[0]->getHref());
+ $this->assertSame('subtitles', $tracks[0]->getKind());
+ $this->assertSame('English', $tracks[0]->getLabel());
+ $this->assertSame('en-US', $tracks[0]->getLang());
+ $this->assertSame('upload', $tracks[0]->getSource());
+
+ $this->assertSame('https://captions.example.com/textTrack/95b62d1b762700b9d5366a9e71d5fcc5086f2723/183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1554230749920/subtitles_pt-BR.vtt', $tracks[1]->getHref());
+ $this->assertSame('subtitles', $tracks[1]->getKind());
+ $this->assertSame('Brazil', $tracks[1]->getLabel());
+ $this->assertSame('pt-BR', $tracks[1]->getLang());
+ $this->assertSame('upload', $tracks[1]->getSource());
+ }
+
+ public function testPutRecordingTextTrack(): void
+ {
+ $params = new PutRecordingTextTrackParameters('foobar', 'subtitles', 'en-US', 'English');
+
+ $json = '{
+ "response": {
+ "messageKey": "upload_text_track_success",
+ "message": "Text track uploaded successfully",
+ "recordId": "baz",
+ "returncode": "SUCCESS"
+ }
+ }';
+ $this->transport->method('request')->willReturn(new TransportResponse($json, null));
+
+ $response = $this->bbb->putRecordingTextTrack($params);
+
+ $this->assertTrue($response->success());
+ $this->assertEquals('upload_text_track_success', $response->getMessageKey());
+ $this->assertEquals('Text track uploaded successfully', $response->getMessage());
+ $this->assertSame('baz', $response->getRecordID());
+ $this->assertSame('SUCCESS', $response->getReturnCode());
+ }
+
+ public function testHooksCreate(): void
+ {
+ $params = new HooksCreateParameters($this->faker->url);
+
+ $xml = '
+ SUCCESS
+ 1
+ false
+ false
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $response = $this->bbb->hooksCreate($params);
+
+ $this->assertTrue($response->success());
+ $this->assertSame(1, $response->getHookId());
+ $this->assertFalse($response->isPermanentHook());
+ $this->assertFalse($response->hasRawData());
+ }
+
+ public function testHooksList(): void
+ {
+ $params = new HooksListParameters();
+
+ $xml = '
+ SUCCESS
+
+
+ 1
+
+
+ false
+ false
+
+
+ 2
+
+ false
+ false
+
+
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $response = $this->bbb->hooksList($params);
+
+ $this->assertTrue($response->success());
+ $this->assertCount(2, $response->getHooks());
+
+ // Hook for a single meeting
+ $meetingHook = $response->getHooks()[0];
+ $this->assertSame(1, $meetingHook->getHookId());
+ $this->assertSame('http://postcatcher.in/catchers/abcdefghijk', $meetingHook->getCallbackURL());
+ $this->assertSame('my-meeting', $meetingHook->getMeetingID());
+ $this->assertFalse($meetingHook->isPermanentHook());
+ $this->assertFalse($meetingHook->hasRawData());
+
+ // Global hook
+ $globalHook = $response->getHooks()[1];
+ $this->assertSame(2, $globalHook->getHookId());
+ $this->assertSame('http://postcatcher.in/catchers/1234567890', $globalHook->getCallbackURL());
+ $this->assertFalse($globalHook->isPermanentHook());
+ $this->assertFalse($globalHook->hasRawData());
+ }
+
+ public function testHooksListUrl(): void
+ {
+ // Test without meeting ID
+ $params = new HooksListParameters();
+ $url = $this->bbb->getHooksListUrl($params);
+
+ $this->assertStringContainsString(ApiMethod::HOOKS_LIST->value, $url);
+ $this->assertStringNotContainsString('meetingID=', $url);
+
+ // Test with meeting ID
+ $params = new HooksListParameters();
+ $params->setMeetingID('foobar');
+ $url = $this->bbb->getHooksListUrl($params);
+
+ $this->assertStringContainsString('meetingID=foobar', $url);
+ }
+
+ public function testHookDestroy(): void
+ {
+ $params = new HooksDestroyParameters('1');
+
+ $xml = '
+ SUCCESS
+ true
+ ';
+
+ $this->transport->method('request')->willReturn(new TransportResponse($xml, null));
+
+ $response = $this->bbb->hooksDestroy($params);
+
+ $this->assertTrue($response->success());
+ $this->assertTrue($response->removed());
+ }
}
diff --git a/tests/unit/Http/SetCookieTest.php b/tests/unit/Http/SetCookieTest.php
index 588ae033..8ad3a0c8 100644
--- a/tests/unit/Http/SetCookieTest.php
+++ b/tests/unit/Http/SetCookieTest.php
@@ -24,8 +24,9 @@
* THE SOFTWARE.
*/
-namespace BigBlueButton\Http;
+namespace BigBlueButton\Tests\Unit\Http;
+use BigBlueButton\Http\SetCookie;
use PHPUnit\Framework\TestCase;
/**
@@ -148,6 +149,7 @@ public function testMatchesDomain(): void
self::assertFalse($cookie->matchesDomain('example.com'));
}
+ /** @return array> */
public function pathMatchProvider(): array
{
return [
@@ -179,6 +181,7 @@ public function testMatchesPath(string $cookiePath, string $requestPath, bool $i
self::assertSame($isMatch, $cookie->matchesPath($requestPath));
}
+ /** @return array> */
public function cookieValidateProvider(): array
{
return [
@@ -234,6 +237,8 @@ public function testConvertsToString(): void
/**
* Provides the parsed information from a cookie.
+ *
+ * @return array
*/
public function cookieParserDataProvider(): array
{
@@ -392,9 +397,10 @@ public function cookieParserDataProvider(): array
/**
* @dataProvider cookieParserDataProvider
*
- * @param string|array $cookie
+ * @param array|string $cookie
+ * @param array $parsed
*/
- public function testParseCookie($cookie, array $parsed): void
+ public function testParseCookie(array|string $cookie, array $parsed): void
{
foreach ((array) $cookie as $v) {
$c = SetCookie::fromString($v);
@@ -402,7 +408,7 @@ public function testParseCookie($cookie, array $parsed): void
if (isset($p['Expires'])) {
$delta = 40;
- $parsedExpires = is_numeric($parsed['Expires']) ? $parsed['Expires'] : strtotime($parsed['Expires']);
+ $parsedExpires = is_numeric($parsed['Expires']) ? $parsed['Expires'] : strtotime((string) $parsed['Expires']);
self::assertLessThan($delta, abs($p['Expires'] - $parsedExpires), 'Comparing Expires '.var_export($p['Expires'], true).' : '.var_export($parsed, true).' | '.var_export($p, true));
unset($p['Expires']);
unset($parsed['Expires']);
@@ -433,6 +439,8 @@ public function testParseCookie($cookie, array $parsed): void
/**
* Provides the data for testing isExpired.
+ *
+ * @return array>
*/
public function isExpiredProvider(): array
{
diff --git a/tests/unit/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransportTest.php b/tests/unit/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransportTest.php
index 73d97637..093d23cb 100644
--- a/tests/unit/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransportTest.php
+++ b/tests/unit/Http/Transport/Bridge/PsrHttpClient/PsrHttpClientTransportTest.php
@@ -19,10 +19,11 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http\Transport\Bridge\PsrHttpClient;
+namespace BigBlueButton\Tests\Unit\Http\Transport\Bridge\PsrHttpClient;
use BigBlueButton\Exceptions\NetworkException;
use BigBlueButton\Exceptions\RuntimeException;
+use BigBlueButton\Http\Transport\Bridge\PsrHttpClient\PsrHttpClientTransport;
use BigBlueButton\Http\Transport\TransportRequest;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
@@ -43,28 +44,22 @@
*/
final class PsrHttpClientTransportTest extends TestCase
{
- /**
- * @var PsrHttpClientTransport
- */
- private $transport;
+ private PsrHttpClientTransport $transport;
/**
* @var MockObject&ClientInterface
*/
- private $httpClientMock;
+ private ?MockObject $httpClientMock = null;
/**
* @var MockObject&RequestFactoryInterface
*/
- private $requestFactoryMock;
+ private ?MockObject $requestFactoryMock = null;
/**
* @var MockObject&StreamFactoryInterface
*/
- private $streamFactoryMock;
+ private ?MockObject $streamFactoryMock = null;
- /**
- * {@inheritDoc}
- */
protected function setUp(): void
{
$this->transport = $this->createTransport();
@@ -203,6 +198,7 @@ public function testRequestWithClientException(): void
$this->transport->request($request);
}
+ /** @return iterable> */
public function provideBadResponseCodes(): iterable
{
foreach (range(100, 199) as $badCode) {
diff --git a/tests/unit/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransportTest.php b/tests/unit/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransportTest.php
index 34c1f9a0..740596ce 100644
--- a/tests/unit/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransportTest.php
+++ b/tests/unit/Http/Transport/Bridge/SymfonyHttpClient/SymfonyHttpClientTransportTest.php
@@ -19,10 +19,11 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http\Transport\Bridge\SymfonyHttpClient;
+namespace BigBlueButton\Tests\Unit\Http\Transport\Bridge\SymfonyHttpClient;
use BigBlueButton\Exceptions\NetworkException;
use BigBlueButton\Exceptions\RuntimeException;
+use BigBlueButton\Http\Transport\Bridge\SymfonyHttpClient\SymfonyHttpClientTransport;
use BigBlueButton\Http\Transport\TransportRequest;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\Exception\TransportException;
@@ -200,6 +201,7 @@ public function testRequestWithDefaultOptions(): void
}
}
+ /** @return iterable> */
public function provideBadResponseCodes(): iterable
{
foreach (range(100, 199) as $badCode) {
@@ -241,6 +243,7 @@ public function testRequestWithBadResponseCode(int $badCode): void
}
}
+ /** @return iterable> */
public function provideBadResponseExceptions(): iterable
{
yield 'Client exception' => [new FakeClientException(), 400];
diff --git a/tests/unit/Http/Transport/CookieTest.php b/tests/unit/Http/Transport/CookieTest.php
index aab7cd0e..5b131aa6 100644
--- a/tests/unit/Http/Transport/CookieTest.php
+++ b/tests/unit/Http/Transport/CookieTest.php
@@ -19,8 +19,9 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http\Transport;
+namespace BigBlueButton\Tests\Unit\Http\Transport;
+use BigBlueButton\Http\Transport\Cookie;
use PHPUnit\Framework\TestCase;
/**
diff --git a/tests/unit/Http/Transport/HeaderTest.php b/tests/unit/Http/Transport/HeaderTest.php
index 70abb5d5..d823c559 100644
--- a/tests/unit/Http/Transport/HeaderTest.php
+++ b/tests/unit/Http/Transport/HeaderTest.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace BigBlueButton\Http;
+namespace BigBlueButton\Tests\Unit\Http;
/**
* This file is part of littleredbutton/bigbluebutton-api-php.
@@ -21,7 +21,7 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http;
+namespace BigBlueButton\Tests\Unit\Http\Transport;
use BigBlueButton\Http\Transport\Header;
use PHPUnit\Framework\TestCase;
@@ -61,7 +61,7 @@ public function provideBadlyFormattedHeaders(): iterable
public function testMergeCurlHeadersWithBadHeaders(string $badHeader): void
{
$this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage(sprintf('Header value "%s" is invalid. Expected format is "Header-Name: value".', $badHeader));
+ $this->expectExceptionMessage(\sprintf('Header value "%s" is invalid. Expected format is "Header-Name: value".', $badHeader));
Header::mergeCurlHeaders([$badHeader]);
}
@@ -78,15 +78,13 @@ public function provideNonStringHeaders(): iterable
/**
* @dataProvider provideNonStringHeaders
- *
- * @param mixed $badHeader
*/
- public function testMergeCurlHeadersWithNonStringHeaders($badHeader): void
+ public function testMergeCurlHeadersWithNonStringHeaders(mixed $badHeader): void
{
$this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage(sprintf(
+ $this->expectExceptionMessage(\sprintf(
'Non-string header with type "%s" passed.',
- \is_object($badHeader) ? \get_class($badHeader) : \gettype($badHeader)
+ get_debug_type($badHeader)
));
Header::mergeCurlHeaders([$badHeader]);
diff --git a/tests/unit/Http/Transport/TransportRequestTest.php b/tests/unit/Http/Transport/TransportRequestTest.php
index ec9a728f..4ec702a1 100644
--- a/tests/unit/Http/Transport/TransportRequestTest.php
+++ b/tests/unit/Http/Transport/TransportRequestTest.php
@@ -19,7 +19,7 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http;
+namespace BigBlueButton\Tests\Unit\Http;
use BigBlueButton\Http\Transport\TransportRequest;
use PHPUnit\Framework\TestCase;
diff --git a/tests/unit/Http/Transport/TransportResponseTest.php b/tests/unit/Http/Transport/TransportResponseTest.php
index 5ab01bdc..adf293bd 100644
--- a/tests/unit/Http/Transport/TransportResponseTest.php
+++ b/tests/unit/Http/Transport/TransportResponseTest.php
@@ -19,8 +19,9 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Http\Transport;
+namespace BigBlueButton\Tests\Unit\Http\Transport;
+use BigBlueButton\Http\Transport\TransportResponse;
use PHPUnit\Framework\TestCase;
/**
diff --git a/tests/unit/Parameters/BaseParametersTest.php b/tests/unit/Parameters/BaseParametersTest.php
index 9a430c7f..9645f10b 100644
--- a/tests/unit/Parameters/BaseParametersTest.php
+++ b/tests/unit/Parameters/BaseParametersTest.php
@@ -19,8 +19,9 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
+use BigBlueButton\Parameters\BaseParameters;
use PHPUnit\Framework\TestCase;
final class BaseParametersTest extends TestCase
@@ -54,6 +55,17 @@ public function testSetterWithInvalid(): void
$params->setInvalid('foobar');
}
+
+ public function testEnum(): void
+ {
+ $params = new TestEnumParameters();
+
+ $params->setEnum('one');
+ $this->assertSame(TestEnum::ONE, $params->getEnum());
+
+ $params->setEnum('two');
+ $this->assertSame(TestEnum::TWO, $params->getEnum());
+ }
}
/**
@@ -65,5 +77,22 @@ public function testSetterWithInvalid(): void
*/
final class TestParameters extends BaseParameters
{
- protected $notABool = 'string';
+ protected string $notABool = 'string';
+}
+
+/**
+ * @internal
+ *
+ * @method self setEnum(TestEnum|string $enum)
+ * @method TestEnum getEnum()
+ */
+final class TestEnumParameters extends BaseParameters
+{
+ protected ?TestEnum $enum = null;
+}
+
+enum TestEnum: string
+{
+ case ONE = 'one';
+ case TWO = 'two';
}
diff --git a/tests/unit/Parameters/CreateMeetingParametersTest.php b/tests/unit/Parameters/CreateMeetingParametersTest.php
index e951e777..be94bead 100644
--- a/tests/unit/Parameters/CreateMeetingParametersTest.php
+++ b/tests/unit/Parameters/CreateMeetingParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\Core\GuestPolicy;
-use BigBlueButton\TestCase;
-use PHPUnit\Framework\Error\Warning;
+use BigBlueButton\Enum\Feature;
+use BigBlueButton\Enum\GuestPolicy;
+use BigBlueButton\Parameters\CreateMeetingParameters;
+use BigBlueButton\Tests\Common\TestCase;
/**
* Class CreateMeetingParametersTest.
*/
-class CreateMeetingParametersTest extends TestCase
+final class CreateMeetingParametersTest extends TestCase
{
- public function testCreateMeetingParameters()
+ public function testCreateMeetingParameters(): void
{
$params = $this->generateCreateParams();
$createMeetingParams = $this->getCreateMock($params);
$this->assertEquals($params['name'], $createMeetingParams->getName());
$this->assertEquals($params['meetingID'], $createMeetingParams->getMeetingID());
- $this->assertEquals($params['attendeePW'], $createMeetingParams->getAttendeePW());
- $this->assertEquals($params['moderatorPW'], $createMeetingParams->getModeratorPW());
$this->assertEquals($params['autoStartRecording'], $createMeetingParams->isAutoStartRecording());
$this->assertEquals($params['dialNumber'], $createMeetingParams->getDialNumber());
$this->assertEquals($params['voiceBridge'], $createMeetingParams->getVoiceBridge());
@@ -49,6 +51,7 @@ public function testCreateMeetingParameters()
$this->assertEquals($params['moderatorOnlyMessage'], $createMeetingParams->getModeratorOnlyMessage());
$this->assertEquals($params['webcamsOnlyForModerator'], $createMeetingParams->isWebcamsOnlyForModerator());
$this->assertEquals($params['logo'], $createMeetingParams->getLogo());
+ $this->assertEquals($params['darklogo'], $createMeetingParams->getDarklogo());
$this->assertEquals($params['copyright'], $createMeetingParams->getCopyright());
$this->assertEquals($params['muteOnStart'], $createMeetingParams->isMuteOnStart());
$this->assertEquals($params['guestPolicy'], $createMeetingParams->getGuestPolicy());
@@ -56,19 +59,18 @@ public function testCreateMeetingParameters()
$this->assertEquals($params['lockSettingsDisableMic'], $createMeetingParams->isLockSettingsDisableMic());
$this->assertEquals($params['lockSettingsDisablePrivateChat'], $createMeetingParams->isLockSettingsDisablePrivateChat());
$this->assertEquals($params['lockSettingsDisablePublicChat'], $createMeetingParams->isLockSettingsDisablePublicChat());
- $this->assertEquals($params['lockSettingsDisableNote'], $createMeetingParams->isLockSettingsDisableNote());
+ $this->assertEquals($params['lockSettingsDisableNotes'], $createMeetingParams->isLockSettingsDisableNotes());
$this->assertEquals($params['lockSettingsLockedLayout'], $createMeetingParams->isLockSettingsLockedLayout());
$this->assertEquals($params['lockSettingsHideUserList'], $createMeetingParams->isLockSettingsHideUserList());
$this->assertEquals($params['lockSettingsLockOnJoin'], $createMeetingParams->isLockSettingsLockOnJoin());
$this->assertEquals($params['lockSettingsLockOnJoinConfigurable'], $createMeetingParams->isLockSettingsLockOnJoinConfigurable());
$this->assertEquals($params['allowModsToUnmuteUsers'], $createMeetingParams->isAllowModsToUnmuteUsers());
$this->assertEquals($params['allowModsToEjectCameras'], $createMeetingParams->isAllowModsToEjectCameras());
+ $this->assertEquals($params['allowPromoteGuestToModerator'], $createMeetingParams->isAllowPromoteGuestToModerator());
$this->assertEquals($params['guestPolicy'], $createMeetingParams->getGuestPolicy());
$this->assertEquals($params['endWhenNoModerator'], $createMeetingParams->isEndWhenNoModerator());
$this->assertEquals($params['endWhenNoModeratorDelayInMinutes'], $createMeetingParams->getEndWhenNoModeratorDelayInMinutes());
- $this->assertEquals($params['learningDashboardEnabled'], $createMeetingParams->isLearningDashboardEnabled());
$this->assertEquals($params['learningDashboardCleanupDelayInMinutes'], $createMeetingParams->getLearningDashboardCleanupDelayInMinutes());
- $this->assertEquals($params['breakoutRoomsEnabled'], $createMeetingParams->isBreakoutRoomsEnabled());
$this->assertEquals($params['breakoutRoomsRecord'], $createMeetingParams->isBreakoutRoomsRecord());
$this->assertEquals($params['breakoutRoomsPrivateChatEnabled'], $createMeetingParams->isBreakoutRoomsPrivateChatEnabled());
$this->assertEquals($params['meetingEndedURL'], $createMeetingParams->getMeetingEndedURL());
@@ -82,14 +84,14 @@ public function testCreateMeetingParameters()
$this->assertEquals($params['endWhenNoModerator'], $createMeetingParams->isEndWhenNoModerator());
$this->assertEquals($params['endWhenNoModeratorDelayInMinutes'], $createMeetingParams->getEndWhenNoModeratorDelayInMinutes());
$this->assertEquals($params['meetingLayout'], $createMeetingParams->getMeetingLayout());
- $this->assertEquals($params['learningDashboardEnabled'], $createMeetingParams->isLearningDashboardEnabled());
$this->assertEquals($params['learningDashboardCleanupDelayInMinutes'], $createMeetingParams->getLearningDashboardCleanupDelayInMinutes());
$this->assertEquals($params['allowModsToEjectCameras'], $createMeetingParams->isAllowModsToEjectCameras());
- $this->assertEquals($params['breakoutRoomsEnabled'], $createMeetingParams->isBreakoutRoomsEnabled());
$this->assertEquals($params['breakoutRoomsPrivateChatEnabled'], $createMeetingParams->isBreakoutRoomsPrivateChatEnabled());
$this->assertEquals($params['breakoutRoomsRecord'], $createMeetingParams->isBreakoutRoomsRecord());
$this->assertEquals($params['allowRequestsWithoutSession'], $createMeetingParams->isAllowRequestsWithoutSession());
- $this->assertEquals($params['virtualBackgroundsDisabled'], $createMeetingParams->isVirtualBackgroundsDisabled());
+ $this->assertEquals(json_encode($params['groups']), json_encode($createMeetingParams->getBreakoutRoomsGroups()));
+ $this->assertEquals($params['disabledFeatures'], $createMeetingParams->getDisabledFeatures());
+ $this->assertEquals($params['disabledFeaturesExclude'], $createMeetingParams->getDisabledFeaturesExclude());
// Check values are empty of this is not a breakout room
$this->assertNull($createMeetingParams->isBreakout());
@@ -104,7 +106,54 @@ public function testCreateMeetingParameters()
$this->assertEquals($newId, $createMeetingParams->getMeetingID());
}
- public function testCreateBreakoutMeeting()
+ public function testMetaParameters(): void
+ {
+ $params = $this->generateCreateParams();
+ $createMeetingParams = $this->getCreateMock($params);
+ $createMeetingParams->addMeta('userdata-bbb_hide_presentation_on_join', true);
+ $createMeetingParams->addMeta('userdata-bbb_show_participants_on_login', false);
+ $createMeetingParams->addMeta('userdata-bbb_fullaudio_bridge', 'fullaudio');
+
+ // Test getters
+ $this->assertTrue($createMeetingParams->getMeta('userdata-bbb_hide_presentation_on_join'));
+ $this->assertFalse($createMeetingParams->getMeta('userdata-bbb_show_participants_on_login'));
+ $this->assertEquals('fullaudio', $createMeetingParams->getMeta('userdata-bbb_fullaudio_bridge'));
+
+ $params = urldecode($createMeetingParams->getHTTPQuery());
+
+ // Test HTTP query
+ $this->assertStringContainsString('meta_userdata-bbb_hide_presentation_on_join=true', $params);
+ $this->assertStringContainsString('meta_userdata-bbb_show_participants_on_login=false', $params);
+ $this->assertStringContainsString('meta_userdata-bbb_fullaudio_bridge=fullaudio', $params);
+ }
+
+ public function testDisabledFeatures(): void
+ {
+ $params = $this->generateCreateParams();
+ $createMeetingParams = $this->getCreateMock($params);
+
+ // Test empty disabled features
+ $createMeetingParams->setDisabledFeatures([]);
+ $params = urldecode($createMeetingParams->getHTTPQuery());
+ $this->assertStringNotContainsString('disabledFeatures=', $params);
+
+ // Test with multiple disabled features
+ $createMeetingParams->setDisabledFeatures([Feature::CHAT, Feature::POLLS, Feature::CAPTIONS]);
+ $params = urldecode($createMeetingParams->getHTTPQuery());
+ $this->assertStringContainsString('disabledFeatures=chat,polls,captions', $params);
+
+ // Test empty disabled features exclude
+ $createMeetingParams->setDisabledFeaturesExclude([]);
+ $params = urldecode($createMeetingParams->getHTTPQuery());
+ $this->assertStringNotContainsString('disabledFeaturesExclude=', $params);
+
+ // Test with multiple disabled features exclude
+ $createMeetingParams->setDisabledFeaturesExclude([Feature::CHAT, Feature::POLLS]);
+ $params = urldecode($createMeetingParams->getHTTPQuery());
+ $this->assertStringContainsString('disabledFeaturesExclude=chat,polls', $params);
+ }
+
+ public function testCreateBreakoutMeeting(): void
{
$params = $this->generateBreakoutCreateParams($this->generateCreateParams());
$createBreakoutMeetingParams = $this->getBreakoutCreateMock($params);
@@ -117,57 +166,59 @@ public function testCreateBreakoutMeeting()
$this->assertStringContainsString('isBreakout='.rawurlencode($createBreakoutMeetingParams->isBreakout() ? 'true' : 'false'), $params);
$this->assertStringContainsString('parentMeetingID='.rawurlencode($createBreakoutMeetingParams->getParentMeetingID()), $params);
- $this->assertStringContainsString('sequence='.rawurlencode($createBreakoutMeetingParams->getSequence()), $params);
+ $this->assertStringContainsString('sequence='.rawurlencode((string) $createBreakoutMeetingParams->getSequence()), $params);
$this->assertStringContainsString('freeJoin='.rawurlencode($createBreakoutMeetingParams->isFreeJoin() ? 'true' : 'false'), $params);
}
- public function testCreateBreakoutMeetingWithMissingParams()
+ public function testCreateBreakoutMeetingWithMissingParams(): void
{
- $this->expectException(Warning::class);
+ $this->expectException(\RuntimeException::class);
$params = new CreateMeetingParameters($this->faker->uuid, $this->faker->name);
$params->setBreakout(true);
$params->getHTTPQuery();
}
- public function testNonExistingProperty()
+ public function testNonExistingProperty(): void
{
$this->expectException(\BadFunctionCallException::class);
$params = new CreateMeetingParameters($this->faker->uuid, $this->faker->name);
+ /* @phpstan-ignore-next-line */
$params->getFoobar();
}
- public function testWrongMethodName()
+ public function testWrongMethodName(): void
{
$this->expectException(\BadFunctionCallException::class);
$params = new CreateMeetingParameters($this->faker->uuid, $this->faker->name);
+ /* @phpstan-ignore-next-line */
$params->getname();
}
- public function testGetPresentationsAsXMLWithUrl()
+ public function testGetPresentationsAsXMLWithUrl(): void
{
$params = $this->generateCreateParams();
$createMeetingParams = $this->getCreateMock($params);
$createMeetingParams->addPresentation('http://test-install.blindsidenetworks.com/default.pdf');
- $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'presentation_with_url.xml', $createMeetingParams->getPresentationsAsXML());
+ $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'presentation_with_url.xml', $createMeetingParams->getModules());
}
- public function testGetPresentationsAsXMLWithUrlAndFilename()
+ public function testGetPresentationsAsXMLWithUrlAndFilename(): void
{
$params = $this->generateCreateParams();
$createMeetingParams = $this->getCreateMock($params);
$createMeetingParams->addPresentation('http://test-install.blindsidenetworks.com/default.pdf', null, 'presentation.pdf');
- $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'presentation_with_filename.xml', $createMeetingParams->getPresentationsAsXML());
+ $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'presentation_with_filename.xml', $createMeetingParams->getModules());
}
- public function testGetPresentationsAsXMLWithFile()
+ public function testGetPresentationsAsXMLWithFile(): void
{
$params = $this->generateCreateParams();
$createMeetingParams = $this->getCreateMock($params);
$createMeetingParams->addPresentation('bbb_logo.png', file_get_contents(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'bbb_logo.png'));
- $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'presentation_with_embedded_file.xml', $createMeetingParams->getPresentationsAsXML());
+ $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'presentation_with_embedded_file.xml', $createMeetingParams->getModules());
}
public function testUserCameraCap(): void
@@ -221,4 +272,14 @@ public function testGuestPolicyAskModerator(): void
$this->assertSame(GuestPolicy::ASK_MODERATOR, $createMeetingParams->getGuestPolicy());
$this->assertTrue($createMeetingParams->isGuestPolicyAskModerator());
}
+
+ public function testClientSettingsOverride(): void
+ {
+ $params = $this->generateCreateParams();
+ $createMeetingParams = $this->getCreateMock($params);
+
+ $createMeetingParams->setClientSettingsOverride('{ "public": { "app": { "appName": "Test" } } }');
+
+ $this->assertXmlStringEqualsXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'client_settings.xml', $createMeetingParams->getModules());
+ }
}
diff --git a/tests/unit/Parameters/DeleteRecordingsParametersTest.php b/tests/unit/Parameters/DeleteRecordingsParametersTest.php
index b183b1af..1b7e0346 100644
--- a/tests/unit/Parameters/DeleteRecordingsParametersTest.php
+++ b/tests/unit/Parameters/DeleteRecordingsParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\DeleteRecordingsParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class DeleteRecordingsParametersTest extends TestCase
+final class DeleteRecordingsParametersTest extends TestCase
{
- public function testDeleteRecordingParameter()
+ public function testDeleteRecordingParameter(): void
{
$recordingId = $this->faker->uuid;
$deleteRecording = new DeleteRecordingsParameters($recordingId);
diff --git a/tests/unit/Parameters/EndMeetingParametersTest.php b/tests/unit/Parameters/EndMeetingParametersTest.php
index 2873bb0a..45a3693c 100644
--- a/tests/unit/Parameters/EndMeetingParametersTest.php
+++ b/tests/unit/Parameters/EndMeetingParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\EndMeetingParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class EndMeetingParametersTest extends TestCase
+final class EndMeetingParametersTest extends TestCase
{
- public function testEndMeetingParameters()
+ public function testEndMeetingParameters(): void
{
- $endMeetingParams = new EndMeetingParameters($meetingId = $this->faker->uuid, $password = $this->faker->password());
+ $endMeetingParams = new EndMeetingParameters($meetingId = $this->faker->uuid);
$this->assertEquals($meetingId, $endMeetingParams->getMeetingID());
- $this->assertEquals($password, $endMeetingParams->getPassword());
// Test setters that are ignored by the constructor
$endMeetingParams->setMeetingID($newId = $this->faker->uuid);
- $endMeetingParams->setPassword($newPassword = $this->faker->password);
$this->assertEquals($newId, $endMeetingParams->getMeetingID());
- $this->assertEquals($newPassword, $endMeetingParams->getPassword());
}
}
diff --git a/tests/unit/Parameters/GetMeetingInfoParametersTest.php b/tests/unit/Parameters/GetMeetingInfoParametersTest.php
index 192f3205..df6bba99 100644
--- a/tests/unit/Parameters/GetMeetingInfoParametersTest.php
+++ b/tests/unit/Parameters/GetMeetingInfoParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\GetMeetingInfoParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class GetMeetingInfoParametersTest extends TestCase
+final class GetMeetingInfoParametersTest extends TestCase
{
- public function testGetMeetingInfoParameters()
+ public function testGetMeetingInfoParameters(): void
{
$getMeetingInfoParams = new GetMeetingInfoParameters($meetingId = $this->faker->uuid);
diff --git a/tests/unit/Parameters/GetRecordingTextTracksParametersTest.php b/tests/unit/Parameters/GetRecordingTextTracksParametersTest.php
index ae46c8d5..22164b6b 100644
--- a/tests/unit/Parameters/GetRecordingTextTracksParametersTest.php
+++ b/tests/unit/Parameters/GetRecordingTextTracksParametersTest.php
@@ -1,5 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\GetRecordingTextTracksParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class GetRecordingTextTracksParametersTest extends TestCase
+final class GetRecordingTextTracksParametersTest extends TestCase
{
- public function testGetRecordingTextTracksParameters()
+ public function testGetRecordingTextTracksParameters(): void
{
$getRecordingTextTracksParams = new GetRecordingTextTracksParameters($recordId = $this->faker->uuid);
diff --git a/tests/unit/Parameters/GetRecordingsParametersTest.php b/tests/unit/Parameters/GetRecordingsParametersTest.php
index 355c5500..d3967a2d 100644
--- a/tests/unit/Parameters/GetRecordingsParametersTest.php
+++ b/tests/unit/Parameters/GetRecordingsParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\GetRecordingsParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class GetRecordingsParametersTest extends TestCase
+final class GetRecordingsParametersTest extends TestCase
{
- public function testGetRecordingsParameters()
+ public function testGetRecordingsParameters(): void
{
$getRecordings = new GetRecordingsParameters();
$getRecordings->setMeetingID($meetingId = $this->faker->uuid);
diff --git a/tests/unit/Parameters/HooksCreateParametersTest.php b/tests/unit/Parameters/HooksCreateParametersTest.php
index 97769273..f8e344c0 100644
--- a/tests/unit/Parameters/HooksCreateParametersTest.php
+++ b/tests/unit/Parameters/HooksCreateParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\HooksCreateParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class HooksCreateParametersTest extends TestCase
+final class HooksCreateParametersTest extends TestCase
{
- public function testHooksCreateParameters()
+ public function testHooksCreateParameters(): void
{
$hooksCreateParameters = new HooksCreateParameters($callBackUrl = $this->faker->url);
diff --git a/tests/unit/Parameters/HooksDestroyParametersTest.php b/tests/unit/Parameters/HooksDestroyParametersTest.php
index c3e5eddb..aa3ea0ff 100644
--- a/tests/unit/Parameters/HooksDestroyParametersTest.php
+++ b/tests/unit/Parameters/HooksDestroyParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\HooksDestroyParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class HooksDestroyParametersTest extends TestCase
+final class HooksDestroyParametersTest extends TestCase
{
public function testHooksDestroyParameters(): void
{
- $hooksCreateParameters = new HooksDestroyParameters($hookId = $this->faker->numberBetween(1, 50));
+ $hooksCreateParameters = new HooksDestroyParameters((string) $hookId = $this->faker->numberBetween(1, 50));
$this->assertEquals($hookId, $hooksCreateParameters->getHookID());
}
diff --git a/tests/unit/Parameters/HooksListParametersTest.php b/tests/unit/Parameters/HooksListParametersTest.php
new file mode 100644
index 00000000..5aa44d53
--- /dev/null
+++ b/tests/unit/Parameters/HooksListParametersTest.php
@@ -0,0 +1,40 @@
+.
+ */
+
+namespace BigBlueButton\Tests\Unit\Parameters;
+
+use BigBlueButton\Parameters\HooksListParameters;
+use BigBlueButton\Tests\Common\TestCase;
+
+final class HooksListParametersTest extends TestCase
+{
+ public function testHooksListParameters(): void
+ {
+ $hooksListParameters = new HooksListParameters();
+
+ $this->assertNull($hooksListParameters->getMeetingID());
+
+ // Test setters that are ignored by the constructor
+ $hooksListParameters->setMeetingID($meetingId = $this->faker->uuid);
+ $this->assertEquals($meetingId, $hooksListParameters->getMeetingID());
+ }
+}
diff --git a/tests/unit/Parameters/InsertDocumentParametersTest.php b/tests/unit/Parameters/InsertDocumentParametersTest.php
index d7acb3cd..d9bdd361 100644
--- a/tests/unit/Parameters/InsertDocumentParametersTest.php
+++ b/tests/unit/Parameters/InsertDocumentParametersTest.php
@@ -19,20 +19,26 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\InsertDocumentParameters;
+use BigBlueButton\Tests\Common\TestCase;
final class InsertDocumentParametersTest extends TestCase
{
- public function testIsMeetingRunningParameters(): void
+ public function testInsertingDocuments(): void
{
$meetingId = $this->faker->uuid;
$params = new InsertDocumentParameters($meetingId);
+ // Adding presentations
$params->addPresentation('http://localhost/foobar.png', 'Foobar.png');
$params->addPresentation('http://localhost/foobar.pdf', 'Foobar.pdf', true);
$params->addPresentation('http://localhost/foobar.svg', 'Foobar.svg', true, false);
+ $params->addPresentation('http://localhost/demo.pdf', 'Demo.pdf', true);
+
+ // Removing presentation
+ $params->removePresentation('http://localhost/demo.pdf');
$this->assertEquals($meetingId, $params->getMeetingID());
diff --git a/tests/unit/Parameters/IsMeetingRunningParametersTest.php b/tests/unit/Parameters/IsMeetingRunningParametersTest.php
index 9e89b286..3c941408 100644
--- a/tests/unit/Parameters/IsMeetingRunningParametersTest.php
+++ b/tests/unit/Parameters/IsMeetingRunningParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\IsMeetingRunningParameters;
+use BigBlueButton\Tests\Common\TestCase;
/**
* Class IsMeetingRunningParametersTest.
*/
-class IsMeetingRunningParametersTest extends TestCase
+final class IsMeetingRunningParametersTest extends TestCase
{
- public function testIsMeetingRunningParameters()
+ public function testIsMeetingRunningParameters(): void
{
$meetingId = $this->faker->uuid;
$isRunningParams = new IsMeetingRunningParameters($meetingId);
diff --git a/tests/unit/Parameters/JoinMeetingParametersTest.php b/tests/unit/Parameters/JoinMeetingParametersTest.php
index 924ba035..4aa1f16b 100644
--- a/tests/unit/Parameters/JoinMeetingParametersTest.php
+++ b/tests/unit/Parameters/JoinMeetingParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Enum\Role;
+use BigBlueButton\Tests\Common\TestCase;
-class JoinMeetingParametersTest extends TestCase
+final class JoinMeetingParametersTest extends TestCase
{
- public function testJoinMeetingParameters()
+ public function testJoinMeetingParameters(): void
{
$params = $this->generateJoinMeetingParams();
+ $params['role'] = Role::MODERATOR;
$joinMeetingParams = $this->getJoinMeetingMock($params);
$this->assertEquals($params['meetingID'], $joinMeetingParams->getMeetingID());
$this->assertEquals($params['fullName'], $joinMeetingParams->getFullName());
- $this->assertEquals($params['password'], $joinMeetingParams->getPassword());
+ $this->assertEquals($params['role'], $joinMeetingParams->getRole());
$this->assertEquals($params['userID'], $joinMeetingParams->getUserID());
$this->assertEquals($params['webVoiceConf'], $joinMeetingParams->getWebVoiceConf());
$this->assertEquals($params['createTime'], $joinMeetingParams->getCreateTime());
+ $this->assertEquals($params['errorRedirectUrl'], $joinMeetingParams->getErrorRedirectUrl());
$this->assertEquals($params['userdata-countrycode'], $joinMeetingParams->getUserData('countrycode'));
$this->assertEquals($params['userdata-email'], $joinMeetingParams->getUserData('email'));
$this->assertEquals($params['userdata-commercial'], $joinMeetingParams->getUserData('commercial'));
@@ -41,21 +47,21 @@ public function testJoinMeetingParameters()
// Test setters that are ignored by the constructor
$joinMeetingParams->setMeetingID($newId = $this->faker->uuid);
$joinMeetingParams->setFullName($newName = $this->faker->name);
- $joinMeetingParams->setPassword($newPassword = $this->faker->password);
- $joinMeetingParams->setConfigToken($configToken = $this->faker->md5);
+ $joinMeetingParams->setRole($newRole = Role::VIEWER);
$joinMeetingParams->setAvatarURL($avatarUrl = $this->faker->url);
$joinMeetingParams->setRedirect($redirect = $this->faker->boolean(50));
- $joinMeetingParams->setClientURL($clientUrl = $this->faker->url);
- $joinMeetingParams->setJoinViaHtml5($joinViaHtml5 = $this->faker->boolean(50));
+ $joinMeetingParams->setErrorRedirectUrl($newErrorRedirectUrl = $this->faker->url);
$joinMeetingParams->setGuest($guest = $this->faker->boolean(50));
+ $joinMeetingParams->setWebcamBackgroundURL($webcamBackgroundURL = $this->faker->url);
+ $joinMeetingParams->setBot($bot = $this->faker->boolean(50));
$this->assertEquals($newId, $joinMeetingParams->getMeetingID());
$this->assertEquals($newName, $joinMeetingParams->getFullName());
- $this->assertEquals($newPassword, $joinMeetingParams->getPassword());
- $this->assertEquals($configToken, $joinMeetingParams->getConfigToken());
+ $this->assertEquals($newRole, $joinMeetingParams->getRole());
$this->assertEquals($avatarUrl, $joinMeetingParams->getAvatarURL());
$this->assertEquals($redirect, $joinMeetingParams->isRedirect());
- $this->assertEquals($clientUrl, $joinMeetingParams->getClientURL());
- $this->assertEquals($joinViaHtml5, $joinMeetingParams->isJoinViaHtml5());
+ $this->assertEquals($newErrorRedirectUrl, $joinMeetingParams->getErrorRedirectUrl());
$this->assertEquals($guest, $joinMeetingParams->isGuest());
+ $this->assertEquals($webcamBackgroundURL, $joinMeetingParams->getWebcamBackgroundURL());
+ $this->assertEquals($bot, $joinMeetingParams->isBot());
}
}
diff --git a/tests/unit/Parameters/PublishRecordingsParametersTest.php b/tests/unit/Parameters/PublishRecordingsParametersTest.php
index 3abfdf13..95cc3228 100644
--- a/tests/unit/Parameters/PublishRecordingsParametersTest.php
+++ b/tests/unit/Parameters/PublishRecordingsParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\PublishRecordingsParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class PublishRecordingsParametersTest extends TestCase
+final class PublishRecordingsParametersTest extends TestCase
{
- public function testPublishRecordingsParameters()
+ public function testPublishRecordingsParameters(): void
{
$recordingId = $this->faker->uuid;
$publish = $this->faker->boolean(50);
@@ -33,7 +37,7 @@ public function testPublishRecordingsParameters()
$this->assertEquals($publish, $publishRecording->isPublish());
// Test setters that are ignored by the constructor
- $publishRecording->setRecordID($newRecordingId = !$this->faker->uuid);
+ $publishRecording->setRecordID($newRecordingId = $this->faker->uuid);
$publishRecording->setPublish($publish = !$publish);
$this->assertEquals($newRecordingId, $publishRecording->getRecordID());
$this->assertEquals($publish, $publishRecording->isPublish());
diff --git a/tests/unit/Parameters/PutRecordingTextTracksParametersTest.php b/tests/unit/Parameters/PutRecordingTextTracksParametersTest.php
index 454cdffb..0e02f5b8 100644
--- a/tests/unit/Parameters/PutRecordingTextTracksParametersTest.php
+++ b/tests/unit/Parameters/PutRecordingTextTracksParametersTest.php
@@ -1,5 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Parameters\PutRecordingTextTrackParameters;
+use BigBlueButton\Tests\Common\TestCase;
-class PutRecordingTextTracksParametersTest extends TestCase
+final class PutRecordingTextTracksParametersTest extends TestCase
{
- public function testPutRecordingTextTracksParameters()
+ public function testPutRecordingTextTracksParameters(): void
{
$getRecordingTextTracksParams = new PutRecordingTextTrackParameters(
$recordId = $this->faker->uuid,
diff --git a/tests/unit/Parameters/UpdateRecordingsParametersTest.php b/tests/unit/Parameters/UpdateRecordingsParametersTest.php
index ad36c198..8f4eafa5 100644
--- a/tests/unit/Parameters/UpdateRecordingsParametersTest.php
+++ b/tests/unit/Parameters/UpdateRecordingsParametersTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Parameters;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class UpdateRecordingsParametersTest extends TestCase
+final class UpdateRecordingsParametersTest extends TestCase
{
- public function testUpdateRecordingsParameters()
+ public function testUpdateRecordingsParameters(): void
{
$params = $this->generateUpdateRecordingsParams();
$updateRecordingsParams = $this->getUpdateRecordingsParamsMock($params);
diff --git a/tests/unit/Responses/ApiVersionResponseTest.php b/tests/unit/Responses/ApiVersionResponseTest.php
index 7f59a122..a43c8401 100644
--- a/tests/unit/Responses/ApiVersionResponseTest.php
+++ b/tests/unit/Responses/ApiVersionResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\ApiVersionResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class ApiVersionResponseTest extends TestCase
+final class ApiVersionResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\ApiVersionResponse
- */
- private $version;
+ private ApiVersionResponse $version;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->version = new ApiVersionResponse($xml);
}
- public function testApiVersionResponseContent()
+ public function testApiVersionResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->version->getReturnCode());
$this->assertEquals('2.0', $this->version->getVersion());
@@ -46,7 +46,7 @@ public function testApiVersionResponseContent()
$this->assertEquals('2.4-rc-7', $this->version->getBbbVersion());
}
- public function testApiVersionResponseTypes()
+ public function testApiVersionResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->version, ['getReturnCode', 'getVersion', 'getApiVersion', 'getBbbVersion']);
}
diff --git a/tests/unit/Responses/CreateMeetingResponseTest.php b/tests/unit/Responses/CreateMeetingResponseTest.php
index 84198494..6d5d40f2 100644
--- a/tests/unit/Responses/CreateMeetingResponseTest.php
+++ b/tests/unit/Responses/CreateMeetingResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\CreateMeetingResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class CreateMeetingResponseTest extends TestCase
+final class CreateMeetingResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\CreateMeetingResponse
- */
- private $meeting;
+ private CreateMeetingResponse $meeting;
protected function setUp(): void
{
@@ -38,14 +38,15 @@ protected function setUp(): void
$this->meeting = new CreateMeetingResponse($xml);
}
- public function testCreateMeetingResponseContent()
+ public function testCreateMeetingResponseContent(): void
{
+ $this->assertTrue($this->meeting->success());
+ $this->assertFalse($this->meeting->failed());
$this->assertEquals('SUCCESS', $this->meeting->getReturnCode());
+
$this->assertEquals('random-1665177', $this->meeting->getMeetingId());
$this->assertEquals('1a6938c707cdf5d052958672d66c219c30690c47-1524212045514', $this->meeting->getInternalMeetingId());
$this->assertEquals('bbb-none', $this->meeting->getParentMeetingId());
- $this->assertEquals('tK6J5cJv3hMLNx5IBePa', $this->meeting->getAttendeePassword());
- $this->assertEquals('34Heu0uiZYqCZXX9C4m2', $this->meeting->getModeratorPassword());
$this->assertEquals(1453283819419, $this->meeting->getCreationTime());
$this->assertEquals(76286, $this->meeting->getVoiceBridge());
$this->assertEquals('Wed Jan 20 04:56:59 EST 2016', $this->meeting->getCreationDate());
@@ -54,15 +55,33 @@ public function testCreateMeetingResponseContent()
$this->assertEquals(20, $this->meeting->getDuration());
$this->assertFalse($this->meeting->hasBeenForciblyEnded());
$this->assertEquals('duplicateWarning', $this->meeting->getMessageKey());
+ $this->assertTrue($this->meeting->isDuplicate());
$this->assertEquals('This conference was already in existence and may currently be in progress.', $this->meeting->getMessage());
+
+ $this->assertFalse($this->meeting->isIdNotUnique());
}
- public function testCreateMeetingResponseTypes()
+ public function testCreateMeetingResponseTypes(): void
{
- $this->assertEachGetterValueIsString($this->meeting, ['getReturnCode', 'getInternalMeetingId', 'getParentMeetingId',
- 'getAttendeePassword', 'getModeratorPassword', 'getDialNumber', 'getCreationDate', ]);
+ $this->assertEachGetterValueIsString($this->meeting, [
+ 'getReturnCode', 'getInternalMeetingId', 'getParentMeetingId',
+ 'getDialNumber', 'getCreationDate',
+ ]);
$this->assertEachGetterValueIsDouble($this->meeting, ['getCreationTime']);
$this->assertEachGetterValueIsInteger($this->meeting, ['getDuration', 'getVoiceBridge']);
$this->assertEachGetterValueIsBoolean($this->meeting, ['hasUserJoined', 'hasBeenForciblyEnded']);
}
+
+ public function testIdNotUnique(): void
+ {
+ $xml = $this->loadXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'create_meeting_not_unique_error.xml');
+
+ $meeting = new CreateMeetingResponse($xml);
+
+ $this->assertFalse($meeting->success());
+ $this->assertTrue($meeting->failed());
+ $this->assertEquals('FAILED', $meeting->getReturnCode());
+
+ $this->assertTrue($meeting->isIdNotUnique());
+ }
}
diff --git a/tests/unit/Responses/DeleteRecordingsResponseTest.php b/tests/unit/Responses/DeleteRecordingsResponseTest.php
index ae7416f5..39c9be87 100644
--- a/tests/unit/Responses/DeleteRecordingsResponseTest.php
+++ b/tests/unit/Responses/DeleteRecordingsResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\DeleteRecordingsResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class DeleteRecordingsResponseTest extends TestCase
+final class DeleteRecordingsResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\DeleteRecordingsResponse
- */
- private $delete;
+ private DeleteRecordingsResponse $delete;
protected function setUp(): void
{
@@ -38,15 +38,25 @@ protected function setUp(): void
$this->delete = new DeleteRecordingsResponse($xml);
}
- public function testDeleteRecordingsResponseContent()
+ public function testDeleteRecordingsResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->delete->getReturnCode());
$this->assertTrue($this->delete->isDeleted());
}
- public function testDeleteRecordingsResponseTypes()
+ public function testDeleteRecordingsResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->delete, ['getReturnCode']);
$this->assertEachGetterValueIsBoolean($this->delete, ['isDeleted']);
}
+
+ public function testNotFoundError(): void
+ {
+ $xml = $this->loadXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'not_found_error.xml');
+
+ $delete = new DeleteRecordingsResponse($xml);
+
+ $this->assertTrue($delete->failed());
+ $this->assertTrue($delete->isNotFound());
+ }
}
diff --git a/tests/unit/Responses/EndMeetingResponseTest.php b/tests/unit/Responses/EndMeetingResponseTest.php
index 37ecefb9..1e1300e1 100644
--- a/tests/unit/Responses/EndMeetingResponseTest.php
+++ b/tests/unit/Responses/EndMeetingResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\EndMeetingResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class EndMeetingResponseTest extends TestCase
+final class EndMeetingResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\EndMeetingResponse
- */
- private $end;
+ private EndMeetingResponse $end;
protected function setUp(): void
{
@@ -38,14 +38,14 @@ protected function setUp(): void
$this->end = new EndMeetingResponse($xml);
}
- public function testEndMeetingResponseContent()
+ public function testEndMeetingResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->end->getReturnCode());
$this->assertEquals('sentEndMeetingRequest', $this->end->getMessageKey());
$this->assertEquals('A request to end the meeting was sent. Please wait a few seconds, and then use the getMeetingInfo or isMeetingRunning API calls to verify that it was ended.', $this->end->getMessage());
}
- public function testEndMeetingResponseTypes()
+ public function testEndMeetingResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->end, ['getReturnCode', 'getMessageKey', 'getMessage']);
}
diff --git a/tests/unit/Responses/GetMeetingInfoResponseTest.php b/tests/unit/Responses/GetMeetingInfoResponseTest.php
index c6cf2696..6ab4e8fd 100644
--- a/tests/unit/Responses/GetMeetingInfoResponseTest.php
+++ b/tests/unit/Responses/GetMeetingInfoResponseTest.php
@@ -1,5 +1,11 @@
.
*/
-class GetMeetingInfoResponseTest extends \BigBlueButton\TestCase
+final class GetMeetingInfoResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\GetMeetingInfoResponse
- */
- private $meetingInfo;
+ private GetMeetingInfoResponse $meetingInfo;
protected function setUp(): void
{
@@ -30,12 +33,12 @@ protected function setUp(): void
$xml = $this->loadXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'get_meeting_info.xml');
- $this->meetingInfo = new \BigBlueButton\Responses\GetMeetingInfoResponse($xml);
+ $this->meetingInfo = new GetMeetingInfoResponse($xml);
}
- public function testGetMeetingInfoResponseContent()
+ public function testGetMeetingInfoResponseContent(): void
{
- $this->assertInstanceOf('BigBlueButton\Core\Meeting', $this->meetingInfo->getMeeting());
+ $this->assertInstanceOf(Meeting::class, $this->meetingInfo->getMeeting());
$this->assertCount(4, $this->meetingInfo->getMeeting()->getAttendees());
$this->assertEquals('SUCCESS', $this->meetingInfo->getReturnCode());
@@ -47,8 +50,6 @@ public function testGetMeetingInfoResponseContent()
$this->assertEquals('Tue Jan 19 07:25:17 EST 2016', $info->getCreationDate());
$this->assertEquals(70100, $info->getVoiceBridge());
$this->assertEquals('613-555-1234', $info->getDialNumber());
- $this->assertEquals('dbfc7207321527bbb870c82028', $info->getAttendeePassword());
- $this->assertEquals('4bfbbeeb4a65cacaefe3676633', $info->getModeratorPassword());
$this->assertTrue($info->isRunning());
$this->assertEquals(20, $info->getDuration());
$this->assertTrue($info->hasUserJoined());
@@ -66,7 +67,7 @@ public function testGetMeetingInfoResponseContent()
$this->assertTrue($info->isBreakout());
}
- public function testMeetingAttendeeContent()
+ public function testMeetingAttendeeContent(): void
{
$this->assertCount(4, $this->meetingInfo->getMeeting()->getAttendees());
@@ -118,15 +119,19 @@ public function testMeetingViewers(): void
$this->assertEquals('VIEWER', $secondViewer->getRole());
}
- public function testGetMeetingInfoResponseTypes()
+ public function testGetMeetingInfoResponseTypes(): void
{
$info = $this->meetingInfo->getMeeting();
- $this->assertEachGetterValueIsString($info, ['getMeetingName', 'getMeetingId', 'getInternalMeetingId',
- 'getModeratorPassword', 'getAttendeePassword', 'getCreationDate', 'getDialNumber', ]);
+ $this->assertEachGetterValueIsString($info, [
+ 'getMeetingName', 'getMeetingId', 'getInternalMeetingId',
+ 'getCreationDate', 'getDialNumber',
+ ]);
- $this->assertEachGetterValueIsInteger($info, ['getVoiceBridge', 'getDuration', 'getParticipantCount',
- 'getListenerCount', 'getVoiceParticipantCount', 'getVideoCount', 'getMaxUsers', 'getModeratorCount', ]);
+ $this->assertEachGetterValueIsInteger($info, [
+ 'getVoiceBridge', 'getDuration', 'getParticipantCount',
+ 'getListenerCount', 'getVoiceParticipantCount', 'getVideoCount', 'getMaxUsers', 'getModeratorCount',
+ ]);
$this->assertEachGetterValueIsDouble($info, ['getStartTime', 'getEndTime', 'getCreationTime']);
@@ -138,7 +143,7 @@ public function testGetMeetingInfoResponseTypes()
$this->assertEachGetterValueIsBoolean($anAttendee, ['isPresenter', 'isListeningOnly', 'hasJoinedVoice', 'hasVideo']);
}
- public function testGetMeetingInfoMetadataContent()
+ public function testGetMeetingInfoMetadataContent(): void
{
$metas = $this->meetingInfo->getMeeting()->getMetas();
diff --git a/tests/unit/Responses/GetMeetingsResponseTest.php b/tests/unit/Responses/GetMeetingsResponseTest.php
index 2f77ce3d..f39df44a 100644
--- a/tests/unit/Responses/GetMeetingsResponseTest.php
+++ b/tests/unit/Responses/GetMeetingsResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\GetMeetingsResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class GetMeetingsResponseTest extends TestCase
+final class GetMeetingsResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\GetMeetingsResponse
- */
- private $meetings;
+ private GetMeetingsResponse $meetings;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->meetings = new GetMeetingsResponse($xml);
}
- public function testGetMeetingsResponseContent()
+ public function testGetMeetingsResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->meetings->getReturnCode());
@@ -52,8 +52,6 @@ public function testGetMeetingsResponseContent()
$this->assertEquals('Tue Jan 19 08:27:55 EST 2016', $aMeeting->getCreationDate());
$this->assertEquals(49518, $aMeeting->getVoiceBridge());
$this->assertEquals('580.124.3937x93615', $aMeeting->getDialNumber());
- $this->assertEquals('f~kxYJeAV~G?Jb+E:ggn', $aMeeting->getAttendeePassword());
- $this->assertEquals('n:"zWc##Bi.y,d^s,mMF', $aMeeting->getModeratorPassword());
$this->assertFalse($aMeeting->hasBeenForciblyEnded());
$this->assertTrue($aMeeting->isRunning());
$this->assertEquals(5, $aMeeting->getParticipantCount());
@@ -68,21 +66,22 @@ public function testGetMeetingsResponseContent()
$this->assertEquals('http://www.muller.biz/autem-dolor-aut-nam-doloribus-molestiae', $aMeeting->getMetas()['endcallbackurl']);
}
- public function testGetMeetingsResponseTypes()
+ public function testGetMeetingsResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->meetings, ['getReturnCode']);
$aMeeting = $this->meetings->getMeetings()[2];
- $this->assertEachGetterValueIsString($aMeeting, ['getMeetingId', 'getMeetingName', 'getCreationDate', 'getDialNumber',
- 'getAttendeePassword', 'getModeratorPassword', ]);
+ $this->assertEachGetterValueIsString($aMeeting, ['getMeetingId', 'getMeetingName', 'getCreationDate', 'getDialNumber']);
$this->assertEachGetterValueIsDouble($aMeeting, ['getCreationTime']);
- $this->assertEachGetterValueIsInteger($aMeeting, ['getVoiceBridge', 'getParticipantCount', 'getListenerCount',
- 'getVoiceParticipantCount', 'getVideoCount', 'getDuration', ]);
+ $this->assertEachGetterValueIsInteger($aMeeting, [
+ 'getVoiceBridge', 'getParticipantCount', 'getListenerCount',
+ 'getVoiceParticipantCount', 'getVideoCount', 'getDuration',
+ ]);
$this->assertEachGetterValueIsBoolean($aMeeting, ['hasBeenForciblyEnded', 'isRunning', 'hasUserJoined']);
}
- public function testGetMeetingsNoMeetings()
+ public function testGetMeetingsNoMeetings(): void
{
// scalelite response no meetings
$xml = simplexml_load_string('SUCCESSnoMeetingsNo meetings were found on this server.');
diff --git a/tests/unit/Responses/GetRecordingsResponseTest.php b/tests/unit/Responses/GetRecordingsResponseTest.php
index 85dfcd4e..d95d8e6b 100644
--- a/tests/unit/Responses/GetRecordingsResponseTest.php
+++ b/tests/unit/Responses/GetRecordingsResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\GetRecordingsResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class GetRecordingsResponseTest extends TestCase
+final class GetRecordingsResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\GetRecordingsResponse
- */
- private $records;
+ private GetRecordingsResponse $records;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->records = new GetRecordingsResponse($xml);
}
- public function testGetRecordingResponseContent()
+ public function testGetRecordingResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->records->getReturnCode());
@@ -60,14 +60,14 @@ public function testGetRecordingResponseContent()
$this->assertEquals(9, \count($aRecord->getMetas()));
}
- public function testRecordMetadataContent()
+ public function testRecordMetadataContent(): void
{
$metas = $this->records->getRecords()[4]->getMetas();
$this->assertEquals('moodle-mod_bigbluebuttonbn (2015080611)', $metas['bbb-origin-tag']);
}
- public function testGetRecordingResponseTypes()
+ public function testGetRecordingResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->records, ['getReturnCode']);
@@ -111,5 +111,25 @@ public function testImagePreviews(): void
$this->assertEquals('Welcome to', $previews[0]->getAlt());
$this->assertEquals('https://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530718721134/thumbnails/thumb-1.png', $previews[0]->getUrl());
+ $this->assertEquals(176, $previews[0]->getWidth());
+ $this->assertEquals(136, $previews[0]->getHeight());
+
+ // Load previews again, check if same instance is returned (caching)
+ $newPreviews = $formats[1]->getImagePreviews();
+ $this->assertTrue($previews[0] === $newPreviews[0]);
+ }
+
+ public function testHasNoRecordings(): void
+ {
+ $xml = '
+ SUCCESS
+
+ noRecordings
+ There are no recordings for the meeting(s).
+ ';
+
+ $response = new GetRecordingsResponse(simplexml_load_string($xml));
+
+ $this->assertTrue($response->hasNoRecordings());
}
}
diff --git a/tests/unit/Responses/GetRecordingsTextTracksResponseTest.php b/tests/unit/Responses/GetRecordingsTextTracksResponseTest.php
index eb660884..ef3c7cc6 100644
--- a/tests/unit/Responses/GetRecordingsTextTracksResponseTest.php
+++ b/tests/unit/Responses/GetRecordingsTextTracksResponseTest.php
@@ -1,16 +1,15 @@
tracks = new GetRecordingTextTracksResponse($json);
}
- public function testGetRecordingTextTracksResponseContent()
+ public function testGetRecordingTextTracksResponseContent(): void
{
$this->assertEquals(GetRecordingTextTracksResponse::SUCCESS, $this->tracks->getReturnCode());
$this->assertTrue($this->tracks->success());
@@ -30,7 +29,7 @@ public function testGetRecordingTextTracksResponseContent()
$this->assertCount(2, $this->tracks->getTracks());
}
- public function testGetRecordingTextTracksResponseTypes()
+ public function testGetRecordingTextTracksResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->tracks, ['getReturnCode']);
@@ -41,16 +40,16 @@ public function testGetRecordingTextTracksResponseTypes()
$secondTracks = $this->tracks->getTracks()[1];
$this->assertEachGetterValueIsString($secondTracks, [
- 'getHref',
- 'getKind',
- 'getLabel',
- 'getLang',
- 'getSource',
- ]
+ 'getHref',
+ 'getKind',
+ 'getLabel',
+ 'getLang',
+ 'getSource',
+ ]
);
}
- public function testGetRecordingTextTracksResponseValues()
+ public function testGetRecordingTextTracksResponseValues(): void
{
$secondTracks = $this->tracks->getTracks()[1];
diff --git a/tests/unit/Responses/HooksCreateResponseTest.php b/tests/unit/Responses/HooksCreateResponseTest.php
index 440e5965..77a35d1a 100644
--- a/tests/unit/Responses/HooksCreateResponseTest.php
+++ b/tests/unit/Responses/HooksCreateResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\HooksCreateResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class HooksCreateResponseTest extends TestCase
+final class HooksCreateResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\HooksCreateResponse
- */
- private $createResponse;
+ private HooksCreateResponse $createResponse;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->createResponse = new HooksCreateResponse($xml);
}
- public function testHooksCreateResponseContent()
+ public function testHooksCreateResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->createResponse->getReturnCode());
$this->assertEquals(1, $this->createResponse->getHookId());
@@ -46,7 +46,7 @@ public function testHooksCreateResponseContent()
$this->assertFalse($this->createResponse->hasRawData());
}
- public function testHooksCreateResponseTypes()
+ public function testHooksCreateResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->createResponse, ['getReturnCode']);
$this->assertEachGetterValueIsInteger($this->createResponse, ['getHookId']);
diff --git a/tests/unit/Responses/HooksDestroyResponseTest.php b/tests/unit/Responses/HooksDestroyResponseTest.php
index 0e0eb047..7704ee1a 100644
--- a/tests/unit/Responses/HooksDestroyResponseTest.php
+++ b/tests/unit/Responses/HooksDestroyResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\HooksDestroyResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class HooksDestroyResponseTest extends TestCase
+final class HooksDestroyResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\HooksDestroyResponse
- */
- private $destroyResponse;
+ private HooksDestroyResponse $destroyResponse;
protected function setUp(): void
{
@@ -38,15 +38,33 @@ protected function setUp(): void
$this->destroyResponse = new HooksDestroyResponse($xml);
}
- public function testHooksDestroyResponseContent()
+ public function testHooksDestroyResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->destroyResponse->getReturnCode());
$this->assertTrue($this->destroyResponse->removed());
}
- public function testHooksDestroyResponseTypes()
+ public function testHooksDestroyResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->destroyResponse, ['getReturnCode']);
$this->assertEachGetterValueIsBoolean($this->destroyResponse, ['removed']);
}
+
+ public function testHookDestroyMissingHook(): void
+ {
+ $xml = simplexml_load_string('FAILEDdestroyMissingHookThe hook informed was not found.');
+
+ $destroyResponse = new HooksDestroyResponse($xml);
+ $this->assertTrue($destroyResponse->failed());
+ $this->assertTrue($destroyResponse->isMissingHook());
+ }
+
+ public function testHookDestroyHookError(): void
+ {
+ $xml = simplexml_load_string('FAILEDdestroyHookErrorAn error happened while removing your hook. Check the logs.');
+
+ $destroyResponse = new HooksDestroyResponse($xml);
+ $this->assertTrue($destroyResponse->failed());
+ $this->assertTrue($destroyResponse->isHookError());
+ }
}
diff --git a/tests/unit/Responses/HooksListResponseTest.php b/tests/unit/Responses/HooksListResponseTest.php
index ea3d2745..8395fd19 100644
--- a/tests/unit/Responses/HooksListResponseTest.php
+++ b/tests/unit/Responses/HooksListResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\HooksListResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class HooksListResponseTest extends TestCase
+final class HooksListResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\HooksListResponse
- */
- private $listResponse;
+ private HooksListResponse $listResponse;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->listResponse = new HooksListResponse($xml);
}
- public function testHooksListResponseContent()
+ public function testHooksListResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->listResponse->getReturnCode());
$this->assertCount(2, $this->listResponse->getHooks());
@@ -52,7 +52,7 @@ public function testHooksListResponseContent()
$this->assertFalse($aHook->hasRawData());
}
- public function testHooksListResponseTypes()
+ public function testHooksListResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->listResponse, ['getReturnCode']);
diff --git a/tests/unit/Responses/InsertDocumentResponseTest.php b/tests/unit/Responses/InsertDocumentResponseTest.php
index bf9dc225..01d1012e 100644
--- a/tests/unit/Responses/InsertDocumentResponseTest.php
+++ b/tests/unit/Responses/InsertDocumentResponseTest.php
@@ -19,17 +19,14 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\InsertDocumentResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class InsertDocumentResponseTest extends TestCase
+final class InsertDocumentResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\IsMeetingRunningResponse
- */
- private $running;
+ private InsertDocumentResponse $running;
protected function setUp(): void
{
diff --git a/tests/unit/Responses/IsMeetingRunningResponseTest.php b/tests/unit/Responses/IsMeetingRunningResponseTest.php
index 5e4a2f89..70dce13f 100644
--- a/tests/unit/Responses/IsMeetingRunningResponseTest.php
+++ b/tests/unit/Responses/IsMeetingRunningResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\IsMeetingRunningResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class IsMeetingRunningResponseTest extends TestCase
+final class IsMeetingRunningResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\IsMeetingRunningResponse
- */
- private $running;
+ private IsMeetingRunningResponse $running;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->running = new IsMeetingRunningResponse($xml);
}
- public function testIsMeetingRunningResponseContent()
+ public function testIsMeetingRunningResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->running->getReturnCode());
$this->assertTrue($this->running->isRunning());
@@ -46,7 +46,7 @@ public function testIsMeetingRunningResponseContent()
$this->assertEquals('SUCCESStrue', $this->minifyString($this->running->getRawXml()->asXML()));
}
- public function testIsMeetingRunningResponseTypes()
+ public function testIsMeetingRunningResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->running, ['getReturnCode']);
$this->assertEachGetterValueIsBoolean($this->running, ['isRunning']);
diff --git a/tests/unit/Responses/JoinMeetingResponseTest.php b/tests/unit/Responses/JoinMeetingResponseTest.php
index 0178dd55..836e3060 100644
--- a/tests/unit/Responses/JoinMeetingResponseTest.php
+++ b/tests/unit/Responses/JoinMeetingResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\JoinMeetingResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class JoinMeetingResponseTest extends TestCase
+final class JoinMeetingResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\JoinMeetingResponse
- */
- private $joinMeeting;
+ private JoinMeetingResponse $joinMeeting;
protected function setUp(): void
{
@@ -38,7 +38,7 @@ protected function setUp(): void
$this->joinMeeting = new JoinMeetingResponse($xml);
}
- public function testJoinMeetingResponseContent()
+ public function testJoinMeetingResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->joinMeeting->getReturnCode());
$this->assertEquals('successfullyJoined', $this->joinMeeting->getMessageKey());
@@ -51,7 +51,7 @@ public function testJoinMeetingResponseContent()
$this->assertEquals('https://bigblubutton-server.sample/client/BigBlueButton.html?sessionToken=0wzsph6uaelwc68z', $this->joinMeeting->getUrl());
}
- public function testJoinMeetingResponseTypes()
+ public function testJoinMeetingResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->joinMeeting, ['getReturnCode', 'getMessageKey', 'getMessage', 'getMeetingId', 'getUserId', 'getAuthToken', 'getSessionToken', 'getGuestStatus', 'getUrl']);
}
diff --git a/tests/unit/Responses/PublishRecordingsResponseTest.php b/tests/unit/Responses/PublishRecordingsResponseTest.php
index 105a6792..b8fe8727 100644
--- a/tests/unit/Responses/PublishRecordingsResponseTest.php
+++ b/tests/unit/Responses/PublishRecordingsResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\PublishRecordingsResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class PublishRecordingsResponseTest extends TestCase
+final class PublishRecordingsResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\PublishRecordingsResponse
- */
- private $publish;
+ private PublishRecordingsResponse $publish;
protected function setUp(): void
{
@@ -38,15 +38,25 @@ protected function setUp(): void
$this->publish = new PublishRecordingsResponse($xml);
}
- public function testPublishRecordingsResponseContent()
+ public function testPublishRecordingsResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->publish->getReturnCode());
$this->assertTrue($this->publish->isPublished());
}
- public function testPublishRecordingsResponseTypes()
+ public function testPublishRecordingsResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->publish, ['getReturnCode']);
$this->assertEachGetterValueIsBoolean($this->publish, ['isPublished']);
}
+
+ public function testNotFoundError(): void
+ {
+ $xml = $this->loadXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'not_found_error.xml');
+
+ $publish = new PublishRecordingsResponse($xml);
+
+ $this->assertTrue($publish->failed());
+ $this->assertTrue($publish->isNotFound());
+ }
}
diff --git a/tests/unit/Responses/PutRecordingTextTrackResponseTest.php b/tests/unit/Responses/PutRecordingTextTrackResponseTest.php
new file mode 100644
index 00000000..8b6b9a34
--- /dev/null
+++ b/tests/unit/Responses/PutRecordingTextTrackResponseTest.php
@@ -0,0 +1,147 @@
+.
+ */
+
+namespace BigBlueButton\Tests\Unit\Responses;
+
+use BigBlueButton\Responses\PutRecordingTextTrackResponse;
+use BigBlueButton\Tests\Common\TestCase;
+
+final class PutRecordingTextTrackResponseTest extends TestCase
+{
+ public function testUploadSuccess(): void
+ {
+ $json = '{
+ "response": {
+ "messageKey": "upload_text_track_success",
+ "message": "Text track uploaded successfully",
+ "recordId": "baz",
+ "returncode": "SUCCESS"
+ }
+ }';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertTrue($response->success());
+ $this->assertEquals('baz', $response->getRecordID());
+ $this->assertTrue($response->isUploadTrackSuccess());
+ }
+
+ public function testUploadFailed(): void
+ {
+ $json = '{
+ "response": {
+ "messageKey": "upload_text_track_failed",
+ "message": "Text track upload failed.",
+ "recordId": "baz",
+ "returncode": "FAILED"
+ }
+ }';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertTrue($response->failed());
+ $this->assertEquals('baz', $response->getRecordID());
+ $this->assertTrue($response->isUploadTrackFailed());
+ }
+
+ public function testUploadEmpty(): void
+ {
+ $json = '{
+ "response": {
+ "messageKey": "empty_uploaded_text_track",
+ "message": "Empty uploaded text track.",
+ "returncode": "FAILED"
+ }
+ }';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertTrue($response->failed());
+ $this->assertTrue($response->isUploadTrackEmpty());
+ }
+
+ public function testNoRecordings(): void
+ {
+ $json = '{
+ "response": {
+ "messageKey": "noRecordings",
+ "message": "No recording was found for meeting-id-1234.",
+ "returncode": "FAILED"
+ }
+ }';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertTrue($response->failed());
+ $this->assertTrue($response->isNoRecordings());
+ }
+
+ public function testInvalidLang(): void
+ {
+ $json = '{
+ "response": {
+ "messageKey": "invalidLang",
+ "message": "Malformed lang param, received=english",
+ "returncode": "FAILED"
+ }
+ }';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertTrue($response->failed());
+ $this->assertTrue($response->isInvalidLang());
+ }
+
+ public function testInvalidKind(): void
+ {
+ $json = '{
+ "response": {
+ "messageKey": "invalidKind",
+ "message": "Invalid kind parameter, expected=\'subtitles|captions\' actual=somethingelse",
+ "returncode": "FAILED"
+ }
+ }';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertTrue($response->failed());
+ $this->assertTrue($response->isInvalidKind());
+ }
+
+ public function testHandleMissingJsonKeys(): void
+ {
+ $json = '{}';
+
+ $response = new PutRecordingTextTrackResponse($json);
+
+ $this->assertFalse($response->success());
+ $this->assertFalse($response->failed());
+ $this->assertFalse($response->hasChecksumError());
+ $this->assertEquals('', $response->getRecordID());
+ $this->assertFalse($response->isUploadTrackSuccess());
+ $this->assertFalse($response->isUploadTrackFailed());
+ $this->assertFalse($response->isUploadTrackEmpty());
+ $this->assertFalse($response->isNoRecordings());
+ $this->assertFalse($response->isInvalidLang());
+ $this->assertFalse($response->isInvalidKind());
+ }
+}
diff --git a/tests/unit/Responses/UpdateRecordingsResponseTest.php b/tests/unit/Responses/UpdateRecordingsResponseTest.php
index 76e61026..7f78c536 100644
--- a/tests/unit/Responses/UpdateRecordingsResponseTest.php
+++ b/tests/unit/Responses/UpdateRecordingsResponseTest.php
@@ -1,4 +1,7 @@
.
*/
-namespace BigBlueButton\Parameters;
+namespace BigBlueButton\Tests\Unit\Responses;
use BigBlueButton\Responses\UpdateRecordingsResponse;
-use BigBlueButton\TestCase;
+use BigBlueButton\Tests\Common\TestCase;
-class UpdateRecordingsResponseTest extends TestCase
+final class UpdateRecordingsResponseTest extends TestCase
{
- /**
- * @var \BigBlueButton\Responses\UpdateRecordingsResponse
- */
- private $update;
+ private UpdateRecordingsResponse $update;
protected function setUp(): void
{
@@ -38,15 +38,25 @@ protected function setUp(): void
$this->update = new UpdateRecordingsResponse($xml);
}
- public function testUpdateRecordingsResponseContent()
+ public function testUpdateRecordingsResponseContent(): void
{
$this->assertEquals('SUCCESS', $this->update->getReturnCode());
$this->assertTrue($this->update->isUpdated());
}
- public function testUpdateRecordingsResponseTypes()
+ public function testUpdateRecordingsResponseTypes(): void
{
$this->assertEachGetterValueIsString($this->update, ['getReturnCode']);
$this->assertEachGetterValueIsBoolean($this->update, ['isUpdated']);
}
+
+ public function testNotFoundError(): void
+ {
+ $xml = $this->loadXmlFile(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'not_found_error.xml');
+
+ $update = new UpdateRecordingsResponse($xml);
+
+ $this->assertTrue($update->failed());
+ $this->assertTrue($update->isNotFound());
+ }
}
diff --git a/tests/unit/Util/ArrayHelperTest.php b/tests/unit/Util/ArrayHelperTest.php
index 16e43593..9ea33908 100644
--- a/tests/unit/Util/ArrayHelperTest.php
+++ b/tests/unit/Util/ArrayHelperTest.php
@@ -19,8 +19,9 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Util;
+namespace BigBlueButton\Tests\Unit\Util;
+use BigBlueButton\Util\ArrayHelper;
use PHPUnit\Framework\TestCase;
/**
@@ -28,6 +29,7 @@
*/
final class ArrayHelperTest extends TestCase
{
+ /** @return iterable> */
public function provideArrays(): iterable
{
yield 'simple flat arrays' => [
@@ -58,6 +60,10 @@ public function provideArrays(): iterable
/**
* @dataProvider provideArrays
+ *
+ * @param array $input1
+ * @param array $input2
+ * @param array $output
*/
public function testMergeRecursive(array $input1, array $input2, bool $reorderNested, array $output): void
{
diff --git a/tests/unit/Util/SimpleXMLElementExtendedTest.php b/tests/unit/Util/SimpleXMLElementExtendedTest.php
new file mode 100644
index 00000000..c29a09c7
--- /dev/null
+++ b/tests/unit/Util/SimpleXMLElementExtendedTest.php
@@ -0,0 +1,46 @@
+.
+ */
+
+namespace BigBlueButton\Tests\Unit\Util;
+
+use BigBlueButton\Tests\Common\TestCase;
+use BigBlueButton\Util\SimpleXMLElementExtended;
+
+/**
+ * @covers \BigBlueButton\Util\SimpleXMLElementExtended
+ */
+final class SimpleXMLElementExtendedTest extends TestCase
+{
+ /**
+ * Test adding a child element with CDATA content.
+ */
+ public function testAddChildWithCData(): void
+ {
+ $xml = new SimpleXMLElementExtended('');
+ $module = $xml->addChildWithCData('module', '{"foo": {"foo": "baa"}}');
+ $module->addAttribute('name', 'clientSettingsOverride');
+
+ $expected = '
+';
+
+ $this->assertXmlStringEqualsXmlString($expected, $xml->asXML());
+ }
+}
diff --git a/tests/unit/Util/UrlBuilderTest.php b/tests/unit/Util/UrlBuilderTest.php
index facce75d..0c6acc94 100644
--- a/tests/unit/Util/UrlBuilderTest.php
+++ b/tests/unit/Util/UrlBuilderTest.php
@@ -19,8 +19,10 @@
* along with littleredbutton/bigbluebutton-api-php. If not, see .
*/
-namespace BigBlueButton\Util;
+namespace BigBlueButton\Tests\Unit\Util;
+use BigBlueButton\Enum\HashingAlgorithm;
+use BigBlueButton\Util\UrlBuilder;
use PHPUnit\Framework\TestCase;
/**
@@ -30,7 +32,8 @@ final class UrlBuilderTest extends TestCase
{
public function testBuildUrl(): void
{
- $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/');
+ // Test with sha1 hash algorithm
+ $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/', HashingAlgorithm::SHA_1);
// echo sha1('getMeetings' . 'foo=bar&baz=bazinga' . 'AFFE');
$this->assertSame(
@@ -38,11 +41,21 @@ public function testBuildUrl(): void
$urlBuilder->buildUrl('getMeetings', 'foo=bar&baz=bazinga'),
'signed URL is OK'
);
+
+ // Test with sha256 hash algorithm
+ $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/', HashingAlgorithm::SHA_256);
+
+ // echo hash('sha256', 'getMeetings' . 'foo=bar&baz=bazinga' . 'AFFE');
+ $this->assertSame(
+ 'https://bbb.example/bigbluebutton/api/getMeetings?foo=bar&baz=bazinga&checksum=e93a022a742425259bf3acec803ad8b4e428e7653b66bfecfa60d935a04bcc3b',
+ $urlBuilder->buildUrl('getMeetings', 'foo=bar&baz=bazinga'),
+ 'signed URL is OK'
+ );
}
public function testBuildUrlWithEmptyParams(): void
{
- $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/');
+ $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/', HashingAlgorithm::SHA_1);
// echo sha1('getMeetings' . '' . 'AFFE');
$this->assertSame(
@@ -54,7 +67,7 @@ public function testBuildUrlWithEmptyParams(): void
public function testBuildUrlWithoutAppend(): void
{
- $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/');
+ $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/', HashingAlgorithm::SHA_1);
$this->assertSame(
'https://bbb.example/bigbluebutton/api/getMeetings',
@@ -65,7 +78,7 @@ public function testBuildUrlWithoutAppend(): void
public function testBuildQs(): void
{
- $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/');
+ $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/', HashingAlgorithm::SHA_1);
// echo sha1('getMeetings' . 'foo=bar&baz=bazinga' . 'AFFE');
$this->assertSame(
@@ -77,7 +90,7 @@ public function testBuildQs(): void
public function testBuildQsWithEmptyParams(): void
{
- $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/');
+ $urlBuilder = new UrlBuilder('AFFE', 'https://bbb.example/bigbluebutton/', HashingAlgorithm::SHA_1);
// echo sha1('getMeetings' . '' . 'AFFE');
$this->assertSame(
diff --git a/tools/.php-coveralls/composer.json b/tools/.php-coveralls/composer.json
deleted file mode 100644
index 79cd2252..00000000
--- a/tools/.php-coveralls/composer.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "require": {
- "php-coveralls/php-coveralls": "^2.4.0"
- }
-}
diff --git a/tools/.phpstan/.gitignore b/tools/.phpstan/.gitignore
new file mode 100644
index 00000000..57872d0f
--- /dev/null
+++ b/tools/.phpstan/.gitignore
@@ -0,0 +1 @@
+/vendor/
diff --git a/tools/.phpstan/composer.json b/tools/.phpstan/composer.json
new file mode 100644
index 00000000..90c99dfd
--- /dev/null
+++ b/tools/.phpstan/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "phpstan/phpstan": "^1.10"
+ }
+}
diff --git a/tools/.phpstan/composer.lock b/tools/.phpstan/composer.lock
new file mode 100644
index 00000000..2c3ffe96
--- /dev/null
+++ b/tools/.phpstan/composer.lock
@@ -0,0 +1,77 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "14812c2a05a5972f00f9d67abbd710a9",
+ "packages": [
+ {
+ "name": "phpstan/phpstan",
+ "version": "1.12.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpstan.git",
+ "reference": "0fcbf194ab63d8159bb70d9aa3e1350051632009"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0fcbf194ab63d8159bb70d9aa3e1350051632009",
+ "reference": "0fcbf194ab63d8159bb70d9aa3e1350051632009",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2|^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan-shim": "*"
+ },
+ "bin": [
+ "phpstan",
+ "phpstan.phar"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "keywords": [
+ "dev",
+ "static analysis"
+ ],
+ "support": {
+ "docs": "https://phpstan.org/user-guide/getting-started",
+ "forum": "https://github.com/phpstan/phpstan/discussions",
+ "issues": "https://github.com/phpstan/phpstan/issues",
+ "security": "https://github.com/phpstan/phpstan/security/policy",
+ "source": "https://github.com/phpstan/phpstan-src"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ondrejmirtes",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/phpstan",
+ "type": "github"
+ }
+ ],
+ "time": "2024-09-09T08:10:35+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.6.0"
+}
diff --git a/tools/.phpunit/composer.json b/tools/.phpunit/composer.json
index 18a43fc8..4db33099 100644
--- a/tools/.phpunit/composer.json
+++ b/tools/.phpunit/composer.json
@@ -1,6 +1,6 @@
{
"require": {
- "phpunit/phpunit": "^8",
- "fakerphp/faker": "^1.14"
+ "phpunit/phpunit": "^9.0",
+ "fakerphp/faker": "1.20.*"
}
}
diff --git a/tools/.psalm/composer.json b/tools/.psalm/composer.json
index e2261577..70de5195 100644
--- a/tools/.psalm/composer.json
+++ b/tools/.psalm/composer.json
@@ -1,5 +1,5 @@
{
"require": {
- "vimeo/psalm": "^4.22"
+ "vimeo/psalm": "^5.23"
}
}
diff --git a/tools/.php-coveralls/.gitignore b/tools/.rector/.gitignore
similarity index 100%
rename from tools/.php-coveralls/.gitignore
rename to tools/.rector/.gitignore
diff --git a/tools/.rector/composer.json b/tools/.rector/composer.json
new file mode 100644
index 00000000..056d015c
--- /dev/null
+++ b/tools/.rector/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "rector/rector": "^1.0"
+ }
+}
diff --git a/tools/README.md b/tools/README.md
index d8dc27e2..3ceb0402 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -5,7 +5,7 @@ The dependencies are not pulled via the main composer.json to keep the dependenc
## Structure of the `tools` folder
-Each tool has a hidden (dot) folder with it's tool name. For exmaple, PHP-CS-Fixer uses `tools/.php-cs-fixer`:
+Each tool has a hidden (dot) folder with its tool name. For example, PHP-CS-Fixer uses `tools/.php-cs-fixer`:
~~~
tools/
diff --git a/tools/bootstrap.php b/tools/bootstrap.php
new file mode 100644
index 00000000..5a34c481
--- /dev/null
+++ b/tools/bootstrap.php
@@ -0,0 +1,13 @@
+mustRun();
+
+require __DIR__.'/.phpunit/vendor/autoload.php';
diff --git a/tools/php-coveralls b/tools/phpstan
similarity index 53%
rename from tools/php-coveralls
rename to tools/phpstan
index 657546b6..9d0b643e 100755
--- a/tools/php-coveralls
+++ b/tools/phpstan
@@ -3,5 +3,5 @@
DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
-composer install --working-dir=$DIR/.php-coveralls --quiet
-exec $DIR/.php-coveralls/vendor/bin/php-coveralls "$@"
+composer install --working-dir=$DIR/.phpstan --quiet
+exec $DIR/.phpstan/vendor/bin/phpstan "$@"
diff --git a/tools/rector b/tools/rector
new file mode 100755
index 00000000..c5f602ae
--- /dev/null
+++ b/tools/rector
@@ -0,0 +1,7 @@
+#!/bin/bash
+# This file was created automatically by cotor as a tool wrapper.
+
+DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
+
+composer install --working-dir=$DIR/.rector --quiet
+exec $DIR/.rector/vendor/bin/rector "$@"