Skip to content

Commit

Permalink
I implemented a straightforward cookie collection mechanism that allo…
Browse files Browse the repository at this point in the history
…ws for project work from any place
  • Loading branch information
hcan359 committed Oct 21, 2024
1 parent 22f829d commit 8f3fbee
Show file tree
Hide file tree
Showing 9 changed files with 430 additions and 0 deletions.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,45 @@ $cookie = (new \Yiisoft\Cookies\Cookie('cookieName'))
->withRawValue('ebaKUq90PhiHck_MR7st-E1SxhbYWiTsLo82mCTbNuAh7rgflx5LVsYfJJseyQCrODuVcJkTSYhm1WKte-l5lQ==')
```

Work with cookie request collection from any place in you project. Add in config you app in middleware block
```php
'middlewares' => [
RequestCookieCollectionMiddleware::class,
...
],
```

Initial provider in di-web config
```php
return [
...,
RequestCookieProviderInterface::class => [
'class' => RequestCookieProvider::class,
],

```

Use as dependency in any part of ur code
```php

use \Yiisoft\Cookies\RequestCookieProviderInterface;

final class MyService
{
public function __construct(
private RequestCookieProviderInterface $requestCookieProvider
)
{
}

public function doIt()
{
$cookieCollection = $this->requestCookieProvider->get();
// ...
}
}
```
```
## Documentation
- [Internals](docs/internals.md)
Expand Down
19 changes: 19 additions & 0 deletions src/Exception/RequestCookieCollectionNotSetException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Cookies\Exception;

use LogicException;
use Throwable;

/**
* Thrown when Request cookie collect isn't set before.
*/
final class RequestCookieCollectionNotSetException extends LogicException
{
public function __construct(int $code = 0, ?Throwable $previous = null)

Check warning on line 15 in src/Exception/RequestCookieCollectionNotSetException.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ */ final class RequestCookieCollectionNotSetException extends LogicException { - public function __construct(int $code = 0, ?Throwable $previous = null) + public function __construct(int $code = -1, ?Throwable $previous = null) { parent::__construct('Request cookie collect is not set.', $code, $previous); } }

Check warning on line 15 in src/Exception/RequestCookieCollectionNotSetException.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": --- Original +++ New @@ @@ */ final class RequestCookieCollectionNotSetException extends LogicException { - public function __construct(int $code = 0, ?Throwable $previous = null) + public function __construct(int $code = 1, ?Throwable $previous = null) { parent::__construct('Request cookie collect is not set.', $code, $previous); } }
{
parent::__construct('Request cookie collect is not set.', $code, $previous);
}
}
82 changes: 82 additions & 0 deletions src/RequestCookieCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Cookies;

use InvalidArgumentException;

/**
* A CookieCollection helps to work with many cookies at once and to read request cookies.
*
* @see Cookie
*
*/
final class RequestCookieCollection
{
/**
* @var Cookie[] The cookies in this collection (indexed by the cookie name).
*
* @psalm-var array<string, Cookie>
*/
private array $cookies = [];

/**
* CookieCollection constructor.
*
* @param array|Cookie[] $cookies The cookies that this collection initially contains.
*/
public function __construct(array $cookies = [])
{
foreach ($cookies as $cookie) {
if (!($cookie instanceof Cookie)) {
throw new InvalidArgumentException('CookieCollection can contain only Cookie instances.');
}

$this->cookies[$cookie->getName()] = $cookie;
}
}

/**
* Returns the value of the named cookie.
*
* @param string $name The cookie name.
* @param string|null $defaultValue The value that should be returned when the named cookie does not exist.
*
* @return string|null The value of the named cookie or the default value if cookie is not set.
*
* @see get()
*/
public function getValue(string $name, ?string $defaultValue = null): ?string
{
return isset($this->cookies[$name]) ? $this->cookies[$name]->getValue() : $defaultValue;
}

/**
* Returns the cookie with the specified name.
*
* @param string $name The cookie name.
*
* @return Cookie|null The cookie with the specified name. Null if the named cookie does not exist.
*
* @see getValue()
*/
public function get(string $name): ?Cookie
{
return $this->cookies[$name] ?? null;
}

/**
* Returns whether there is a cookie with the specified name.
*
* @param string $name The cookie name.
*
* @return bool Whether the named cookie exists.
*
* @see remove()
*/
public function has(string $name): bool
{
return isset($this->cookies[$name]);
}
}
43 changes: 43 additions & 0 deletions src/RequestCookieCollectionMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Cookies;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
* Stores cookies request {@see RequestCookieProviderInterface}.
* You need to add this into your application middleware stack.
*/
final class RequestCookieCollectionMiddleware implements MiddlewareInterface
{
private RequestCookieProviderInterface $cookieProvider;

public function __construct(RequestCookieProviderInterface $cookieProvider)
{
$this->cookieProvider = $cookieProvider;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$cookies = $this->collectCookies($request);
$this->cookieProvider->set(new RequestCookieCollection($cookies));
return $handler->handle($request);
}

private function collectCookies(ServerRequestInterface $request): array
{
$collection = [];
foreach ($request->getCookieParams() as $name => $value) {
if (!is_string($name) || !is_string($value)) {
continue;
}
$collection[] = (new Cookie($name, $value));
}
return $collection;
}
}
32 changes: 32 additions & 0 deletions src/RequestCookieProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Cookies;

use Yiisoft\Cookies\Exception\RequestCookieCollectionNotSetException;

/**
* Stores request for further consumption by attribute handlers.
*/
final class RequestCookieProvider implements RequestCookieProviderInterface
{
/**
* @var RequestCookieCollection|null The collection.
*/
private ?RequestCookieCollection $cookieCollection = null;

public function set(RequestCookieCollection $cookieCollection): void
{
$this->cookieCollection = $cookieCollection;
}

public function get(): RequestCookieCollection
{
if ($this->cookieCollection === null) {
throw new RequestCookieCollectionNotSetException();
}

return $this->cookieCollection;
}
}
27 changes: 27 additions & 0 deletions src/RequestCookieProviderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Cookies;

use Yiisoft\Cookies\Exception\RequestCookieCollectionNotSetException;

/**
* Provides a way to set the current cookie collection and then get it when needed.
*/
interface RequestCookieProviderInterface
{
/**
* Set the current cookie request collection.
*
* @param RequestCookieCollection $cookieCollection The collection to set.
*/
public function set(RequestCookieCollection $cookieCollection): void;

/**
* Get the current request cookie collection.
*
* @throws RequestCookieCollectionNotSetException
*/
public function get(): RequestCookieCollection;
}
49 changes: 49 additions & 0 deletions tests/LocalCookieCollectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Cookies\Tests;

use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Yiisoft\Cookies\Cookie;
use Yiisoft\Cookies\RequestCookieCollection;

final class LocalCookieCollectionTest extends TestCase
{
public function testConstructorWithInvalidArray(): void
{
$this->expectException(InvalidArgumentException::class);
new RequestCookieCollection([new Cookie('test'), 'string']);
}

public function testGet(): void
{
$cookie = new Cookie('test');
$collection = new RequestCookieCollection([$cookie]);
$this->assertEquals($cookie, $collection->get('test'));
}

public function testGetNonExisting(): void
{
$collection = new RequestCookieCollection([]);
$this->assertEquals(null, $collection->get('test'));
}

public function testGetValue(): void
{
$cookie = new Cookie('test', 'testVal');
$collection = new RequestCookieCollection([$cookie]);

$this->assertEquals('testVal', $collection->getValue('test'));
}

public function testExpireWithNonExistingKey(): void
{
$cookie = new Cookie('test', 'testVal');
$collection = new RequestCookieCollection([$cookie]);

$this->assertTrue($collection->has('test'));
$this->assertFalse($collection->has('test2'));
}
}
Loading

0 comments on commit 8f3fbee

Please sign in to comment.