Presenters and linking without Request
- mishak
- Member | 94
Code is meta. This is blunt as I can be, if you still don't understand what am I proposing ask me directly. Will try my best to explain it.
Introduction
Common Problem: Generate emails from latte templates is still difficult and messy (using lot of anti-patterns).
Meta Problem: Generating link in CLI requires mocking http request and
presenter Request
. Using UI macro {link}
in CLI
requires extra work. By CLI I mean anything but environment that has data
for HttpRequest available.
There are several points that are in dire need of refactoring and in sum would allow for clean and practical solution to both problems.
Benefits
- Generating application URLs without presenter in a clean way. CLI, tests, links without request.
- Simplification of
{link}
macro logic. - @mkoubik Integrations of Latte into other frameworks wouldn't have to reimplement the {link} macro.
- Link caching
Roadmap
Hereby I propose refactoring all related functionality by inverting dependencies into multiple classes.
- Splitting
Presenter::createRequest
toRequestFactory
- Extracting
LinkGenerator
fromPresenter::link
- Refactoring
PresenterComponent::link
to useLinkGenerator
. - Refactoring
{link}
macro - There should be enough code for own package
nette/application-link
with {link} macro. optional
Splitting Presenter::createRequest
to
RequestFactory
Similar to Presenter::createTemplate
but much harder.
Should use context object to carry dependencies on Presenter or component. It
might help to offload Presenter
and component
logic to such contexts.
Context can be in later stage created from ILinkContext
.
Extracting LinkGenerator
from
PresenterComponent::link
class LinkGenerator {
function __constructor(IRouter, ILinkSetup);
function link(...[, ILinkContext $ctx = NULL]) {
if ($ctx === NULL) $ctx = new AbsoluteLinkContext;
...
}
}
class HttpRequestLinkSetup implements ILinkSetup {
function __constructor(HttpRequest);
}
class ConstantLinkSetup ... {
static function fromUrl($url);
function __construct(/* pass [<protocol>://]<host>[:<port>][/<path>] */);
}
// ... Presenter, Control and AbsoluteLinkContext
LinkContext would be responsible for determining absolute/relative url. It
could have space for additional logic that does not fit
LinkGenerator
.
LinkGenerator will be available as service in DI.
Refactoring PresenterComponent::link
class PresenterComponent {
function link(...) {
$this->linkGenerator->link(..., new PresenterContext($this));
}
}
Refactoring {link}
macro
{link}
macro would require template to have
$_linkGenerator
and $_linkContext
to work. With
optional $_presenterLinkContext
for {plink} functionality. Contexts
can be generated in BC manner
# {link}
isset($_linkContext) ? $_linkContext : new ControlLinkContext($_control)
# {plink}
isset($_presenterLinkContext) ? $_presenterLinkContext: new PresenterLinkContext(isset($_presenter) ? $_presenter : $_control->getPresenter()))
ILinkContext purpose – sub-topic to discuss – light vs. heavy
Complexity of ILinkContext will depend on result of
Presenter::createRequest
and Presenter::link
refactoring. Their main purpose is to pass necessary information for building
links to LinkGenerator
.
They could just pass $relativePathEnabled
,
$presenter
or $control
. Or carry logic that utilizes
these parameters so LinkGenerator
does not have to know
about them.
I came up with them as a solution for passing information that would unify
use of link without explicit need of $_presenter
or
$_component
in template. In result {plink}
and
{link}
would be reduced only to different contexts.
AbsoluteLinkContext
would be complementary as solution (not only)
for email templates which would no longer need $_presenter
in
template with {link}
macros.
Work done by others (might not be related)
- Panda is refactoring request factory.
- Jan Tvrdik has done link factory.
EDIT: Added explanation of ILinkContext
Thanks Filip!
EDIT2: Expanded a bit about Presenter::createRequest
.
Last edited by mishak (2014-06-16 03:01)
- David Grudl
- Nette Core | 8228
Generating link in CLI requires mocking http request and presenter.
Are you sure? https://github.com/…/IRouter.php#L36
- mishak
- Member | 94
Yes. IRouter
is not the URL factory
Presenter::createRequest
is. $refUrl
is filled by
presenter. You can look at it as a hidden factory and dependency. Hidden factory
would be the $refUrl
setup. Hidden dependency is the HttpRequest used for creating
$refUrl
and relative urls.
By extracting it into interface first step of refactoring is done.
IRefUrlFactory
with implementation for HttpRequest
and
for plain URL (non-browser, could be used as fallback).
But you will still have one HttpRequest
dependency. That would be solved by ILinkSetup
.
So ILinkSetup
will have to provide at least BaseUrl (string) and
RefUrl (Url object).
Last edited by mishak (2014-06-16 03:45)