diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index 381c75d..c039148 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -51,9 +51,9 @@ body: label: "🐘 PHP Version" description: "What version of PHP are you running?" options: - - PHP 7.3.x - - PHP 7.4.x + - PHP 8.0 - Different version (specify in environment) + - type: dropdown id: operating-system attributes: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..f02bcd6 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,20 @@ +name: "CodeQL" + +on: [pull_request] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - run: git checkout HEAD^2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" diff --git a/.travis.yml b/.travis.yml index b441653..3fcd18b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,4 @@ before_script: composer install --ignore-platform-reqs script: - vendor/bin/phpunit --configuration phpunit.xml -- vendor/bin/psalm --show-info=true +- vendor/bin/psalm --show-info=true \ No newline at end of file diff --git a/composer.json b/composer.json index c2b90bf..cec5b85 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,9 @@ "keywords": ["php","framework", "upf", "utopia", "analytics"], "license": "MIT", "minimum-stability": "stable", + "scripts": { + "check": "./vendor/bin/phpstan analyse --level 6 src tests" + }, "autoload": { "psr-4": {"Utopia\\Analytics\\": "src/Analytics"} }, @@ -14,6 +17,7 @@ }, "require-dev": { "phpunit/phpunit": "^9.3", + "phpstan/phpstan": "1.9.x-dev", "vimeo/psalm": "^5.6" } } diff --git a/src/Analytics/Adapter.php b/src/Analytics/Adapter.php index 79992d4..9c9e174 100644 --- a/src/Analytics/Adapter.php +++ b/src/Analytics/Adapter.php @@ -18,7 +18,7 @@ abstract class Adapter /** * The IP address to forward to Plausible - * + * * @var string */ protected string $clientIP; @@ -32,7 +32,7 @@ abstract class Adapter /** * Gets the name of the adapter. - * + * * @return string */ abstract public function getName(): string; @@ -40,7 +40,7 @@ abstract public function getName(): string; /** * Global Headers * - * @var array + * @var array */ protected $headers = [ 'Content-Type' => '', @@ -48,7 +48,7 @@ abstract public function getName(): string; /** * Enables tracking for this instance. - * + * * @return void */ public function enable(): void @@ -58,7 +58,7 @@ public function enable(): void /** * Disables tracking for this instance. - * + * * @return void */ public function disable(): void @@ -68,7 +68,7 @@ public function disable(): void /** * Send the event to the adapter. - * + * * @param Event $event * @return bool */ @@ -88,9 +88,11 @@ public abstract function validate(Event $event): bool; /** * Sets the client IP address. + * * @param string $clientIP The IP address to use. * + * @return self */ public function setClientIP(string $clientIP): self @@ -101,9 +103,9 @@ public function setClientIP(string $clientIP): self /** * Sets the client user agent. - * + * * @param string $userAgent The user agent to use. - * + * * @return self */ public function setUserAgent(string $userAgent): self @@ -114,7 +116,7 @@ public function setUserAgent(string $userAgent): self /** * Creates an Event on the remote analytics platform. - * + * * @param Event $event * @return bool */ @@ -135,12 +137,13 @@ public function createEvent(Event $event): bool * * @param string $method * @param string $path - * @param array $params - * @param array $headers - * @return array|string + * @param array $params + * @param array $headers + * + * @return array * @throws \Exception */ - public function call(string $method, string $path = '', array $headers = array(), array $params = array()): array|string + public function call(string $method, string $path = '', array $headers = array(), array $params = array()): array { $headers = array_merge($this->headers, $headers); $ch = curl_init((str_contains($path, 'http') ? $path : $this->endpoint . $path . (($method == 'GET' && !empty($params)) ? '?' . http_build_query($params) : ''))); @@ -194,7 +197,7 @@ public function call(string $method, string $path = '', array $headers = array() $responseType = $responseHeaders['Content-Type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); - + switch(substr($responseType, 0, strpos($responseType, ';'))) { case 'application/json': $responseBody = json_decode($responseBody, true); @@ -204,7 +207,7 @@ public function call(string $method, string $path = '', array $headers = array() if (curl_errno($ch)) { throw new \Exception(curl_error($ch)); } - + curl_close($ch); if($responseStatus >= 400) { @@ -222,11 +225,12 @@ public function call(string $method, string $path = '', array $headers = array() /** * Flatten params array to PHP multiple format * - * @param array $data + * @param array $data * @param string $prefix - * @return array + * @return array */ - protected function flatten(array $data, string $prefix = ''): array { + protected function flatten(array $data, string $prefix = ''): array + { $output = []; foreach($data as $key => $value) { @@ -245,7 +249,7 @@ protected function flatten(array $data, string $prefix = ''): array { /** * Log Error - * + * * @param Exception $e * @return void */ @@ -256,4 +260,4 @@ protected function logError(Exception $e) { Console::error('[Error] File: ' . $e->getFile()); Console::error('[Error] Line: ' . $e->getLine()); } -} \ No newline at end of file +} diff --git a/src/Analytics/Adapter/ActiveCampaign.php b/src/Analytics/Adapter/ActiveCampaign.php index cc7cbfa..0fc872d 100644 --- a/src/Analytics/Adapter/ActiveCampaign.php +++ b/src/Analytics/Adapter/ActiveCampaign.php @@ -36,7 +36,7 @@ class ActiveCampaign extends Adapter /** * Gets the name of the adapter. - * + * * @return string */ public function getName(): string @@ -47,13 +47,14 @@ public function getName(): string /** * Checks if a contact exists by the email ID. Returns the User ID if it exists and false if it doesn't. - * + * * @param string $email * @return bool|int */ public function contactExists(string $email): bool|int { try { + $result = $this->call('GET', '/api/3/contacts', [], [ 'email' => $email ]); @@ -73,7 +74,7 @@ public function contactExists(string $email): bool|int /** * Create a contact - * + * * @param string $email * @param string $firstName * @param string $lastName @@ -102,13 +103,13 @@ public function createContact(string $email, string $firstName = '', string $las /** * Update contact - * + * * @param string $contactId * @param string $email * @param string $firstName * @param string $lastName * @param string $phone - * + * * @return bool */ public function updateContact(string $contactId, string $email, string $firstName = '', string $lastName = '', string $phone = ''): bool @@ -132,9 +133,9 @@ public function updateContact(string $contactId, string $email, string $firstNam } } - /** - * Delete a contact - * + /** + * Delete a contact + * * @param string $email * @return bool */ @@ -157,7 +158,7 @@ public function deleteContact(string $email): bool /** * Account Exists - * + * * @param string $name * @return bool|int */ @@ -181,12 +182,12 @@ public function accountExists(string $name): bool|int /** * Create an account - * + * * @param string $name * @param string $url * @param int $ownerId - * @param array $fields - * + * @param array $fields + * * @return bool */ public function createAccount(string $name, string $url = '', int $ownerId = 1, array $fields = []): bool @@ -213,13 +214,13 @@ public function createAccount(string $name, string $url = '', int $ownerId = 1, /** * Update an account - * + * * @param string $accountId * @param string $name * @param string $url * @param int $ownerId - * @param array $fields - * + * @param array $fields + * * @return bool */ public function updateAccount(string $accountId, string $name, string $url = '', int $ownerId = 1, array $fields = []): bool @@ -246,9 +247,9 @@ public function updateAccount(string $accountId, string $name, string $url = '', /** * Delete an account - * + * * @param string $accountId - * + * * @return bool */ public function deleteAccount(string $accountId): bool @@ -264,13 +265,13 @@ public function deleteAccount(string $accountId): bool /** * Sync an association - * + * * Creates an association if it doesn't exist and updates it if it does - * + * * @param string $accountId * @param string $contactId * @param string $role - * + * * @return bool */ public function syncAssociation(string $accountId, string $contactId, string $role = ''): bool @@ -319,11 +320,11 @@ public function syncAssociation(string $accountId, string $contactId, string $ro } /** - * @param string $key + * @param string $key * @param string $actId * @param string $apiKey * @param string $organisationId - * + * * @return ActiveCampaign */ public function __construct(string $key, string $actId, string $apiKey, string $organisationId) @@ -340,7 +341,7 @@ public function __construct(string $key, string $actId, string $apiKey, string $ /** * Creates an Event on the remote analytics platform. - * + * * @param Event $event * @return bool */ @@ -370,9 +371,9 @@ public function send(Event $event): bool /** * Sets the client IP address. - * + * * @param string $ip The IP address to use. - * + * * @return self */ public function setClientIP(string $clientIP): self @@ -382,9 +383,9 @@ public function setClientIP(string $clientIP): self /** * Sets the client user agent. - * + * * @param string $userAgent The user agent to use. - * + * * @return self */ public function setUserAgent(string $userAgent): self diff --git a/src/Analytics/Adapter/Orbit.php b/src/Analytics/Adapter/Orbit.php index 348f0a6..ec0bd50 100644 --- a/src/Analytics/Adapter/Orbit.php +++ b/src/Analytics/Adapter/Orbit.php @@ -107,7 +107,7 @@ public function send(Event $event): bool /** * Sets the client IP address. * - * @param string $ip The IP address to use. + * @param string $clientIP The IP address to use. * * @return self */ diff --git a/src/Analytics/Adapter/Plausible.php b/src/Analytics/Adapter/Plausible.php index ea5013a..bea618e 100644 --- a/src/Analytics/Adapter/Plausible.php +++ b/src/Analytics/Adapter/Plausible.php @@ -30,7 +30,7 @@ class Plausible extends Adapter /** * Global Headers * - * @var array + * @var array */ protected $headers = []; @@ -43,7 +43,7 @@ class Plausible extends Adapter /** * Domain to use for events - * + * * @var string */ protected string $domain; @@ -51,7 +51,7 @@ class Plausible extends Adapter /** * Gets the name of the adapter. - * + * * @return string */ public function getName(): string @@ -61,12 +61,12 @@ public function getName(): string /** * Constructor. - * + * * @param string $domain The domain to use for events * @param string $apiKey The API key to use for requests * @param string $useragent The useragent to use for requests * @param string $clientIP The IP address to forward to Plausible - * + * * @return Plausible */ public function __construct(string $domain, string $apiKey, string $useragent, string $clientIP) @@ -79,9 +79,9 @@ public function __construct(string $domain, string $apiKey, string $useragent, s /** * Sends an event to Plausible. - * + * * @param Event $event The event to send. - * + * * @return bool */ public function send(Event $event): bool @@ -115,9 +115,9 @@ public function send(Event $event): bool /** * Provision a goal for the given event. - * + * * @param string $eventName The name of the event. - * + * * @return bool */ private function provisionGoal(string $eventName): bool @@ -156,6 +156,7 @@ public function validate(Event $event): bool 'filters' => json_encode(["goal" => $event->getName()]), ]); + /** @var string $checkCreated */ $checkCreated = $this->call('GET', $validateURL, [ 'Content-Type' => '', 'Authorization' => 'Bearer ' . $this->apiKey diff --git a/src/Analytics/Event.php b/src/Analytics/Event.php index 989135e..b93f49f 100644 --- a/src/Analytics/Event.php +++ b/src/Analytics/Event.php @@ -3,7 +3,7 @@ namespace Utopia\Analytics; class Event { - + /** * @var string (required) */ @@ -25,13 +25,13 @@ class Event { private ?string $value = null; /** - * @var array[] + * @var array */ private array $props = []; /** * Get the type of event - * + * * @return string */ public function getType(): string { @@ -40,7 +40,7 @@ public function getType(): string { /** * Set the type of event - * + * * @param string $type * @return Event */ @@ -51,7 +51,7 @@ public function setType(string $type): self { /** * Get the URL of the event - * + * * @return string */ public function getUrl(): string { @@ -60,7 +60,7 @@ public function getUrl(): string { /** * Set the URL of the event - * + * * @param string $url * @return Event */ @@ -71,7 +71,7 @@ public function setUrl(string $url): self { /** * Get the name of the event - * + * * @return string */ public function getName(): string { @@ -80,7 +80,7 @@ public function getName(): string { /** * Set the name of the event - * + * * @param string $name * @return Event */ @@ -91,7 +91,7 @@ public function setName(string $name): self { /** * Get the value of the event - * + * * @return string|null */ public function getValue(): ?string { @@ -100,7 +100,7 @@ public function getValue(): ?string { /** * Set the value of the event - * + * * @param string|null $value * @return Event */ @@ -111,8 +111,8 @@ public function setValue(?string $value): self { /** * Get the properties of the event - * - * @return array[] + * + * @return array */ public function getProps(): array { return $this->props; @@ -120,7 +120,7 @@ public function getProps(): array { /** * Adds extra properties to the event - * + * * @param string $key * @param string $value * @return Event @@ -132,7 +132,7 @@ public function addProp(string $key, string $value): self { /** * Removes a property from the event - * + * * @param string $key * @return Event */ @@ -145,7 +145,7 @@ public function removeProp(string $key): self { /** * Get a property from the event - * + * * @param string $key * @return mixed */ @@ -158,12 +158,12 @@ public function getProp(string $key): mixed { /** * Set the properties of the event - * - * @param array[] $props + * + * @param array $props * @return Event */ public function setProps(array $props): self { $this->props = $props; return $this; } -} \ No newline at end of file +} diff --git a/tests/Analytics/AnalyticsTest.php b/tests/Analytics/AnalyticsTest.php index 1bfb3b5..86c8411 100644 --- a/tests/Analytics/AnalyticsTest.php +++ b/tests/Analytics/AnalyticsTest.php @@ -12,16 +12,16 @@ class AnalyticsTest extends TestCase { - /** @var \Utopia\Analytics\Adapter\GoogleAnalytics $ga */ + /** @var GoogleAnalytics $ga */ public $ga; - /** @var \Utopia\Analytics\Adapter\ActiveCampaign|null $ac */ + /** @var ActiveCampaign|null $ac */ public $ac; - /** @var \Utopia\Analytics\Adapter\Plausible $pa */ + /** @var Plausible $pa */ public $pa; - /** @var \Utopia\Analytics\Adapter\Orbit $orbit */ + /** @var Orbit $orbit */ public $orbit; public function __construct() @@ -74,7 +74,7 @@ public function testGoogleAnalytics(): void $this->assertFalse($this->ga->validate($normalEvent)); } - public function testPlausible() + public function testPlausible(): void { $pageviewEvent = new Event(); $pageviewEvent @@ -83,7 +83,7 @@ public function testPlausible() $normalEvent = new Event(); $normalEvent->setType('testEvent') - ->setName('testEvent'.chr(mt_rand(97, 122)).substr(md5(time()), 1, 5)) + ->setName('testEvent'.chr(mt_rand(97, 122)).substr(md5(strval(time())), 1, 5)) ->setUrl('https://www.appwrite.io/docs/installation') ->setProps(['category' => 'testEvent']);; @@ -92,11 +92,16 @@ public function testPlausible() $this->assertTrue($this->pa->validate($normalEvent)); } - public function testActiveCampaignCreateContact() { + public function testActiveCampaignCreateContact(): void + { $this->assertTrue($this->ac->createContact('analytics2@utopiaphp.com', 'Analytics', 'Utopia')); } - public function testActiveCampaignGetContact() { + /** + * @return array + */ + public function testActiveCampaignGetContact(): array + { $contactID = $this->ac->contactExists('analytics2@utopiaphp.com'); $this->assertIsNumeric($contactID); @@ -105,14 +110,20 @@ public function testActiveCampaignGetContact() { ]; } - public function testActiveCampaignCreateAccount() { - $this->assertTrue($this->ac->createAccount('Example Account 1', 'https://example.com', '1234567890')); + public function testActiveCampaignCreateAccount(): void + { + $this->assertTrue($this->ac->createAccount('Example Account 1', 'https://example.com', 1234567890)); } /** * @depends testActiveCampaignGetContact + * + * @param array $data + * + * @return array */ - public function testActiveCampaignGetAccount($data) { + public function testActiveCampaignGetAccount($data): array + { $accountID = $this->ac->accountExists('Example Account 1'); $this->assertIsNumeric($accountID); @@ -123,47 +134,60 @@ public function testActiveCampaignGetAccount($data) { /** * @depends testActiveCampaignGetAccount + * + * @param array $data */ - public function testActiveCampaignSyncAsociation($data) { + public function testActiveCampaignSyncAsociation($data): void + { $this->assertTrue($this->ac->syncAssociation($data['accountID'], $data['contactID'], 'Owner')); $this->assertTrue($this->ac->syncAssociation($data['accountID'], $data['contactID'], 'Software Developer')); } /** * @depends testActiveCampaignGetContact + * + * @param array $data */ - public function testActiveCampaignUpdateContact($data) { + public function testActiveCampaignUpdateContact($data): void + { $this->assertTrue($this->ac->updateContact($data['contactID'], 'analytics2@utopiaphp.com', '', '', '7223224241')); } - public function testActiveCampaignDeleteContact() { + public function testActiveCampaignDeleteContact(): void + { $this->assertTrue($this->ac->deleteContact('analytics2@utopiaphp.com')); } /** * @depends testActiveCampaignGetAccount + * + * @param array $data */ - public function testActiveCampaignUpdateAccount($data) { + public function testActiveCampaignUpdateAccount($data): void { $this->assertTrue($this->ac->updateAccount( - $data['accountID'], - 'Utopia', - 'utopia.com', + $data['accountID'], + 'Utopia', + 'utopia.com', 1)); } /** * @depends testActiveCampaignGetAccount + * + * @param array $data */ - public function testActiveCampaignDeleteAccount($data) { + public function testActiveCampaignDeleteAccount($data): void + { $this->assertTrue($this->ac->deleteAccount($data['accountID'])); } - public function testActiveCampaign() { + public function testActiveCampaign(): void + { $this->assertTrue($this->ac->createContact('analytics@utopiaphp.com', 'Analytics', 'Utopia')); $event = new Event(); $event->setType('testEvent') - ->setName('testEvent'.chr(mt_rand(97, 122)).substr(md5(time()), 1, 5)) + ->setName('testEvent'.chr(mt_rand(97, 122)).substr(md5(strval(time())), 1, 5)) ->setUrl('https://www.appwrite.io/docs/installation') ->setProps(['category' => 'analytics:test', 'email' => 'analytics@utopiaphp.com', 'tags' => ['test', 'test2']]);