Skip to content

Commit

Permalink
Defer ReCaptcha
Browse files Browse the repository at this point in the history
The Charcoal service no longer requires Google's `ReCaptcha` class to be created first; the client is managed internally and deferred until needed.

Removed:
- "google/recaptcha" from service provider; handled internally by `Captcha` class

Added:
- `Captcha::setClientClass()` for customizing the deferred `ReCaptcha` class
- `Captcha::createClient()` for instantiating the `ReCaptcha` class

Changed:
- "charcoal/captcha" to improve instantiation of `Captcha` class
- `Captcha` to support custom `ReCaptcha` class
- `Captcha` to defer creation of `ReCaptcha` object
- Improve examples in README
  • Loading branch information
mcaskill committed May 23, 2018
1 parent d738e8e commit c6fe0bd
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 30 deletions.
56 changes: 47 additions & 9 deletions README.md
Expand Up @@ -42,19 +42,15 @@ See [`composer.json`](composer.json) for depenencides.
## Usage

```php
use ReCaptcha\ReCaptcha;
use Charcoal\ReCaptcha\Captcha;

$container[ReCaptcha::class] = new ReCaptcha($key);
$container[Captcha::class] = new Captcha([
$captcha = new Captcha([
'config' => [
'public_key' => '…'
],
'client' => $container[ReCaptcha::class]
'public_key' => '…',
'private_key' => '…',
]
]);

$captcha = $container[Captcha::class];

// As middleware
$app->post('/signup', '…')->add($captcha);

Expand All @@ -76,6 +72,49 @@ echo $captcha->display(
);
```

By default, the `Captcha` adapter will defer the instantiation of [`ReCaptcha`][class-recaptcha] until the first verification request.



### Custom ReCaptcha Class

The `ReCaptcha` class be swapped using the `client_class` option.

```php
use Charcoal\ReCaptcha\Captcha;
use MyApp\ MyCustomReCaptcha;

$captcha = new Captcha([
'config' => [
'public_key' => '…',
'private_key' => '…',
],
'client_class' => MyCustomReCaptcha::class
]);
```



### Custom ReCaptcha Instance

An instance of the `ReCaptcha` class can be assigned using the `client` option.

```php
use Charcoal\ReCaptcha\Captcha;
use ReCaptcha\ReCaptcha;
use ReCaptcha\RequestMethod\CurlPost;

$client = new ReCaptcha('…', new CurlPost());

$captcha = new Captcha([
'config' => [
'public_key' => '…',
'private_key' => '…',
],
'client' => $client
]);
```



## Service Provider
Expand All @@ -93,7 +132,6 @@ If [`CaptchaServiceProvider`](src/CaptchaServiceProvider.php) is used, the follo
### Services

- **charcoal/captcha**: An instance of [`Captcha`](src/CaptchaConfig.php).
- **google/recaptcha**: An instance of Google's [`ReCaptcha`][class-recaptcha].



Expand Down
63 changes: 62 additions & 1 deletion src/Captcha.php
Expand Up @@ -45,6 +45,13 @@ class Captcha
*/
private $client;

/**
* Default "ReCaptcha" class to use for making a new client.
*
* @var string
*/
protected $clientClass = ReCaptcha::class;

/**
* Store the last ReCaptcha response.
*
Expand All @@ -59,7 +66,14 @@ class Captcha
public function __construct(array $data)
{
$this->setConfig($data['config']);
$this->setClient($data['client']);

if (isset($data['client'])) {
$this->setClient($data['client']);
}

if (isset($data['client_class'])) {
$this->setClientClass($data['client_class']);
}
}

/**
Expand Down Expand Up @@ -97,13 +111,30 @@ protected function createConfig($data = null)
return new CaptchaConfig($data);
}

/**
* Create a new ReCaptcha instance.
*
* @param string $secret Shared secret between site and reCAPTCHA server.
* @param mixed[] $args Additional {@see \ReCaptcha\ReCaptcha::__construct() constructor parameters}.
* @return ReCaptcha
*/
protected function createClient($secret, ...$args)
{
array_unshift($args, $secret);
return new $this->clientClass(...$args);
}

/**
* Retrieve the ReCaptcha client.
*
* @return ReCaptcha
*/
public function client()
{
if ($this->client === null) {
$this->client = $this->createClient($this->config('private_key'));
}

return $this->client;
}

Expand All @@ -118,6 +149,36 @@ private function setClient(ReCaptcha $client)
$this->client = $client;
}

/**
* Changes the specific client class generated by the Captcha wrapper.
*
* Using this function developers can have the wrapper generate a custom ReCaptcha object.
*
* @param string $class The ReCaptcha class name.
* @throws InvalidArgumentException When passed an invalid or nonexistant class.
* @return void
*/
private function setClientClass($class)
{
if (!class_exists($class)) {
throw new InvalidArgumentException(
sprintf('Client class %s does not exist', $class)
);
}

$interfaces = class_implements($class, true);

if (!in_array(ReCaptcha::class, $interfaces)) {
throw new InvalidArgumentException(sprintf(
'Client class %s must inherit from %s',
$class,
ReCaptcha::class
));
}

$this->clientClass = $class;
}

/**
* Call the reCAPTCHA API to verify whether the user passes CAPTCHA test.
*
Expand Down
27 changes: 7 additions & 20 deletions src/CaptchaServiceProvider.php
Expand Up @@ -39,35 +39,22 @@ public function register(Container $container)
return new CaptchaConfig($appConfig['apis.google.recaptcha']);
};

/**
* Add the Google reCaptcha Client
*
* @param Container $container A container instance.
* @return ReCaptcha
*/
$container['google/recaptcha'] = function (Container $container) {
$captchaConfig = $container['charcoal/captcha/config'];
return new ReCaptcha($captchaConfig['private_key']);
};

/**
* Add the Charcoal reCaptcha Service
*
* @param Container $container A container instance.
* @return Captcha
*/
$container['charcoal/captcha'] = function (Container $container) {
$args = [
'config' => $container['charcoal/captcha/config']
];

if (isset($container['translator'])) {
$captcha = new LocalizedCaptcha([
'config' => $container['charcoal/captcha/config'],
'client' => $container['google/recaptcha'],
'translator' => $container['translator']
]);
$args['translator'] = $container['translator'];
$captcha = new LocalizedCaptcha($args);
} else {
$captcha = new Captcha([
'config' => $container['charcoal/captcha/config'],
'client' => $container['google/recaptcha']
]);
$captcha = new Captcha($args);
}

return $captcha;
Expand Down

0 comments on commit c6fe0bd

Please sign in to comment.