CoolCMS API

NewsletterAddressPresenter extends BasePresenter
in package

Table of Contents

Constants

defaultLinkParameters  : mixed = ['slug' => NULL]
SESSION_NAMESPACE  : mixed = 'script'
FALLBACK_LAYOUT  : mixed = '@layout_one.latte'
Layout used when the theme lacks the requested one.
LOCALE_MAP  : mixed = ['cs' => 'cs_CZ', 'en' => 'en_US', 'sk' => 'sk_...
Maps the short language code to the full locale of the registered NEON sources.

Properties

$accessTokenValidator  : AccessTokenValidator
Validates access tokens beyond signature and expiry.
$accountDeletionSessionManager  : AccountDeletionSessionManager
Account deletion — cancel ticket of a sign-in refused while the account awaits deletion.
$authManager  : AuthManager
$authStorageManager  : AuthStorageManager
$container  : Container
$currencyContext  : CurrencyContext
$currencyManager  : CurrencyManager
$deviceDetector  : DeviceDetector
$displayPaymentRegionManager  : PaymentRegionManager
IMPORTANT: a custom name, not `$paymentRegionManager`. Several presenters (Discussion/Bazaar Payment) have the region manager in the constructor, and a same-named property would break the container ("Cannot redeclare").
$eventDispatcher  : EventDispatcher
$jwtManager  : JwtManager
$languageContext  : LanguageContext
$languageManager  : LanguageManager
$localizationContext  : LocalizationContext
$localizationManager  : LocalizationManager
$loginDeviceCookie  : LoginDeviceCookie
"Known device" cookie for the password login throttle ({@see self::rememberLoginDevice()}).
$pageManager  : PageManager
$presenterContext  : PresenterContext
$settingContext  : SettingContext
$settingManager  : SettingManager
$slug  : string|int|null
$themeContext  : ThemeContext
$themeManager  : ThemeManager
$themeResolver  : DefaultThemeResolver
$translator  : ITranslator
$translatorSessionResolver  : Session
$userManager  : UserManager
$debugMode  : bool
$newsletterAddressManager  : NewsletterAddressManager
$pageEntity  : Page|null
$productionMode  : bool
$translatorDomain  : string
$isLoggingIn  : bool
$theme  : Theme|null

Methods

__construct()  : mixed
actionActivate()  : void
actionUnsubscribe()  : void
Unsubscribes the address from the link in a newsletter e-mail: the address row is deleted. The link carries the e-mail and the address key; a wrong pair (a test e-mail, an old link) only shows the error message.
beforeRender()  : void
completeExternalLogin()  : bool
Completes an OAuth login (`LoginExternalComponent`) with the same storage as a password login.
createComponent()  : IComponent|null
formatLayoutTemplateFiles()  : array<string|int, mixed>
Returns candidate layout files; Nette takes the first existing one.
getContainer()  : Container
getPageEntity()  : Page|null
getTranslator()  : ITranslator
handleChangeLocale()  : void
handleLogout()  : void
handleSignOut()  : void
Sign-out from an ordinary link (account menu), also without JavaScript.
hasServiceByType()  : bool
Returns whether the container has a service of the given type.
initializeTranslator()  : void
loginWithCredentials()  : void
Logs in by username and password; called only by the login form (after validation and CSRF).
redirectToPendingAccountDeletion()  : void
Account deletion: a sign-in (password or OAuth) was refused because the account awaits deletion: keep the cancel ticket in the session and go to the "Account deletion" page, which offers "Cancel the deletion". Without a ticket (should not happen) the visitor gets the plain refusal flash instead.
renderActivate()  : void
renderUnsubscribe()  : void
setConfigParameters()  : void
setTranslator()  : $this
startup()  : void
typedComponent()  : T
Returns a subcomponent with a verified type.
checkAuthentication()  : void
fallbackToMainLocalization()  : bool
Whether the presenter may fall back to the main localization for an unknown locale; a regular page may not (404).
getSessionKey()  : string
Returns a session key string, e.g. 'front.auth.step1'.
getSessionSection()  : SessionSection
Returns a Nette\SessionSection instance using a dynamically built session key.
initializePresenterContext()  : void
isSameSiteRequest()  : bool
Tells whether the request comes from the own site (Nette SameSite cookie); protects GET actions with a side effect.
loadPageEntity()  : Page|null
Returns the page of the request by `slug` (empty is the home page, a number is the ID, otherwise `href`).
logout()  : void
setTranslatorDomain()  : void
createIdentity()  : SimpleIdentity|null
createMultiplierComponent()  : Multiplier<string|int, IComponent>
Creates a multiplier for the component.
createNewComponentInstance()  : IComponent|null
Creates a new component instance without adding it to the presenter; used by the multiplier.
createStandardComponent()  : IComponent|null
Creates a standard component (not a multiplier).
expireIdleLogin()  : bool
Checks whether the login expired from inactivity.
flashConfirmation()  : void
IMPORTANT: the flash gets the finished translation, not a key and not a {@see \App\Core\Utils\Controls\FlashMessage} object.
formatLayoutCandidates()  : array<int, string>
getClientIp()  : string
initializeDisplayRegion()  : void
Initializes the currency and VAT display of prices.
initializeExternalFiles()  : void
initializeMetaTags()  : void
initializePage()  : void
isDevelopment()  : bool
layoutFileExists()  : bool
loadLocalization()  : Localization|null
Returns the localization by `loc` from the URL, or `null` when there is no such locale.
localizationCurrencyKey()  : string|null
Front needs no currency key from the localization; the currency and the display region are filled by {@see CurrencyInitTrait::initializeDisplayRegion()}.
logoutNetteUser()  : void
processFailedLogin()  : void
processInvalidToken()  : void
processLogin()  : void
processLoginException()  : void
processMissingToken()  : void
processSuccessfulLogin()  : void
processValidToken()  : void
readLoginDeviceToken()  : string|null
Returns the raw known-device cookie for the Api login (the Api verifies its signature).
redirectAfterLoginAction()  : void
Ends a sign-in attempt. A classic (non-AJAX) successful sign-in lands on "My account" ({@see PageId::SYSTEM_USER_ACCOUNT}); a failed one on the home page. An AJAX sign-in stays on the current page and only redraws the flash messages.
redirectToHomepage()  : never
IMPORTANT: `slug` must be `null`, not `1`. The homepage route has the slug in its mask with a default, so a concrete value stops it matching and `redirect()` ends with `InvalidLinkException: No route for Front:System:Page:homepage(slug=1)` and HTTP 500, at a point where the address is already activated in the DB.
refreshNetteIdentity()  : bool
Refreshes the token for the same logged-in user.
rememberLoginDevice()  : void
Issues or renews the "known device" cookie after a successful login (password or OAuth).
resolveLoginErrorMessage()  : string
Resolves the translated login error text.
revokeTokensOnLogout()  : void
Calls the Api logout (revokes the refresh family and deny-lists the access `jti`) for the tokens of the current session.
sendUnsubscribeConfirmation()  : never
Plain confirmation page with a button that posts the same link (scripts have no theme templates).
setNetteUser()  : void
tryRefresh()  : bool
Tries an automatic refresh when the access token has expired.

Constants

SESSION_NAMESPACE

protected mixed SESSION_NAMESPACE = 'script'

FALLBACK_LAYOUT

Layout used when the theme lacks the requested one.

private mixed FALLBACK_LAYOUT = '@layout_one.latte'

@layout_one.latte (one column, shared header and footer) exists in every theme and is the plainest page the system can render, so anything fits in it.

IMPORTANT: not @layout.latte; that is a bare Nette skeleton titled "Nette Web" without header, footer or styles, hardly better than a missing layout.

LOCALE_MAP

Maps the short language code to the full locale of the registered NEON sources.

private mixed LOCALE_MAP = ['cs' => 'cs_CZ', 'en' => 'en_US', 'sk' => 'sk_SK']

The short code (cs, en, sk) comes from LanguageContext, derived from the URL parameter loc/lang; the full locales are cs_CZ, en_US, sk_SK. translator.neon configures one shared fallback chain [cs_CZ, cs, en_US, en, sk_SK, sk] for all languages, so a short code would always map to cs_CZ first, whatever language is active. A direct match on the full locale bypasses that.

The Contributte LocaleResolvers\Router (the only configured resolver) looks for the route parameter locale, but this application routes under loc, so it always returns null and the translator falls back to default: cs. An explicit setLocale() from here bypasses the resolver, which Translator::getLocale() asks only while no locale has been set explicitly.

Properties

$accessTokenValidator

Validates access tokens beyond signature and expiry.

public AccessTokenValidator $accessTokenValidator

A revoked token (jti on the deny-list) that has not expired yet would otherwise keep the session logged in although the Api guard rejects the same token. Same contract as JwtAuthTrait::checkJwtAuth(), one implementation.

Attributes
#[Inject]

$displayPaymentRegionManager

IMPORTANT: a custom name, not `$paymentRegionManager`. Several presenters (Discussion/Bazaar Payment) have the region manager in the constructor, and a same-named property would break the container ("Cannot redeclare").

public PaymentRegionManager $displayPaymentRegionManager
Attributes
#[Inject]

$loginDeviceCookie

"Known device" cookie for the password login throttle ({@see self::rememberLoginDevice()}).

public LoginDeviceCookie $loginDeviceCookie
Attributes
#[Inject]

$slug

public string|int|null $slug = NULL
Attributes
#[Persistent]

Methods

actionUnsubscribe()

Unsubscribes the address from the link in a newsletter e-mail: the address row is deleted. The link carries the e-mail and the address key; a wrong pair (a test e-mail, an old link) only shows the error message.

public actionUnsubscribe() : void

IMPORTANT: the link (GET) only shows a confirmation with a button, the delete is the POST of that button. Mail security scanners open the links of incoming e-mails, a GET that deletes would unsubscribe every recipient.

completeExternalLogin()

Completes an OAuth login (`LoginExternalComponent`) with the same storage as a password login.

public completeExternalLogin(array<string, mixed> $resultData) : bool

IMPORTANT: the whole session section is cleared first and the refresh token from the Api must be stored. Otherwise the user drops out after 15 minutes, and the refresh token of the previous account stays in the section, so tryRefresh() would log account A back in after expiry (shared computer).

Parameters
$resultData : array<string, mixed>

data from the Api loginExternal (token, refreshToken, payload)

Return values
bool

createComponent()

public createComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

formatLayoutTemplateFiles()

Returns candidate layout files; Nette takes the first existing one.

public formatLayoutTemplateFiles() : array<string|int, mixed>

IMPORTANT: when the theme lacks the layout, a fallback is added. The layout name is stored in cms_system_pages.layout, one column shared by all themes, so a page set to @text_layout_two.latte wants that file even in a theme that never got it. Without a fallback Nette finds nothing and renders the presenter without a layout: the page has no header, footer or styles but returns HTTP 200.

The fallback is logged, because a silent fallback would hide the problem entirely; when the page asks for the fallback layout itself and the theme lacks it, there is nowhere to fall back to, so it is logged as an error and the page renders without a layout.

Return values
array<string|int, mixed>

getContainer()

public getContainer() : Container
Return values
Container

handleChangeLocale()

public handleChangeLocale(string $locale) : void
Parameters
$locale : string

handleSignOut()

Sign-out from an ordinary link (account menu), also without JavaScript.

public handleSignOut() : void

Nette refuses every signal whose request is not same-origin (Sec-Fetch-Site) and redirects to the same URL without do, so a typed or bookmarked ?do=signOut (Sec-Fetch-Site: none) never ran. A user-initiated navigation cannot be forged by another site, so it is allowed here as well; a cross-site request still ends in detectedCsrf().

Attributes
#[Requires]
$sameOrigin: false

hasServiceByType()

Returns whether the container has a service of the given type.

public hasServiceByType(string $className) : bool

The name is composed dynamically (module plus component), so class_exists() runs first, and a true result guarantees a valid type.

Parameters
$className : string
Tags
phpstan-assert-if-true

class-string $className

Return values
bool

initializeTranslator()

public initializeTranslator(string|null $alias) : void
Parameters
$alias : string|null

loginWithCredentials()

Logs in by username and password; called only by the login form (after validation and CSRF).

public loginWithCredentials(string $username, string $password[, bool $remember = false ]) : void

IMPORTANT: this must not be a handle* method. Nette finds signals by that prefix, so a public handleLogin() would be a signal on every presenter (?do=login&username=…&password=…): the password could end up in the URL and the server log, and the form token would be bypassed.

Parameters
$username : string
$password : string
$remember : bool = false

redirectToPendingAccountDeletion()

Account deletion: a sign-in (password or OAuth) was refused because the account awaits deletion: keep the cancel ticket in the session and go to the "Account deletion" page, which offers "Cancel the deletion". Without a ticket (should not happen) the visitor gets the plain refusal flash instead.

public redirectToPendingAccountDeletion(mixed $resultData) : void
Parameters
$resultData : mixed

setConfigParameters()

public setConfigParameters([bool $debugMode = false ][, bool $productionMode = false ]) : void
Parameters
$debugMode : bool = false
$productionMode : bool = false

setTranslator()

public setTranslator(ITranslator $translator) : $this
Parameters
$translator : ITranslator
Return values
$this

typedComponent()

Returns a subcomponent with a verified type.

public typedComponent(string $name, T> $type) : T

Use it instead of an inline @var above $this['x'] (which does not narrow the type) and instead of the generic IComponent that $this['x'] returns. See Form::typedComponent().

Parameters
$name : string
$type : T>
Tags
template
Return values
T

fallbackToMainLocalization()

Whether the presenter may fall back to the main localization for an unknown locale; a regular page may not (404).

protected fallbackToMainLocalization() : bool
Return values
bool

getSessionKey()

Returns a session key string, e.g. 'front.auth.step1'.

protected getSessionKey([string|null $namespace = null ][, string|null $subsection = null ], string ...$extra) : string
Parameters
$namespace : string|null = null

Base namespace (module prefix). Uses SESSION_NAMESPACE if null.

$subsection : string|null = null

Subsection under the namespace. Uses SESSION_SUBSECTION constant if null.

$extra : string

Additional parts to append (e.g. 'step1', 'wizard', etc.).

Return values
string

getSessionSection()

Returns a Nette\SessionSection instance using a dynamically built session key.

protected getSessionSection([string|null $namespace = null ][, string|null $subsection = null ], string ...$extra) : SessionSection
Parameters
$namespace : string|null = null
$subsection : string|null = null
$extra : string
Tags
see
getSessionKey()
Return values
SessionSection

isSameSiteRequest()

Tells whether the request comes from the own site (Nette SameSite cookie); protects GET actions with a side effect.

protected isSameSiteRequest() : bool

getHttpRequest() returns the IRequest interface, while isSameSite() exists only on Nette\Http\Request.

Return values
bool

loadPageEntity()

Returns the page of the request by `slug` (empty is the home page, a number is the ID, otherwise `href`).

protected loadPageEntity() : Page|null

Returns null when the page does not exist; the 404 is decided by BasePresenter::startup(). The error page (ErrorPresenter) overrides the method because it has no page in the DB and the layout needs an entity.

Return values
Page|null

createIdentity()

private createIdentity(array<string, mixed> $payload, string $token) : SimpleIdentity|null
Parameters
$payload : array<string, mixed>
$token : string
Return values
SimpleIdentity|null

createMultiplierComponent()

Creates a multiplier for the component.

private createMultiplierComponent(string $name) : Multiplier<string|int, IComponent>
Parameters
$name : string
Return values
Multiplier<string|int, IComponent>

createNewComponentInstance()

Creates a new component instance without adding it to the presenter; used by the multiplier.

private createNewComponentInstance(string $baseName[, int|string|null $uniqueKey = null ]) : IComponent|null
Parameters
$baseName : string
$uniqueKey : int|string|null = null
Return values
IComponent|null

createStandardComponent()

Creates a standard component (not a multiplier).

private createStandardComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

expireIdleLogin()

Checks whether the login expired from inactivity.

private expireIdleLogin(AuthSessionStorage $authStorage) : bool

If so, it revokes the tokens (like a logout), clears the auth section, logs out the Nette identity and returns true; otherwise it moves the activity stamp. The limit is 30 minutes without "remember me", 31 days with it (AuthSessionStorage::isIdleExpired()).

Parameters
$authStorage : AuthSessionStorage
Return values
bool

flashConfirmation()

IMPORTANT: the flash gets the finished translation, not a key and not a {@see \App\Core\Utils\Controls\FlashMessage} object.

private flashConfirmation(string $branch, string $type) : void

The redirect target is a front presenter that prints the message through {_$flash->message} (parts/shared/main/flash-messages.latte), and Contributte\Translation\Translator::translate() accepts only string, so a FlashMessage (even though Stringable) ended up as an empty message. Double translation is harmless: returnOriginalMessage: true returns the already translated text unchanged. RegistrationPresenter does the same for registration activation, the very same "e-mail link" flow.

Parameters
$branch : string
$type : string

formatLayoutCandidates()

private formatLayoutCandidates(Theme $theme, string $layout) : array<int, string>
Parameters
$theme : Theme
$layout : string
Return values
array<int, string>

initializeDisplayRegion()

Initializes the currency and VAT display of prices.

private initializeDisplayRegion() : void

IMPORTANT: the display region is the payment region of the localization. The currency column of the localization is not read and ?curr= from the URL is ignored on the front end; the only source is DisplayRegionResolver. The cart and checkout may switch the region by the customer's choice (CheckoutRegionTrait), the catalog always shows the localization region.

Call it after initializeCurrencyList() (the resolver needs the currencies).

initializeExternalFiles()

private initializeExternalFiles(Page|null $pageEntity) : void
Parameters
$pageEntity : Page|null

initializeMetaTags()

private initializeMetaTags(Page|null $pageEntity) : void
Parameters
$pageEntity : Page|null

layoutFileExists()

private layoutFileExists(array<int, string> $files) : bool
Parameters
$files : array<int, string>
Return values
bool

loadLocalization()

Returns the localization by `loc` from the URL, or `null` when there is no such locale.

private loadLocalization() : Localization|null

IMPORTANT: an unknown locale must return null (a non-null return type would turn a forged prefix such as /xx/ into a TypeError, HTTP 500). BasePresenter::startup() turns null into a 404; the error page takes the main website localization via fallbackToMainLocalization().

Return values
Localization|null

localizationCurrencyKey()

Front needs no currency key from the localization; the currency and the display region are filled by {@see CurrencyInitTrait::initializeDisplayRegion()}.

private localizationCurrencyKey(object $localization) : string|null
Parameters
$localization : object
Return values
string|null

processLogin()

private processLogin(string $username, string $password[, bool $remember = false ]) : void
Parameters
$username : string
$password : string
$remember : bool = false

processLoginException()

private processLoginException(Exception $e) : void
Parameters
$e : Exception

readLoginDeviceToken()

Returns the raw known-device cookie for the Api login (the Api verifies its signature).

private readLoginDeviceToken() : string|null
Return values
string|null

redirectAfterLoginAction()

Ends a sign-in attempt. A classic (non-AJAX) successful sign-in lands on "My account" ({@see PageId::SYSTEM_USER_ACCOUNT}); a failed one on the home page. An AJAX sign-in stays on the current page and only redraws the flash messages.

private redirectAfterLoginAction([bool $succeeded = false ]) : void
Parameters
$succeeded : bool = false

redirectToHomepage()

IMPORTANT: `slug` must be `null`, not `1`. The homepage route has the slug in its mask with a default, so a concrete value stops it matching and `redirect()` ends with `InvalidLinkException: No route for Front:System:Page:homepage(slug=1)` and HTTP 500, at a point where the address is already activated in the DB.

private redirectToHomepage() : never

BaseBreadcrumb uses the same shape.

Return values
never

refreshNetteIdentity()

Refreshes the token for the same logged-in user.

private refreshNetteIdentity(array<string, mixed> $payload, string $token) : bool

The identity data (token, name, email) are overwritten in the stored object without login(), so neither the session ID nor the form CSRF tokens change. The identity lives in the session section as an object and the change is written at the end of the request.

Parameters
$payload : array<string, mixed>
$token : string
Return values
bool —

false when not possible (nobody logged in or another user), the caller then uses login

rememberLoginDevice()

Issues or renews the "known device" cookie after a successful login (password or OAuth).

private rememberLoginDevice(mixed $payload) : void

The cookie (LoginDeviceCookie) is a signed proof that this browser has already logged in to the account. The next login sends it to the Api (self::processLogin()), so above the account limit the password from this browser is still verified and foreign attempts do not lock the owner out. HttpOnly, SameSite=Lax, Secure on HTTPS; lifetime ratelimit.loginDevice.cookieLifetime.

Parameters
$payload : mixed

resolveLoginErrorMessage()

Resolves the translated login error text.

private resolveLoginErrorMessage(Result $result) : string

IMPORTANT: a throttle by the brute-force gate must not be shown as "wrong password"; the limit would then look like an inexplicably failing form. The generic results.rateLimitExceeded carries no seconds and does not belong to login, so the login flow has its own key login.rateLimit.message (same family as front.general.login.error.message), with the seconds passed as %count% (Contributte: numeric second argument).

The Api sends retryAfter in data (AuthPresenter::rateLimitedResult()); the internal bridge call does not see the Retry-After header.

Parameters
$result : Result
Return values
string

revokeTokensOnLogout()

Calls the Api logout (revokes the refresh family and deny-lists the access `jti`) for the tokens of the current session.

private revokeTokensOnLogout(AuthSessionStorage $authStorage, mixed $userId) : void

Deliberately fail-open: any failure is only logged, because the local logout must not stay unfinished.

Parameters
$authStorage : AuthSessionStorage
$userId : mixed

sendUnsubscribeConfirmation()

Plain confirmation page with a button that posts the same link (scripts have no theme templates).

private sendUnsubscribeConfirmation(string $email) : never
Parameters
$email : string
Return values
never

setNetteUser()

private setNetteUser(array<string, mixed>|null $payload, string $token) : void
Parameters
$payload : array<string, mixed>|null
$token : string

tryRefresh()

Tries an automatic refresh when the access token has expired.

private tryRefresh(AuthSessionStorage $authStorage) : bool

If the session holds a refresh token and the Api accepts it, the new pair is stored in the session and true is returned; otherwise false, and the caller drops the session.

Parameters
$authStorage : AuthSessionStorage
Return values
bool
On this page

Search results