Skip to content
This repository has been archived by the owner on Aug 31, 2022. It is now read-only.

Commit

Permalink
use-redis-caching-#89 (#91)
Browse files Browse the repository at this point in the history
* Configure redis

* Refactor existing session implementation

* Add redis cart helper

* Replace cache cart helper with redis
  • Loading branch information
kkamara committed Feb 5, 2022
1 parent ffd291a commit a35d064
Show file tree
Hide file tree
Showing 21 changed files with 900 additions and 589 deletions.
7 changes: 3 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ LOG_LEVEL=debug
FORWARD_SELENIUM_PORT=4000
DUSK_DRIVER_URL=http://localhost:%s/wd/hub

REDIS_CLIENT=predis
REDIS_URL=redis://:@redis:6379

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
Expand All @@ -35,10 +38,6 @@ SESSION_LIFETIME=120

MEMCACHED_HOST=127.0.0.1

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
Expand Down
23 changes: 18 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,19 @@ jobs:
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
strategy:
fail-fast: false
matrix:
php-versions: ['8.1.1']
php-versions: ['8.1.2']
steps:
- name: Checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -46,10 +55,14 @@ jobs:
- name: Setup Env Variables
run: |
cp .env.example .env
sed -i -e "s/APP_URL=http:\/\/localhost/APP_URL=http:\/\/127.0.0.1:8000/g" .env
sed -i -e "s/3306/${{ job.services.mysql.ports['3306'] }}/g" .env
sed -i -e "s/DB_HOST=mysql/DB_HOST=127.0.0.1/g" .env
sed -i -e "s/local/testing/g" .env
sed -i "s/APP_URL=http:\/\/localhost/APP_URL=http:\/\/127.0.0.1:8000/g" .env
sed -i "s/3306/${{ job.services.mysql.ports['3306'] }}/g" .env
sed -i "s/DB_HOST=mysql/DB_HOST=127.0.0.1/g" .env
sed -i "s/@redis/@localhost/g" .env
sed -i "s/APP_ENV=local/APP_ENV=testing/g" .env
cat .env
- name: Clear config cache
run: php artisan config:clear
- name: Generate key
run: php artisan key:generate -q -n
- name: Migrate & Seed Database
Expand Down
23 changes: 23 additions & 0 deletions app/Helpers/CommonHelper.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?php

namespace App\Helpers;

use RuntimeException;

/**
* Returns an alphabetical map of country values
* with the respective abbreviations as keys.
Expand All @@ -20,3 +24,22 @@ function awsCredsExist() {
true === isset($_ENV['AWS_DEFAULT_REGION']) &&
true === isset($_ENV['AWS_BUCKET']);
}

/**
* Get a unique fingerprint for the request / route / IP address.
*
* @throws \RuntimeException
* @return string
*/
function fingerprint()
{
$request = request();

if (! $route = $request->route()) {
throw new RuntimeException('Unable to generate fingerprint. Route unavailable.');
}

return sha1(implode('|', [
$route->getDomain(), $request->ip()
]));
}
192 changes: 192 additions & 0 deletions app/Helpers/RedisCartHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?php

namespace App\Helpers;

use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Predis\Client;
use App\Models\Product\Product;
use function App\Helpers\fingerprint;

class RedisCartHelper
{
/**
* Use caching service for querying guest user identifier
* @param Client $client
*/
public function __construct(protected ?Client $client = null) {
$this->client = new Client(config('database.redis.default.url'));
}

/**
* @param Mixed $key
* @return Mixed
*/
public function get($key): mixed {
if (!$this->client->exists($key)) {
return null;
}
$result = $this->client->get($key);
return json_decode($result, 1);
}

/**
* @param Mixed $key
* @param Mixed $value
* @return Mixed
*/
public function set($key, $value): mixed {
return $this->client->set(
$key,
json_encode($value),
'EX',
config('session.lifetime'),
);
}

/**
* @param Array|String $keys
* @return Integer
*/
public function del(string $keys): int {
if (!$this->client->exists($keys)) {
return 0;
}
return $this->client->del($keys);
}

/**
* @return Mixed
*/
public function getRedisCart(): mixed {
return $this->get($this->getGuestIdentifier());
}

/**
* @return Mixed
*/
public function getGuestIdentifier(): string {
return fingerprint();
}

/**
* @param Mixed $value
* @return Mixed
*/
private function setGuestIdentifier($value): mixed {
return true;
}

/**
* Adds a product to the user's session cart.
*
* @param \App\Models\Product $product
*/
public function addProductToSessionCart(Product $product)
{
/** Get existing session cookie if set */
$sessionCart = $this->get($this->getGuestIdentifier());

/** Check is existing cookie is present */
if($sessionCart !== NULL && is_array($sessionCart))
{
$productAlreadyAdded = FALSE;
/** Check if this product already exists in cart */
foreach($sessionCart as $cc)
{
if(is_array($cc) && in_array($product->id, $cc))
{
$productAlreadyAdded = TRUE;
}
}
/** Add new product to session cart if not already present */
if($productAlreadyAdded == FALSE)
{
$newItem = array(
'product' => $product->id,
'amount' => 1,
);
array_push($sessionCart, $newItem);
$this->set($this->getGuestIdentifier(), $sessionCart);
}
}
else
{
/** Set a new session cart cookie with product as it's first item */
$sessionCart = array(
array(
'product' => $product->id,
'amount' => 1,
)
);
$this->set($this->getGuestIdentifier(), $sessionCart);
}
}

/**
* Returns the user's session cart.
*
* @return array
*/
public function getSessionCart()
{
$sessionCart = $this->get($this->getGuestIdentifier());
$array = array();

if(isset($sessionCart))
{
foreach($sessionCart as $cc)
{
$item = Product::where('id', $cc['product'])->first();
$amount = $cc['amount'];

array_push($array, array(
'product' => $item,
'amount' => $amount
));
}
}

return $array;
}

/**
* Updates the respective number of products in the user's session cart.
*
* @param \Illuminate\Http\Request $request
*/
public function updateSessionCartAmount(Request $request)
{
/** Get existing session cart */
$sessionCart = $this->getSessionCart();
$array = array();

foreach($sessionCart as $cc)
{
/** Check if an amount value for this product was given in the request */
$product_id = $cc['product']->id;
$amount = $request->get('amount-' . $product_id);

if($amount !== NULL && $amount != 0)
{
/** Push to $array the product with new amount value */
array_push($array, array(
'product' => $product_id,
'amount' => (int) $amount,
));
}
}

/** Set session cart equal to our updated products array */
$this->set($this->getGuestIdentifier(), $array);
}

/**
* Remove the session cart cookie.
*/
public function clearSessionCart()
{
$this->del($this->getGuestIdentifier());
}
}
42 changes: 32 additions & 10 deletions app/Helpers/SessionCartHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,41 @@

class SessionCartHelper
{
/**
* @param String $key
* @param Mixed $default (optional)
* @return Mixed
*/
public function get(string $key, $default = null): mixed {
return Session::get($key, $default);
}

/**
* @param String|Array $key
* @param Mixed $value (optional)
* @return Mixed
*/
public function put(string $key, $value = null): mixed {
return Session::put($key, $value);
}

/**
* @param String|Array $keys
* @return mixed
*/
public function forget(string $keys): mixed {
return Session::forget($keys);
}

/**
* Adds a product to the user's session cart.
*
* @param \App\Models\Product $product
*/
public function addProductToSessionCart(Product $product)
{
/** Cookie will expire in 120 minutes */
$expiresAt = now()->addMinutes(120);

/** Get existing session cookie if set */
$sessionCart = Session::get('cc');
$sessionCart = $this->get('cc');

/** Check is existing cookie is present */
if($sessionCart !== NULL && is_array($sessionCart))
Expand All @@ -41,7 +64,7 @@ public function addProductToSessionCart(Product $product)
'amount' => 1,
);
array_push($sessionCart, $newItem);
Session::put('cc', $sessionCart, $expiresAt);
$this->put('cc', $sessionCart);
}
}
else
Expand All @@ -53,7 +76,7 @@ public function addProductToSessionCart(Product $product)
'amount' => 1,
)
);
Session::put('cc', $sessionCart, $expiresAt);
$this->put('cc', $sessionCart);
}
}

Expand All @@ -64,7 +87,7 @@ public function addProductToSessionCart(Product $product)
*/
public function getSessionCart()
{
$sessionCart = Session::get('cc');
$sessionCart = $this->get('cc');
$array = array();

if(isset($sessionCart))
Expand Down Expand Up @@ -112,15 +135,14 @@ public function updateSessionCartAmount(Request $request)
}

/** Set session cart equal to our updated products array */
$expiresAt = now()->addMinutes(120);
Session::put('cc', $array, $expiresAt);
$this->put('cc', $array);
}

/**
* Remove the session cart cookie.
*/
public function clearSessionCart()
{
Session::forget('cc');
$this->forget('cc');
}
}
Loading

0 comments on commit a35d064

Please sign in to comment.