I have a use case where I need to have access to a quote_id
for a fairly large number of Middleware actions.
I have a set of entities such as Quote
, Order
, and others, that interact with the database via a repository layer, and repositories needs to have quote_id
available to them in order to access data pertaining to the entities. For example, user opens a Quote
, which becomes active, and most user actions on that Quote
require access to the quote_id
.
Current Design choices
Since quote_id
is so ubiquitous and frequently-used in my application, I put it into the session, so it is available most all the time, even when it is not explicitly needed.
When it is needed, I pull it out of the session, and inject it into constructor of a repository class. This effectively “locks in” the repository to that quote_id
and stays that way throughout the run-time of the request. And that is okay as so far I have not identified any use-cases where I need to have two or more different quote_id
numbers existing simultaneously.
Having $quoteId
being available as part of the repository itself also simplifies handling a bit, as I could refer to it as $this->quoteId
inside the repository. If I didn’t have $quoteId
be a part of the repository, I’d have to pass it as a parameter to every single method call of the repository, which would require me to maintain the value of $quoteId
elsewhere, such as a service or a middleware.
Problem
So, here is problem #1: In my factory, I use the session to get the quote_id
($_SESSION['quote_id']
) and inject its value into a repository of choice. The problem is that I do this before I have access to a ServerRequestInterface
object. I do this at “Factory” time, before request and session from request are available to me.
Also, it is not just the retrieval of the quote_id
that I do, I have a mechanism that first checks the $_GET
superglobal, because there is a use case where I may wish to override the $_SESSION with the $_GET, and so my code below takes care of that, as well as taking care of any validation checks on the id:
class QuoteIdFactory
{
public function __invoke(ContainerInterface $container)
{
if (isset($_GET['quote_id']))
$quoteId = filter_var($_GET['quote_id'], FILTER_VALIDATE_INT);
else if (isset($_SESSION['quote_id']))
$quoteId = filter_var($_SESSION['quote_id'], FILTER_VALIDATE_INT);
else
throw new \RuntimeException("Quote has not been initialized");
Assert::that($quoteId)->integer("Quote Id must be an integer")
->greaterThan(0, "Quote Id must be a positive integer");
return $quoteId;
}
}
I invoke this via container:
return [
'dependencies' => [
'factories' => [
'quoteId' => QuoteIdFactory::class
],
]
];
And when I need this id, I pull it out of the container, and I may inject it into a repository like so:
//in a Factory:
$quoteId = $container->get('quoteId');
$repository = new Repository($quoteId, ... );
//inside middleware/service:
$this->repository->retrieveQuote(); //uses `$this->quoteId` inside
Is there a way to redesign this so that it follows Expressive principles?
I assume the main one is to ensure that I pull GET and SESSION data from Request object, when I have access to the Request object, and not to use superglobal GET and SESSION variables, like I am doing now.