Skip to content

Commit

Permalink
Merge pull request #74 from netflie/2.x-dev
Browse files Browse the repository at this point in the history
2.x version
  • Loading branch information
aalbarca authored Jan 29, 2023
2 parents d471e61 + e413979 commit 3cd61dc
Show file tree
Hide file tree
Showing 83 changed files with 3,340 additions and 470 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ composer.phar
/tests/WhatsAppCloudApiTestConfiguration.php
.phpunit.result.cache
composer.lock
.php-cs-fixer.cache
.php-cs-fixer.cache
.idea/
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
repos:
- repo: https://github.com/digitalpulp/pre-commit-php.git
rev: 1.4.0
hooks:
- id: php-cs-fixer
files: \.(php)$
exclude: ^(vendor)
87 changes: 87 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,84 @@ $whatsapp_cloud_api->sendList(
);
```

## Media messages
### Upload media resources
Media messages accept as identifiers an Internet URL pointing to a public resource (image, video, audio, etc.). When you try to send a media message from a URL you must instantiate the `LinkID` object.

You can also upload your media resources to WhatsApp servers and you will receive a resource identifier:

```php
$response = $whatsapp_cloud_api->uploadMedia('my-image.png');

$media_id = new MediaObjectID($response->decodedBody()['id']);
$whatsapp_cloud_api->sendImage('<destination-phone-number>', $media_id);

```

### Upload media resources
To download a media resource:

```php
$response = $whatsapp_cloud_api->downloadMedia('<media-id>');
```


## Message Response
WhatsAppCloudApi instance returns a Response class or a ResponseException if WhatsApp servers return an error.

```php
try {
$response = $this->whatsapp_app_cloud_api->sendTextMessage(
'<destination-phone-number>,
'Hey there! I\'m using WhatsApp Cloud API. Visit https://www.netflie.es',
true
);
} catch (\Netflie\WhatsAppCloudApi\Response\ResponseException $e) {
print_r($e->response()); // You can still check the Response returned from Meta servers
}
```

## Webhooks

### Webhook verification
Add your webhook in your Meta App dashboard. You need to verify your webhook:

```php
<?php
require 'vendor/autoload.php';

use Netflie\WhatsAppCloudApi\WebHook;

// Instantiate the WhatsAppCloudApi super class.
$webhook = new WebHook();

return $webhook->verify($_GET, "<the-verify-token-defined-in-your-app-dashboard>");
```

### Webhook notifications
Webhook is now verified, you will start receiving notifications every time your customers send messages.


```php
<?php
require 'vendor/autoload.php';
define('STDOUT', fopen('php://stdout', 'w'));

use Netflie\WhatsAppCloudApi\WebHook;


$payload = file_get_contents('php://input');
fwrite(STDOUT, print_r($payload, true) . "\n");

// Instantiate the Webhook super class.
$webhook = new WebHook();


fwrite(STDOUT, print_r($webhook->read(json_decode($payload, true)), true) . "\n");
```

The `Webhook::read` function will return a `Notification` instance. Please, [explore](https://github.com/netflie/whatsapp-cloud-api/tree/main/src/WebHook/Notification "explore") the different notifications availables.

## Features

- Send Text Messages
Expand All @@ -234,11 +312,20 @@ $whatsapp_cloud_api->sendList(
- Send Locations
- Send Contacts
- Send Lists
- Upload media resources to WhatsApp servers
- Download media resources from WhatsApp servers
- Mark messages as read
- Webhook verification
- Webhook notifications

## Getting Help
- Ask a question on the [Discussions forum](https://github.com/netflie/whatsapp-cloud-api/discussions "Discussions forum")
- To report bugs, please [open an issue](https://github.com/netflie/whatsapp-cloud-api/issues/new/choose "open an issue")

## Migration to v2

Please see [UPGRADE](https://github.com/netflie/whatsapp-cloud-api/blob/main/UPGRADE.md "UPGRADE") for more information on how to upgrade to v2.

## Changelog

Please see [CHANGELOG](https://github.com/netflie/whatsapp-cloud-api/blob/main/CHANGELOG.md "CHANGELOG") for more information what has changed recently.
Expand Down
18 changes: 18 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Upgrade to v2

All instructions to upgrade this project from one major version to the next will be documented in this file. Upgrades must be run sequentially, meaning you should not skip major releases while upgrading (fix releases can be skipped).

## 1.x to 2.x

# Final classes
A lot of classes have been marked as final classes. If you have created new classes that extend any of them you will have to create new implementations. The reason for this change is to hide implementation details and avoid breaking versions in subsequent releases. Check the affected classes: https://github.com/netflie/whatsapp-cloud-api/commit/4cf094b1ff9a477eda34151a0e68fc7417950bbb

# Response errors
In previous versions when a request to WhatsApp servers failed a `GuzzleHttp\Exception\ClientException` exception was thrown. From now on a `Netflie\WhatsAppCloudApi\Response\ResponseException` exception will be thrown.

# Client
`Client::sendRequest(Request $request)` has been refactored to `Client::sendMessage(Request\RequestWithBody $request)`

# Request
Request class has been refactored: https://github.com/netflie/whatsapp-cloud-api/commit/17f76e90122d245aace6640a1f8766fb77c29ef6#diff-74d71c4d1f9d84b9b0d946ca96eb875274f95d60611611d84cc01cdf6ed04021L5

4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"phpunit/phpunit": "^9.0",
"symfony/var-dumper": "^5.0",
"phpspec/prophecy-phpunit": "^2.0",
"fakerphp/faker": "^1.19"
"fakerphp/faker": "^1.19",
"friendsofphp/php-cs-fixer": "^3.13",
"phpstan/phpstan": "^1.9"
},
"autoload": {
"psr-4": {
Expand Down
77 changes: 70 additions & 7 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ public function __construct(string $graph_version, ?ClientHandler $handler = nul
}

/**
* Return the original request that returned this response.
* Send a message request to.
*
* @return Response Raw response from the server.
*
* @throws Netflie\WhatsAppCloudApi\Response\ResponseException
*/
public function sendRequest(Request $request): Response
public function sendMessage(Request\RequestWithBody $request): Response
{
$raw_response = $this->handler->send(
$this->buildRequestUri($request),
$request->encodedBody(),
$raw_response = $this->handler->postJsonData(
$this->buildRequestUri($request->nodePath()),
$request->body(),
$request->headers(),
$request->timeout()
);
Expand All @@ -65,6 +65,69 @@ public function sendRequest(Request $request): Response
return $return_response;
}

/**
* Upload a media file to Facebook servers.
*
* @return Response Raw response from the server.
*
* @throws Netflie\WhatsAppCloudApi\Response\ResponseException
*/
public function uploadMedia(Request\MediaRequest\UploadMediaRequest $request): Response
{
$raw_response = $this->handler->postFormData(
$this->buildRequestUri($request->nodePath()),
$request->form(),
$request->headers(),
$request->timeout()
);

$return_response = new Response(
$request,
$raw_response->body(),
$raw_response->httpResponseCode(),
$raw_response->headers()
);

if ($return_response->isError()) {
$return_response->throwException();
}

return $return_response;
}

/**
* Download a media file from Facebook servers.
*
* @return Response Raw response from the server.
*
* @throws Netflie\WhatsAppCloudApi\Response\ResponseException
*/
public function downloadMedia(Request\MediaRequest\DownloadMediaRequest $request): Response
{
$raw_response = $this->handler->get(
$this->buildRequestUri($request->nodePath()),
$request->headers(),
$request->timeout()
);

$response = Response::fromClientResponse($request, $raw_response);
$media_url = $response->decodedBody()['url'];

$raw_response = $this->handler->get(
$media_url,
$request->headers(),
$request->timeout()
);

$return_response = Response::fromClientResponse($request, $raw_response);

if ($return_response->isError()) {
$return_response->throwException();
}

return $return_response;
}

private function defaultHandler(): ClientHandler
{
return new GuzzleClientHandler();
Expand All @@ -75,8 +138,8 @@ private function buildBaseUri(): string
return self::BASE_GRAPH_URL . '/' . $this->graph_version;
}

private function buildRequestUri(Request $request): string
private function buildRequestUri(string $node_path): string
{
return $this->buildBaseUri() . '/' . $request->fromPhoneNumberId() . '/messages';
return $this->buildBaseUri() . '/' . $node_path;
}
}
33 changes: 30 additions & 3 deletions src/Http/ClientHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,43 @@
interface ClientHandler
{
/**
* Sends a request to the server and returns the raw response.
* Sends a JSON POST request to the server and returns the raw response.
*
* @param string $url The endpoint to send the request to.
* @param string $body The body of the request.
* @param array $body The body of the request.
* @param array $headers The request headers.
* @param int $timeout The timeout in seconds for the request.
*
* @return RawResponse Response from the server.
*
* @throws Netflie\WhatsAppCloudApi\Response\ResponseException
*/
public function send(string $url, string $body, array $headers, int $timeout): RawResponse;
public function postJsonData(string $url, array $body, array $headers, int $timeout): RawResponse;

/**
* Sends a form POST request to the server and returns the raw response.
*
* @param string $url The endpoint to send the request to.
* @param array $form The form data of the request.
* @param array $headers The request headers.
* @param int $timeout The timeout in seconds for the request.
*
* @return RawResponse Response from the server.
*
* @throws Netflie\WhatsAppCloudApi\Response\ResponseException
*/
public function postFormData(string $url, array $form, array $headers, int $timeout): RawResponse;

/**
* Sends a GET request to the server and returns the raw response.
*
* @param string $url The endpoint to send the request to.
* @param array $headers The request headers.
* @param int $timeout The timeout in seconds for the request.
*
* @return RawResponse Response from the server.
*
* @throws Netflie\WhatsAppCloudApi\Response\ResponseException
*/
public function get(string $url, array $headers, int $timeout): RawResponse;
}
54 changes: 46 additions & 8 deletions src/Http/GuzzleClientHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
namespace Netflie\WhatsAppCloudApi\Http;

use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;

class GuzzleClientHandler implements ClientHandler
final class GuzzleClientHandler implements ClientHandler
{
/**
* @var \GuzzleHttp\Client The Guzzle client.
*/
protected $guzzle_client;
private $guzzle_client;

/**
* @param \GuzzleHttp\Client|null The Guzzle client.
Expand All @@ -23,18 +24,55 @@ public function __construct(?Client $guzzle_client = null)
* {@inheritDoc}
*
*/
public function send(string $url, string $body, array $headers, int $timeout): RawResponse
public function postJsonData(string $url, array $body, array $headers, int $timeout): RawResponse
{
$raw_handler_response = $this->guzzle_client->post($url, [
'body' => $body,
$raw_handler_response = $this->post($url, $body, 'json', $headers, $timeout);

return $this->buildResponse($raw_handler_response);
}

/**
* {@inheritDoc}
*
*/
public function postFormData(string $url, array $form, array $headers, int $timeout): RawResponse
{
$raw_handler_response = $this->post($url, $form, 'multipart', $headers, $timeout);

return $this->buildResponse($raw_handler_response);
}

/**
* {@inheritDoc}
*
*/
public function get(string $url, array $headers, int $timeout): RawResponse
{
$raw_handler_response = $this->guzzle_client->get($url, [
'headers' => $headers,
'timeout' => $timeout,
'http_errors' => false,
]);

return $this->buildResponse($raw_handler_response);
}

protected function post(string $url, array $data, string $data_type, array $headers, int $timeout): ResponseInterface
{
return $this->guzzle_client->post($url, [
$data_type => $data,
'headers' => $headers,
'timeout' => $timeout,
'http_errors' => false,
]);
}

protected function buildResponse(ResponseInterface $handler_response): RawResponse
{
return new RawResponse(
$raw_handler_response->getHeaders(),
$raw_handler_response->getBody(),
$raw_handler_response->getStatusCode()
$handler_response->getHeaders(),
$handler_response->getBody(),
$handler_response->getStatusCode()
);
}
}
Loading

0 comments on commit 3cd61dc

Please sign in to comment.