Skip to content

Upgrade symfony8#147

Merged
XOlegator merged 26 commits into
masterfrom
upgrade-symfony8
May 27, 2026
Merged

Upgrade symfony8#147
XOlegator merged 26 commits into
masterfrom
upgrade-symfony8

Conversation

@XOlegator
Copy link
Copy Markdown
Contributor

Complete modernization of Intaro Pinboard:

Framework & runtime:

  • Silex → Symfony 8 (PHP 8.5, Doctrine DBAL 4, Twig 3, Symfony Console)
  • MySQL 5.x → MySQL 8.0 / 8.4 LTS (Pinba engine ported by XOlegator/pinba_engine)
  • pnpm + Webpack Encore for frontend assets

Architecture:

  • Doctrine migrations replace legacy schema management
  • DB-based and file-based user authentication (APP_AUTH_USER_SOURCE)
  • 12-step aggregation pipeline via php bin/console aggregate
  • Email notifications and per-server thresholds

Docker:

  • Public single-container image: xolegator/pinboard (nginx + php-fpm + supercronic)
  • docker-compose.public.yml for quick-start via Docker Hub
  • Dev stack via Makefile (make up / make up84 / make up80)

XOlegator and others added 26 commits May 23, 2026 22:28
Complete modernization of Intaro Pinboard:

Framework & runtime:
- Silex → Symfony 8 (PHP 8.5, Doctrine DBAL 4, Twig 3, Symfony Console)
- MySQL 5.x → MySQL 8.0 / 8.4 LTS (Pinba engine ported by XOlegator/pinba_engine)
- pnpm + Webpack Encore for frontend assets

Architecture:
- Doctrine migrations replace legacy schema management
- DB-based and file-based user authentication (APP_AUTH_USER_SOURCE)
- 12-step aggregation pipeline via `php bin/console aggregate`
- Email notifications and per-server thresholds

Docker:
- Public single-container image: xolegator/pinboard (nginx + php-fpm + supercronic)
- docker-compose.public.yml for quick-start via Docker Hub
- Dev stack via Makefile (make up / make up84 / make up80)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Restore CHANGELOG with v2.0 entry summarising the Symfony 8 rewrite
- Restore LICENSE (MIT, 2014–2026)
- composer.json: add name, description, homepage, authors, support, license
- security.yaml: fix critical auth bug — access_control had ROLE_USER rule
  commented out, allowing unauthenticated access to the entire application
- migrations 124237/124315/124434: replace debug InnoDB engine with correct
  ENGINE=PINBA and remove temporary commented-out code left from development
- migration 20260309173000: make idempotent — skip if tables already have
  PINBA engine (new installs with fixed migrations don't need the repair step)
- docs/: translate all Russian docs to English (configuration, deployment,
  standards, testing, README index)
- README.md: fix APP_AUTH_USER_SOURCE default value, add upgrade-from-1.x
  section, correct license reference to MIT
- Remove MailerController test skeleton (not needed in production)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Old loginAction() method (with Russian comments) duplicated app_login.
Also removes the unused Request import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Login template now extends base.html.twig instead of being standalone
- Form is rendered in a centered card (max-width 400px on desktop,
  full-width with side padding on mobile) using Bootstrap card + flex layout
- Added .login-page and .login-card CSS rules to app.scss
- base_url is now a Twig global via twig.yaml (APP_BASE_URL env var)
  so SecurityController no longer needs to pass it explicitly; also
  fixes any other future controller that might forget to pass it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ig files

parameters.yml.dist is the committed template for file-based auth;
parameters.yml (with real password hashes) stays gitignored.
Removed parameters.yml.dist from gitignore — it was incorrectly excluded
by the Symfony default .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Redis connection string (potentially with password) goes in .env.local;
adapter choice stays in cache.yaml as commented examples.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… env

Symfony DI compiles service references statically; env vars cannot select
a cache adapter. REDIS_URL (connection string) stays in env as intended.
Document this constraint inline so deployers know editing cache.yaml is correct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The `hosts` field in parameters.yml was loaded into FileUser but never
enforced — all authenticated users could see all servers.

Restored filtering in three places:
- BeforeController: server list in the navigation menu
- IpmReportByServerNameRepository / MainController: server index page
- ServerController: 403 guard on every server action (overview, timers,
  statuses, req-time, mem-usage, cpu-usage, live)

DB users (APP_AUTH_USER_SOURCE=db) are unrestricted as before —
the User entity has no hosts field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oreController

BeforeController is instantiated manually via `new` (not via DI), so
$this->getUser() / $this->container are never initialized — causing
"must not be accessed before initialization" on every page.

Fix: callers (ServerController, MainController) resolve the regexp from
their own properly-injected $this->getUser() and pass it to actionBefore().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously hosts filtering only worked for file-based auth (FileUser).
DB users (User entity) always saw all servers.

Changes:
- User entity: add nullable `hosts` VARCHAR(500) column
- Migration Version20260524190059: ALTER TABLE user ADD hosts
- AddUserCommand: save hosts argument for DB users (was ignored before)
- Utils::getUserHostsRegexp(): handle both FileUser and DB User
- docs/configuration.md: document hosts argument for both auth modes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add UtilsAccessTest: 12 cases covering getUserHostsRegexp() and
  userCanAccessServer() for null user, FileUser, DB User, wildcard,
  alternation patterns
- SwitchableUserProviderTest: createMock → createStub for repository
  stubs without expectations (fixes PHPUnit 13 notices)
- Migrate phpunit.xml.dist to current schema (removes deprecation warning)
- CS Fixer: sort imports in ServerController

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Restore HAVING cnt > 10: was temporarily removed for local testing
  (comment said "убрал для теста"), now back as intended production behaviour
- Remove commented-out route #[Route('/before')] with "Не в том месте" note
- Remove commented-out old SQL variant (superseded by restored query)
- Remove speculative caching TODO comment
- Remove commented-out Silex-era $app['menu'] assignment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New users were confused because:
- README said "data appears after 15 min" — true for the main dashboard
- Navigation menu requires 10 aggregation cycles (~2.5 h) due to
  HAVING cnt > 10 filter, which was not documented anywhere

Added a clear table in README.md (Quick start), docs/deployment.md
(new "Data visibility timeline" section), and a cross-reference in
docs/docker.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
base_url is already a Twig global (APP_BASE_URL env var, set in
twig.yaml). Passing it as a template variable overrides the global
with a hardcoded '/' — defeating the purpose of APP_BASE_URL entirely.

The same pattern exists in ServerController and TimerController
and will be cleaned up there too.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…in TimerController

- Remove all 'base_url' => '/' overrides (ServerController ×7, TimerController ×1)
  that shadowed the APP_BASE_URL Twig global
- Fix TimerController::buildMenu() missing hostsRegexp — users with restricted
  hosts were seeing all servers in the nav menu on timer pages
- Drop unused 'date' param from getRequestById req_time branch (active SQL
  never used :date; only the commented-out variant did)
- Remove Silex-era commented fetchAll/executeQuery lines from ServerController
  (getHosts, getStatusesReview, getRequestPerSecReview, getRequestReview)
- Simplify getReqTimeBorder signature ($app param unused since Silex removal)
- Fix loose != to !== in getErrorPagesCount
- Remove 'пока для теста' / 'Нужно переосмыслить' placeholder comments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Delete AppFixtures.php — auto-generated empty stub that only called flush()
  with no persisted objects; provides no value
- Inject UserPasswordHasherInterface into UserFixtures and hash the password
  at load time instead of storing a hardcoded bcrypt hash (fragile, algo-tied)
- Set ROLE_ADMIN so the fixture user can actually use the admin panel
- Use admin@example.com (consistent with project docs) and remove the
  auto-generated '// $product = new Product()' comment noise

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Display the current user's identifier (email / username) as a dropdown
toggle on the right side of the top navigation bar. The dropdown contains
a single 'Sign out' link pointing to the existing app_logout route.

The block is guarded by `app.user is not null` so it does not appear on
the login page or any unauthenticated context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…om all repos

Every repository file was missing declare(strict_types=1). Additionally,
all auto-generated findByExampleField / findOneBySomeField placeholder
stubs (produced by make:entity) were left in — these reference a fictional
'exampleField' and are pure boilerplate noise. None of them were ever
wired to actual use in controllers or commands.

Removed stubs from 21 files; added strict_types declaration to all 22
repository files (including the one fixed in the prior commit for
IpmCpuUsageDetails). Custom methods in IpmReportByServerNameRepository
(findAllServers) and UserRepository (upgradePassword) are untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…attern

**Real improvements, not annotation noise:**

ServerController / TimerController — \$conn parameter removal:
  All data-fetching methods took \$conn as first arg (always \$this->entityManager,
  a Silex-era pattern). Removed the param, use \$this->entityManager directly,
  made all internal data methods private. 91 of 142 level-6 errors came from
  this one pattern.

AggregateCommand:
  - isNotIgnore(\$host) → isNotIgnore(string \$host) — was genuinely untyped
  - getBorderOutValues(\$db, \$servers) → fully typed with Connection + array types
  - envCsv() return type narrowed to list<string>
  - All notification-sending methods annotated with precise array shapes

Security layer:
  - FileUser roles array: list<string> throughout (constructor, getRoles, setRoles)
  - FileUserStorage loadUsers/replaceUsers/upsertUser/loadRawConfig/saveRawConfig
    all annotated with array<string, mixed> / list<string>
  - SwitchableUserProvider: @implements UserProviderInterface<FileUser|User>

Stopwatch:
  - \$initTags and both tag-array parameters: array<string, string>

Utils::parseRequestTags:
  - array|bool narrowed to array<string, mixed>|false (more accurate)

Controllers return types:
  - actionLive(): Response (was missing)
  - actionTimer(): parameters string-typed
  - All SQL-result-returning methods annotated with list<array<string, mixed>>
    or more specific shapes (getStatusesReview, getRequestPerSecReview, getTimersList)

PHPStan level: 5 → 6 (0 errors)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove Silex-era $conn parameters from all data methods (ServerController,
  TimerController) — methods are now private and use $this->entityManager directly
- Add precise PHPDoc return types to all data methods in both controllers
- Fix strtotime()|false → (int) cast for date() calls
- Fix parseRequestTags() false-return handling in foreach loops
- Fix getLivePages() list continuity after unset() via array_values()
- Fix findGroupingTags() list return type via array_values() after unset()
- Narrow FileUser::$identifier to non-empty-string via @param annotation;
  remove now-dead empty-string guard from constructor
- Narrow SwitchableUserProvider::loadUserByIdentifier() — validate empty
  identifier at entry, skip empty array keys in fallback search loop
- Add (string) casts in LoginFormAuthenticator for request->get() results
- Add @var array<string,string> and (string) casts in Stopwatch::$initTags

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant