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::createRequesttoRequestFactory - Extracting
LinkGeneratorfromPresenter::link - Refactoring
PresenterComponent::linkto useLinkGenerator. - Refactoring
{link}macro - There should be enough code for own package
nette/application-linkwith {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 | 8285
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)