Upgrade to 1.0.0-rc372

Concerns: pushword/admin, pushword/core

Migration Steps

  1. Run composer update
  2. Run php bin/console doctrine:schema:update --force (adds new template column to page table)
  3. Run php bin/console pw:migrate (migrates data from JSON customProperties to new columns, fixes typos)
  4. Clear cache: php bin/console cache:clear
  5. Update custom code per the breaking changes below

Entity Changes

Page

  • Template column promoted: template is now a real database column (nullable string), no longer stored in customProperties JSON. Getter/setter unchanged: getTemplate() / setTemplate().
  • searchExcerpt typo fixed: getSearchExcrept() removed. Use getSearchExcerpt(). In Twig: page.searchExcrept becomes page.searchExcerpt.
  • Traits inlined: PageEditorTrait, PageExtendedTrait, PageMainImageTrait, PageOpenGraphTrait, PageSearchTrait, PageRedirectionTrait are removed. Their properties and methods are inlined directly into Page.
  • PHP 8.4 property hooks: Simple properties ($h1, $slug, $title, $metaRobots, $name, $editMessage) now use property hooks. Getter/setter methods are retained for caller compatibility.
  • Redirection API changed: getRedirection() now returns ?PageRedirection value object (or null). Use hasRedirection(), getRedirectionUrl(), getRedirectionCode() instead of accessing the old string-based redirection.
  • OG/Twitter getters explicit: getOgTitle(), setOgTitle(), getOgDescription(), etc. are explicit methods (no longer resolved via __call). They still store data in customProperties JSON.
  • __call minimal: Only proxies getCustomProperty() for Twig ergonomics (page.someKey). No method-existence cache, no complex resolution.

Media

  • Image data as embeddable: ImageTrait replaced by ImageData Doctrine embeddable (#[ORM\Embedded(class: ImageData::class, columnPrefix: false)]). DQL queries must use m.imageData.width, m.imageData.height, m.imageData.ratioLabel etc.
  • Removed deprecated methods: getMedia() and getName() removed. Use getFileName() and getAlt().
  • $disableRemoveFile removed: The public flag on Media is gone.

User

  • CustomPropertiesTrait replaced by ExtensiblePropertiesTrait (same JSON column, cleaner API).
  • getSalt() removed (not needed with bcrypt).

SharedTrait: ExtensiblePropertiesTrait

Replaces CustomPropertiesTrait:

Old APINew API
$standAloneCustomPropertiesgetUnmanagedPropertiesAsYaml() / setUnmanagedPropertiesAsYaml()
$registeredCustomPropertyFieldsregisterManagedPropertyKey() / getManagedPropertyKeys()
Method-existence cache ($methodExistsCache)Removed
CustomPropertiesExceptionInvalidArgumentException

Core API unchanged: getCustomProperty(), setCustomProperty(), hasCustomProperty(), removeCustomProperty(), getCustomPropertyScalar(), getCustomPropertyList().

Architecture Changes

Site Configuration

OldNew
Pushword\Core\Component\App\AppConfigPushword\Core\Site\SiteConfig
Pushword\Core\Component\App\AppPoolPushword\Core\Site\SiteRegistry + Pushword\Core\Site\RequestContext
  • SiteRegistry: Pure registry for site configurations. Methods: get(), getDefault(), findByHost(), getHosts(), getAll(), isKnownHost().
  • RequestContext: Request-scoped state. Methods: switchSite(), setCurrentPage(), getCurrentPage(), requirePage(), getCurrentSite(), getLocale().
  • SiteRegistry also delegates to RequestContext for convenience: switchSite(), setCurrentPage(), getCurrentPage(), getMainHost(), getLocale(), etc.

Template Resolution

OldNew
AppConfig::getView() (with Twig+Cache on config)TemplateResolver::resolve() (dedicated service)
  • SiteConfig::getView() still works (delegates to TemplateResolver).
  • TemplateResolver is a standalone service (Pushword\Core\Template\TemplateResolver) injected via DI.

Page Resolution

OldNew
Duplicated findPage() in PageController and FeedControllerPageResolver service
  • PageResolver::findPageOr404(): Shared page lookup logic (slug normalization, pager extraction, permission checks).
  • PageResolver::normalizeSlug(): Static method for slug normalization.

Content Pipeline

OldNew
Pushword\Core\Component\EntityFilter\ManagerPushword\Core\Content\ContentPipeline
Pushword\Core\Component\EntityFilter\ManagerPoolPushword\Core\Content\ContentPipelineFactory
  • ContentPipeline adds explicit typed getters: getMainContent(), getTitle(), getName().
  • ContentPipelineFactory::get(Page) creates pipelines (replaces ManagerPool::getManager()).
  • The pw() Twig function is now on ContentPipelineFactory (moved from ManagerPool).
  • Legacy Manager/ManagerPool still exist for backward compatibility with existing filters. Filters still receive Manager in their apply() signature.

Events

  • PushwordEvents catalog class created at Pushword\Core\Event\PushwordEvents with centralized constants: FILTER_BEFORE, FILTER_AFTER, ADMIN_MENU, ADMIN_LOAD_FIELD.
  • Existing event classes (FilterEvent, AdminMenuItemsEvent, FormField\Event) now reference PushwordEvents constants.

Admin Changes

  • standAloneCustomProperties form field binding changed to unmanagedPropertiesAsYaml.
  • searchExcrept form field binding changed to searchExcerpt.

Twig Template Changes

OldNew
page.searchExcreptpage.searchExcerpt

Other Twig access patterns unchanged: page.ogTitle, page.h1, page.slug, page.someCustomKey all work as before.