build(deps): bump symfony/cache to ^8.0#2
Merged
Conversation
Widen the constraint to allow symfony/cache 8.x (locked at v8.1.0) while keeping doctrine/orm on 2.x. The Dependabot php-deps group bundled this bump with doctrine/orm ^3.6, which removes ORM2-only APIs the codebase still relies on (EntityManager::create, set*CacheImpl, Common\ClassLoader); that part is deferred to a dedicated migration. symfony/cache only backs Doctrine's PSR-6 metadata/query/result caches via DoctrineProvider::wrap() in OSS_Resource_Doctrine2cache. The ApcuAdapter, RedisAdapter and ArrayAdapter classes are unchanged across 6/7/8, so no code change is required. php >=8.4.1 is already required, satisfying the symfony 8 PHP floor. Verified: composer validate --strict, php -l, composer audit, and class resolution of all four cache classes under v8.1.0.
ORM 3.x removes APIs the codebase relies on; the grouped major bump would fatal at boot. Ignore semver-major for doctrine/orm so Dependabot stops re-proposing ORM3; minor/patch still flow.
This was referenced Jun 5, 2026
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
First foundational slice toward dropping the ZF1 bootstrap (WALL #2, docs/ZF1-REMOVAL.md). The native Container has until now reused the merged options array the ZF1 bootstrap built; to stand the kernel up without Zend_Application it must read application.ini itself. src/Kernel/Config/IniConfig.php reproduces exactly the three transforms the ZF1 INI config applied and nothing else: - section inheritance ([child : parent], single parent, transitive) - dotted-key nesting (a.b.c = v -> ['a']['b']['c']) - constant concatenation (APPLICATION_PATH "/x") delegated to PHP's NORMAL INI scanner, which also gives ZF1's boolean coercion (true->'1', false->'') Output is value-for-value identical to getOptions(), so the Container and every native controller read it unchanged. INERT: nothing wires it yet (mirrors how each prior wall started with an inert core). tests/test-kernel-config.php (18 asserts: nesting, inheritance, transitive chain, constant expansion, bool coercion, error cases, + a smoke test against the shipped application.ini.dist) wired into the regression unit job. Guard green (src/ stays zero-Zend_).
This was referenced Jun 6, 2026
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
* WALL #2 slice 2: native Doctrine EM factory (inert) Second foundational slice toward dropping the ZF1 bootstrap (WALL #2, docs/ZF1-REMOVAL.md). The native Container has until now reused the EM the ZF1 `doctrine2` resource built; to stand the kernel up without Zend_Application it must build the same EM itself, from the same options array (now produced framework-free by IniConfig, slice 1 #74). src/Kernel/Doctrine/EntityManagerFactory.php is a verbatim framework-free port of OSS_Resource_Doctrine2 + OSS_Resource_Doctrine2cache, minus the registry/logger side effects that only made sense inside the framework: - create(): Configuration + XML metadata driver over xml_schema_path + proxy dir/namespace/autogen + ORM 2.x EntityManager::create() over the connection options. Connection-lazy (no DB touched until first query). - buildCache(): PSR-6 pool (Apcu/Redis/per-request Array) wrapped by DoctrineProvider, degrading to Array when an extension/server is absent. - registerEntityAutoloaders(): PSR-0 loaders for Entities/Repositories (not in Composer's map; the resource pushed Doctrine ClassLoaders onto the ZF1 autoloader). Proxies stay with Doctrine's own ProxyFactory. INERT: nothing wires it yet; the native bootstrap (a later slice) will, where it gets full runtime validation against the dev MariaDB. tests/test-kernel-em-factory.php builds a lazy EM from a synthetic config against the real XML mapping dir and asserts the wiring (EM type, XML driver, proxy settings, cache, a real Admin metadata load, autoloader). Added to the cache-wiring CI job (which has vendor + doctrine/orm); added the simplexml extension that job needs for the XML driver. The driver-dependent asserts skip gracefully where simplexml is absent (apcu-skip idiom). Guard green. * fixup: register entity autoloaders before metadata-load assert
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Third foundational slice toward dropping the ZF1 bootstrap (WALL #2, docs/ZF1-REMOVAL.md). Throughout the migration the native side reached per-session UI state through the legacy ZF1 namespace object the bootstrap built (Container::session(), templates reading $session->domain, the Auth identity bridge wrapping the auth namespace in MagicPropertyStorage), all via magic-property access over a slice of $_SESSION. src/Kernel/Session/SessionNamespace.php provides that shape natively: a magic-property view of $_SESSION[$namespace] (__get/__set/__isset/__unset), so $ns->domain reads/writes $_SESSION['Application']['domain']. It drops straight into both call sites once the ZF1 bootstrap is gone: - Container::session() -> new SessionNamespace('Application') (templates + FlashMessages keep the same $_SESSION['Application'][...] keys); - Auth bridge -> new MagicPropertyStorage(new SessionNamespace($authNs)). Because it exposes data through magic properties it satisfies MagicPropertyStorage's object contract with no adapter, so the security/auth services stay unchanged. INERT (no call site rewired yet). tests/test-kernel-session-namespace.php (14 asserts: read/write/isset/unset, namespace isolation, the MagicPropertyStorage wrap that the Auth bridge will use, default namespace) wired into the regression unit job. Guard green.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Fourth foundational slice toward dropping the ZF1 bootstrap (WALL #2, docs/ZF1-REMOVAL.md). The native controllers render through Container::getResource('smarty'), which until now returned the ZF1 OSS_View_Smarty — a Smarty-5 wrapper that only extends the ZF1 view base for the framework's view-renderer integration (which native rendering never uses). src/Kernel/View/SmartyView.php reproduces exactly the part the kernel relies on, WITHOUT the framework base, so the native bootstrap can build a view with no ZF1 application present. Faithful subset of OSS_View_Smarty: - same \Smarty\Smarty engine with setEscapeHtml(true); - same bare-function modifiers (strlen/count/in_array/is_array) so the existing templates compile under Smarty 5; - template/compile/cache/config dirs + the OSS plugin dir from options; - __set($k,$v) -> assign (the shape AbstractController::view() uses); - render($name) -> fetch(resolveTemplate($name)) with the same skin lookup (a _skins/<skin>/ copy wins over the default). - fromOptions() reads resources.smarty.* like the ZF1 smarty resource. INERT: nothing wires it yet; the native bootstrap slice will, where the full chrome/OSS-plugin render is image-validated. tests/test-kernel-smarty-view.php (8 asserts: magic-set+render, auto-escape, compile-dir creation, skin override/fallback, unknown-skin throw, fromOptions) renders real templates through the real Smarty engine; added to the cache-wiring CI job (vendor present). Guard green.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Fourth foundational slice toward dropping the ZF1 bootstrap (WALL #2, docs/ZF1-REMOVAL.md). The native controllers render through Container::getResource('smarty'), which until now returned the ZF1 OSS_View_Smarty — a Smarty-5 wrapper that only extends the ZF1 view base for the framework's view-renderer integration (which native rendering never uses). src/Kernel/View/SmartyView.php reproduces exactly the part the kernel relies on, WITHOUT the framework base, so the native bootstrap can build a view with no ZF1 application present. Faithful subset of OSS_View_Smarty: - same \Smarty\Smarty engine with setEscapeHtml(true); - same bare-function modifiers (strlen/count/in_array/is_array) so the existing templates compile under Smarty 5; - template/compile/cache/config dirs + the OSS plugin dir from options; - __set($k,$v) -> assign (the shape AbstractController::view() uses); - render($name) -> fetch(resolveTemplate($name)) with the same skin lookup (a _skins/<skin>/ copy wins over the default). - fromOptions() reads resources.smarty.* like the ZF1 smarty resource. INERT: nothing wires it yet; the native bootstrap slice will, where the full chrome/OSS-plugin render is image-validated. tests/test-kernel-smarty-view.php (8 asserts: magic-set+render, auto-escape, compile-dir creation, skin override/fallback, unknown-skin throw, fromOptions) renders real templates through the real Smarty engine; added to the cache-wiring CI job (vendor present). Guard green.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
… UI) (#78) The keystone of WALL #2 (docs/ZF1-REMOVAL.md): the kernel can now run with the ZF1 application ABSENT. The four inert builders (#74 config, #75 EM, #76 session, #77 view) are assembled into a ready Container WITHOUT Zend_Application. - src/Kernel/Bootstrap.php — framework-free boot(appPath, env, authNs): load options via IniConfig, register entity autoloaders, configure + start the PHP session, build the EM, Smarty view, session namespace and Auth identity bridge, return a Container. Pure baseUrl()/skinCss() from $_SERVER. - src/Kernel/NativeResources.php — presents the EM/view/session through the same getResource()/getOptions() shape the Container expected from the ZF1 bootstrap, so Container/Dispatcher/controllers are reused unchanged. - public/index.php — new VIMBADMIN_NATIVE_BOOTSTRAP=1 path (default off) that boots natively and serves the UI with NO Zend_Application; the non-UI tail falls through to the ZF1 path. A thin Zend autoloader + the residual Zend_Registry/front-controller-base-URL shims the OSS template helpers still read (genUrl) live here, in the ZF1-aware entry point, so Bootstrap stays pure. Two gotchas found + fixed via the image harness: - configureSession(): must apply resources.session.* (save_path=var/session, name=VIMBADMIN3, cookie flags) before session_start(). PHP's default /var/lib/php/sessions is not readable by the FPM user on the locked-down container, so a default session_start silently lost the identity between requests. - registerEntityAutoloaders() must run BEFORE session_start(): the identity array in the session holds an Entities\Admin object; session_start unserialises it immediately, so the class must be loadable or it rehydrates as __PHP_Incomplete_Class and admin/list's $identity.user->getId() fatals. IMAGE-VALIDATED (vimbadmin:dev, VIMBADMIN_NATIVE_BOOTSTRAP=1): login 302 + session persists; domain/admin/mailbox/alias/log/queue/archive/maintenance lists + index/ about all 200 with the Logout chrome; csrf-masked diff vs the native-kernel baseline IDENTICAL on all 8 lists (only wall-clock timestamps differ). EM read+write + flash (login-error alert) exercised. Zero fatals. tests/test-kernel-bootstrap.php (9 asserts: baseUrl derivation, NativeResources shape) in the regression unit job; full boot is image-validated. Guard green.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Flip the entry point so the native bootstrap (no Zend_Application) is the
default path; set VIMBADMIN_NATIVE_BOOTSTRAP=0 to force the legacy ZF1 path.
The whole interactive admin UI now runs framework-free in production.
Two things were required to make the flip safe — once the native bootstrap owns
the PHP session, any route that punts to ZF1 mid-request would make
Zend_Session::start() fatal on the already-defined SID constant:
1. Route BEFORE booting. New Kernel::canHandle(path) decides servability with no
resource at all — router match + built-in handler keys + method_exists on the
mapped controller class. The entry point boots the native stack only for a
path it can fully serve; the non-UI tail (mailer emailSettings /
lost-password/reset, cli-*, queue trigger) reaches ZF1 with NOTHING started.
2. Native controllers must not punt a route they own by returning null at
runtime. Converted the remaining conditional null-returns to native handling:
- domain/mailbox/alias addAction with an id in the URL now redirect to the
native editAction instead of falling back to ZF1;
- domain editAction on an invalid did flashes + redirects (was a ZF1 punt);
- auth setup with the salt unset renders a native first-run salt screen
(new application/views/auth/native-setup-salt.phtml) instead of punting.
IMAGE-VALIDATED (vimbadmin:dev, NO flag = new default): anon about + login + all
list pages + add/edit forms 200 native with the Logout chrome; the ZF1 tail
(/auth/lost-password, /mailbox/email-settings) falls through to ZF1 cleanly (200,
no SID fatal); the de-punted edge cases (/domain/edit/did/<bad> -> 302 flash,
/domain/add/did/N -> 302 to native edit) are native; zero fatals.
tests/test-kernel-http.php gains canHandle asserts (built-in + router-miss; the
method_exists branch is image-validated). Guard green.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Honouring resources.auth.oss.lost_password.use_captcha on the native
lost-password page surfaced two native-bootstrap gaps in the reused ZF1 captcha
(OSS_Captcha_Image extends Zend_Captcha_Image). Both fixed in the ZF1-zone entry
point / the unscanned OSS lib; slice 6c de-Zends the captcha and removes these.
- OSS_Utils::getIniOption(): null-guard the ZF1 front-controller bootstrap param
(null under the native bootstrap) and fall back to the merged options the
native entry publishes in Zend_Registry. Without it OSS_Captcha_Image's ctor
fatals (getTempDir -> getIniOption -> getApplication() on null).
- public/index.php (native zone): bridge Zend_Session to the already-open native
PHP session — set _sessionStarted/_readable/_writable so a ZF1
Zend_Session_Namespace (the captcha word store) attaches to the live session
instead of fataling in Zend_Session::start()/Namespace ("already started" /
"not marked as readable").
Image-validated (vimbadmin:dev + a mailpit SMTP sink): captcha-on GET renders the
image (auth/captcha-image 200 image/png), the RIGHT word sends the reset mail,
the WRONG word shows the inline "does not match that of the image" error and
sends nothing; captcha-off lost-password + the full reset round-trip also send +
verify (new password logs in, the spent token is rejected).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Foundation for porting the mailer-dependent tail (auth lost-password / reset-password, mailbox email-settings) off the ZF1 Zend_Mail path. Inert: nothing calls it yet, mirroring how each WALL #2 resource builder landed. - composer: require symfony/mailer ^8.0 (matches the locked symfony 8.1 band; pulls symfony/mime + event-dispatcher + egulias/email-validator). - src/Kernel/Mail/Mailer.php: framework-free sender. Turns the resources.mail.transport.* ini block (type smtp|sendmail, host, port, ssl tls|ssl|none, username/password, verify_peer[_name]) into a configured symfony transport and sends a Mime\Email. Transport-building decision is a pure, testable resolveConfig(); buildTransport() makes the real transport. ssl=ssl -> implicit TLS (465); ssl=tls/starttls -> opportunistic STARTTLS (587); omitted -> plaintext. verify_peer/_name routed through FILTER_VALIDATE_BOOLEAN so the ini "0" string disables verification. - Container::mailer(): lazily builds the Mailer from options[resources][mail][transport]. No Bootstrap change (reads options()). - tests/test-kernel-mailer.php (26 asserts) + regression.yml step. src/ stays free of the legacy framework prefix (guard green).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Ports OSS_Controller_Trait_Auth::lostPasswordAction/resetPasswordAction onto
the native kernel, sending through the slice-6b-1 Mailer instead of Zend_Mail.
The last two browser auth routes leave ZF1.
- AbstractController: mailer() (native getMailer) + renderEmail() (body-only
Smarty render, no page chrome) for the auth/email/* templates.
- AuthController::lostPasswordAction: anti-enumeration (identical response
whether or not the username exists); 40-char token stored as an expiring
(2h, max 5) tokens.password_reset indexed preference; reset link mailed via
the html email template. Captcha honoured when
resources.auth.oss.lost_password.use_captcha is on — fresh OSS_Captcha_Image
per render, typed text validated (as a field rule) against the SUBMITTED
captcha id; image-click requests a new one (requestnewimage) and
short-circuits before validation. The captcha PNG route (auth/captcha-image)
stays ZF1 via the dispatcher fallback (de-Zended in 6c).
- AuthController::resetPasswordAction: GET (from the emailed link) prefills
username + token from the path; valid POST checks the token against the live
reset-token preferences, sets the new hash, clears all tokens, zeroes any
failed-login counter, mails a confirmation, redirects to login. All failure
paths share one generic message.
- sendAuthEmail() honours resources.auth.oss.email_format (html|plaintext|both)
and sets From/To from identity.mailer.* + the admin email/formatted-name,
mirroring resolveTemplate() + the legacy actions.
- New native views auth/native-{lost,reset}-password.phtml (FormRenderer +
captcha image/refresh; no Zend_Form JS validator).
No NATIVE_CONTROLLERS / Kernel change (auth already native; the dispatcher
invokes the new action methods). src/ stays free of the legacy prefix.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Honouring resources.auth.oss.lost_password.use_captcha on the native
lost-password page surfaced two native-bootstrap gaps in the reused ZF1 captcha
(OSS_Captcha_Image extends Zend_Captcha_Image). Both fixed in the ZF1-zone entry
point / the unscanned OSS lib; slice 6c de-Zends the captcha and removes these.
- OSS_Utils::getIniOption(): null-guard the ZF1 front-controller bootstrap param
(null under the native bootstrap) and fall back to the merged options the
native entry publishes in Zend_Registry. Without it OSS_Captcha_Image's ctor
fatals (getTempDir -> getIniOption -> getApplication() on null).
- public/index.php (native zone): bridge Zend_Session to the already-open native
PHP session — set _sessionStarted/_readable/_writable so a ZF1
Zend_Session_Namespace (the captcha word store) attaches to the live session
instead of fataling in Zend_Session::start()/Namespace ("already started" /
"not marked as readable").
Image-validated (vimbadmin:dev + a mailpit SMTP sink): captcha-on GET renders the
image (auth/captcha-image 200 image/png), the RIGHT word sends the reset mail,
the WRONG word shows the inline "does not match that of the image" error and
sends nothing; captcha-off lost-password + the full reset round-trip also send +
verify (new password logs in, the spent token is rejected).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
* WALL #2 slice 6b-1: native mail sender (symfony/mailer, inert) (#80) Foundation for porting the mailer-dependent tail (auth lost-password / reset-password, mailbox email-settings) off the ZF1 Zend_Mail path. Inert: nothing calls it yet, mirroring how each WALL #2 resource builder landed. - composer: require symfony/mailer ^8.0 (matches the locked symfony 8.1 band; pulls symfony/mime + event-dispatcher + egulias/email-validator). - src/Kernel/Mail/Mailer.php: framework-free sender. Turns the resources.mail.transport.* ini block (type smtp|sendmail, host, port, ssl tls|ssl|none, username/password, verify_peer[_name]) into a configured symfony transport and sends a Mime\Email. Transport-building decision is a pure, testable resolveConfig(); buildTransport() makes the real transport. ssl=ssl -> implicit TLS (465); ssl=tls/starttls -> opportunistic STARTTLS (587); omitted -> plaintext. verify_peer/_name routed through FILTER_VALIDATE_BOOLEAN so the ini "0" string disables verification. - Container::mailer(): lazily builds the Mailer from options[resources][mail][transport]. No Bootstrap change (reads options()). - tests/test-kernel-mailer.php (26 asserts) + regression.yml step. src/ stays free of the legacy framework prefix (guard green). * WALL #2 slice 6b-2: native auth lost-password / reset-password Ports OSS_Controller_Trait_Auth::lostPasswordAction/resetPasswordAction onto the native kernel, sending through the slice-6b-1 Mailer instead of Zend_Mail. The last two browser auth routes leave ZF1. - AbstractController: mailer() (native getMailer) + renderEmail() (body-only Smarty render, no page chrome) for the auth/email/* templates. - AuthController::lostPasswordAction: anti-enumeration (identical response whether or not the username exists); 40-char token stored as an expiring (2h, max 5) tokens.password_reset indexed preference; reset link mailed via the html email template. Captcha honoured when resources.auth.oss.lost_password.use_captcha is on — fresh OSS_Captcha_Image per render, typed text validated (as a field rule) against the SUBMITTED captcha id; image-click requests a new one (requestnewimage) and short-circuits before validation. The captcha PNG route (auth/captcha-image) stays ZF1 via the dispatcher fallback (de-Zended in 6c). - AuthController::resetPasswordAction: GET (from the emailed link) prefills username + token from the path; valid POST checks the token against the live reset-token preferences, sets the new hash, clears all tokens, zeroes any failed-login counter, mails a confirmation, redirects to login. All failure paths share one generic message. - sendAuthEmail() honours resources.auth.oss.email_format (html|plaintext|both) and sets From/To from identity.mailer.* + the admin email/formatted-name, mirroring resolveTemplate() + the legacy actions. - New native views auth/native-{lost,reset}-password.phtml (FormRenderer + captcha image/refresh; no Zend_Form JS validator). No NATIVE_CONTROLLERS / Kernel change (auth already native; the dispatcher invokes the new action methods). src/ stays free of the legacy prefix. * WALL #2 6b-2: make the ZF1 image captcha work under the native bootstrap Honouring resources.auth.oss.lost_password.use_captcha on the native lost-password page surfaced two native-bootstrap gaps in the reused ZF1 captcha (OSS_Captcha_Image extends Zend_Captcha_Image). Both fixed in the ZF1-zone entry point / the unscanned OSS lib; slice 6c de-Zends the captcha and removes these. - OSS_Utils::getIniOption(): null-guard the ZF1 front-controller bootstrap param (null under the native bootstrap) and fall back to the merged options the native entry publishes in Zend_Registry. Without it OSS_Captcha_Image's ctor fatals (getTempDir -> getIniOption -> getApplication() on null). - public/index.php (native zone): bridge Zend_Session to the already-open native PHP session — set _sessionStarted/_readable/_writable so a ZF1 Zend_Session_Namespace (the captcha word store) attaches to the live session instead of fataling in Zend_Session::start()/Namespace ("already started" / "not marked as readable"). Image-validated (vimbadmin:dev + a mailpit SMTP sink): captcha-on GET renders the image (auth/captcha-image 200 image/png), the RIGHT word sends the reset mail, the WRONG word shows the inline "does not match that of the image" error and sends nothing; captcha-off lost-password + the full reset round-trip also send + verify (new password logs in, the spent token is rejected).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
* WALL #2 slice 6b-2: native auth lost-password / reset-password Ports OSS_Controller_Trait_Auth::lostPasswordAction/resetPasswordAction onto the native kernel, sending through the slice-6b-1 Mailer instead of Zend_Mail. The last two browser auth routes leave ZF1. - AbstractController: mailer() (native getMailer) + renderEmail() (body-only Smarty render, no page chrome) for the auth/email/* templates. - AuthController::lostPasswordAction: anti-enumeration (identical response whether or not the username exists); 40-char token stored as an expiring (2h, max 5) tokens.password_reset indexed preference; reset link mailed via the html email template. Captcha honoured when resources.auth.oss.lost_password.use_captcha is on — fresh OSS_Captcha_Image per render, typed text validated (as a field rule) against the SUBMITTED captcha id; image-click requests a new one (requestnewimage) and short-circuits before validation. The captcha PNG route (auth/captcha-image) stays ZF1 via the dispatcher fallback (de-Zended in 6c). - AuthController::resetPasswordAction: GET (from the emailed link) prefills username + token from the path; valid POST checks the token against the live reset-token preferences, sets the new hash, clears all tokens, zeroes any failed-login counter, mails a confirmation, redirects to login. All failure paths share one generic message. - sendAuthEmail() honours resources.auth.oss.email_format (html|plaintext|both) and sets From/To from identity.mailer.* + the admin email/formatted-name, mirroring resolveTemplate() + the legacy actions. - New native views auth/native-{lost,reset}-password.phtml (FormRenderer + captcha image/refresh; no Zend_Form JS validator). No NATIVE_CONTROLLERS / Kernel change (auth already native; the dispatcher invokes the new action methods). src/ stays free of the legacy prefix. * WALL #2 6b-2: make the ZF1 image captcha work under the native bootstrap Honouring resources.auth.oss.lost_password.use_captcha on the native lost-password page surfaced two native-bootstrap gaps in the reused ZF1 captcha (OSS_Captcha_Image extends Zend_Captcha_Image). Both fixed in the ZF1-zone entry point / the unscanned OSS lib; slice 6c de-Zends the captcha and removes these. - OSS_Utils::getIniOption(): null-guard the ZF1 front-controller bootstrap param (null under the native bootstrap) and fall back to the merged options the native entry publishes in Zend_Registry. Without it OSS_Captcha_Image's ctor fatals (getTempDir -> getIniOption -> getApplication() on null). - public/index.php (native zone): bridge Zend_Session to the already-open native PHP session — set _sessionStarted/_readable/_writable so a ZF1 Zend_Session_Namespace (the captcha word store) attaches to the live session instead of fataling in Zend_Session::start()/Namespace ("already started" / "not marked as readable"). Image-validated (vimbadmin:dev + a mailpit SMTP sink): captcha-on GET renders the image (auth/captcha-image 200 image/png), the RIGHT word sends the reset mail, the WRONG word shows the inline "does not match that of the image" error and sends nothing; captcha-off lost-password + the full reset round-trip also send + verify (new password logs in, the spent token is rejected).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Ports the ZF1 emailSettingsAction + _sendSettingsEmail onto the native kernel — the last mailer-dependent browser action. Sends through the slice-6b-1 Mailer. - MailboxController::emailSettingsAction (GET|POST): the ajax "send settings" modal. GET returns the chrome-less modal (type select username/alt_email/other + an "other" free-text box, CSRF-guarded); POST send=1 resolves the recipient(s) and mails the per-user settings, returning the literal ok/error the modal JS expects, or re-rendering the modal with an inline error (the JS detects the <div class="modal-header"> prefix and swaps it in). "other" splits on comma and validates each address (ZF1 parity). - sendSettingsEmail(): From = server.email.*; body = mailbox/email/settings.phtml rendered with the per-user-substituted server.* display settings (Entities\Mailbox::substitute). The mailbox/sendSettingsEmail/preSetBody notify hook has no listeners, so it is not replicated; the welcome-email variant + cc are dropped (consistent with the other native mailbox actions, no mailer there). - AbstractController: renderEmail() generalised to renderPartial() (chrome-less template render for both email bodies AND ajax partials like this modal); AuthController updated to match. - New native view mailbox/native-email-settings.phtml (modal + type-toggle/ajax JS). No NATIVE_CONTROLLERS / Kernel change (mailbox already native; the dispatcher invokes the new action). Image-validated (vimbadmin:dev + mailpit): username -> mail to the mailbox; other with a bad address -> modal re-render, no send; other with two valid addresses -> mail to both; CSRF enforced. src/ stays free of the legacy prefix.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
…te) (#85) Ports the ZF1 emailSettingsAction + _sendSettingsEmail onto the native kernel — the last mailer-dependent browser action. Sends through the slice-6b-1 Mailer. - MailboxController::emailSettingsAction (GET|POST): the ajax "send settings" modal. GET returns the chrome-less modal (type select username/alt_email/other + an "other" free-text box, CSRF-guarded); POST send=1 resolves the recipient(s) and mails the per-user settings, returning the literal ok/error the modal JS expects, or re-rendering the modal with an inline error (the JS detects the <div class="modal-header"> prefix and swaps it in). "other" splits on comma and validates each address (ZF1 parity). - sendSettingsEmail(): From = server.email.*; body = mailbox/email/settings.phtml rendered with the per-user-substituted server.* display settings (Entities\Mailbox::substitute). The mailbox/sendSettingsEmail/preSetBody notify hook has no listeners, so it is not replicated; the welcome-email variant + cc are dropped (consistent with the other native mailbox actions, no mailer there). - AbstractController: renderEmail() generalised to renderPartial() (chrome-less template render for both email bodies AND ajax partials like this modal); AuthController updated to match. - New native view mailbox/native-email-settings.phtml (modal + type-toggle/ajax JS). No NATIVE_CONTROLLERS / Kernel change (mailbox already native; the dispatcher invokes the new action). Image-validated (vimbadmin:dev + mailpit): username -> mail to the mailbox; other with a bad address -> modal re-render, no send; other with two valid addresses -> mail to both; CSRF enforced. src/ stays free of the legacy prefix.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Native port of the ZF1 QueueController::triggerAction — the last WEB route still
served by the ZF1 fallback. Unauthenticated machine endpoint: Bearer-key
(SHA-256, constant-time) + source-IP-allowlist gated, then spawns a background
runner via the framework-free ViMbAdmin_QueueRunner::triggerCheck and returns
JSON. Empty queue.runner.key => 404 (disabled). No NATIVE_CONTROLLERS change
(queue already native; the dispatcher invokes the new action) — but this makes
canHandle('/queue/trigger') true, so the native stack now serves it instead of
falling through to ZF1.
Image-validated (vimbadmin:dev): empty key -> 404; no bearer -> 401; bad key ->
403; correct Bearer + allowed IP -> 200 {"triggered":false}. src/ stays free of
the legacy prefix (calls \ViMbAdmin_Net + \ViMbAdmin_QueueRunner, both
framework-free).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Native port of the ZF1 QueueController::triggerAction — the last WEB route still
served by the ZF1 fallback. Unauthenticated machine endpoint: Bearer-key
(SHA-256, constant-time) + source-IP-allowlist gated, then spawns a background
runner via the framework-free ViMbAdmin_QueueRunner::triggerCheck and returns
JSON. Empty queue.runner.key => 404 (disabled). No NATIVE_CONTROLLERS change
(queue already native; the dispatcher invokes the new action) — but this makes
canHandle('/queue/trigger') true, so the native stack now serves it instead of
falling through to ZF1.
Image-validated (vimbadmin:dev): empty key -> 404; no bearer -> 401; bad key ->
403; correct Bearer + allowed IP -> 200 {"triggered":false}. src/ stays free of
the legacy prefix (calls \ViMbAdmin_Net + \ViMbAdmin_QueueRunner, both
framework-free).
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
First slice of the cli-* migration off ZF1. Adds a framework-free CLI dispatcher mirroring the web kernel's opt-in strangler: bin/vimbtool.php tries the native path first and falls through to the ZF1 Zend_Application path for any command not yet migrated. - src/Kernel/Cli/CliCommand.php — a native CLI command (controller.action name, runs against the native Container, returns an exit code). - src/Kernel/Cli/Command/QueueRunCommand.php — queue.cli-run: drains the mailbox-task queue via the already-extracted, framework-free ViMbAdmin_Service_QueueRunner (#64) — the same engine runNow/runTask + the trigger endpoint use. The every-2-minutes cron entrypoint. - src/Kernel/Cli/CliKernel.php — registry + canHandle()/run(); boots via Bootstrap::boot() (which already skips the session under PHP_SAPI === 'cli', so only config + the Doctrine EM are built — no web scaffolding). - bin/vimbtool.php — native path before Zend_Application: parse argv with getopt(), and if the action is migrated, register a tiny Zend-free PSR-0 autoloader for the OSS_/ViMbAdmin_ library classes (not in the composer classmap; the ZF1 path's Zend_Loader runs only later) and run it. - tests/test-kernel-cli.php (6 asserts) + regression.yml. Image-validated (vimbadmin:dev): `vimbtool.php -a queue.cli-run -v` claims + runs a real PENDING task through the native runner (QUOTA_RECALC -> doveadm, FAILED only because dev dovecot has no quota plugin, same as ZF1), "Processed 1 task(s)", exit 0; an unmigrated command (maintenance.cli-schema-update) + -h still run via the ZF1 fallback. src/ stays free of the legacy prefix. Remaining cli-* (cli-reset-totp, cli-delete-pending, cli-schema-update, mcp.cli-token-*) follow as CliCommands; then 6c drops the ZF1 fallback.
eilandert
added a commit
that referenced
this pull request
Jun 6, 2026
Ports the remaining ZF1 cli*Actions onto native CliCommands (registered in CliKernel; bin/vimbtool.php dispatches them natively, ZF1 fallback for any not mapped — now none of the cli-* are unmapped): - admin.cli-reset-totp -> ResetTotpCommand (ViMbAdmin_TwoFactor, --username/--all) - mailbox.cli-delete-pending-> DeletePendingCommand (pendingDelete + rm_rf maildir/homedir, escapeshellarg) - maintenance.cli-schema-update -> SchemaUpdateCommand (ViMbAdmin_Schema::migrate, same as web #72) - mcp.cli-token-generate|list|revoke -> McpToken{Generate,List,Revoke}Command (McpToken CRUD) bin/vimbtool.php native block: register the ZF1 autoloader (Zend_/OSS_/ViMbAdmin_) + the residual legacy registry glue (Zend_Registry d2em/options) around the booted native Container — exactly as public/index.php does for the web. Needed because the entity-preference layer (OSS_Doctrine2_WithPreferences) and OSS_Utils read the EM/options from the registry (reset-totp hit this). Replaces the 6c-1 hand-rolled PSR-0 shim. CliKernel split into boot() + run(Container) so the entry point wires that glue between. Added --domains to the native getopt (mcp token generate). Image-validated (vimbadmin:dev): schema-update (up to date, v4), delete-pending (no pending), reset-totp --all (exit 0, no Zend_Registry fatal), mcp token generate -> list (active) -> revoke -> list (revoked). test-kernel-cli asserts all 7 registered names. src/ free of the legacy prefix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Splits the safe half out of Dependabot #1.
What
symfony/cacheconstraint to^6.4 || ^7.0 || ^8.0(lock: v7.4.13 → v8.1.0).Why split
Dependabot #1 grouped this with
doctrine/orm ^3.6. ORM3 removes APIs the codebase still uses (EntityManager::create(),set*CacheImpl(),Doctrine\\Common\\ClassLoader, old XmlDriver ctor) — would fatal at boot. That migration is deferred; this PR takes the risk-free cache bump for the longer support window (8.x is the current release line).Impact
symfony/cacheonly backs Doctrine's PSR-6 metadata/query/result caches viaDoctrineProvider::wrap()inOSS_Resource_Doctrine2cache. ApcuAdapter / RedisAdapter / ArrayAdapter are unchanged across 6/7/8 → no code change.php >=8.4.1already required, satisfies symfony 8 floor.Verified locally (PHP 8.4)
composer validate --strict✅composer update symfony/cache --with-all-dependencies→ 1 update, orm untouched ✅php -lacross application/library/public/bin ✅composer audit— no advisories ✅