uxf / cms
    3.71.0
    2025-10-09 09:20 UTC
Requires
- php: ^8.3
 - ext-json: *
 - sentry/sentry: ^4.6
 - symfony/http-client: ^7.2
 - symfony/mailchimp-mailer: ^7.2
 - symfony/psr-http-message-bridge: ^7.2
 - symfony/security-bundle: ^7.2
 - symfony/twig-bundle: ^7.2
 - uxf/content: 3.71.0
 - uxf/datagrid: 3.71.0
 - uxf/form: 3.71.0
 - uxf/security: 3.71.0
 - uxf/storage: 3.71.0
 
- 3.x-dev
 - 3.71.0
 - 3.70.5
 - 3.70.4
 - 3.70.3
 - 3.70.2
 - 3.70.1
 - 3.70.0
 - 3.69.12
 - 3.69.10
 - 3.69.9
 - 3.69.8
 - 3.69.7
 - 3.69.6
 - 3.69.5
 - 3.69.4
 - 3.69.3
 - 3.69.1
 - 3.69.0
 - 3.68.6
 - 3.68.5
 - 3.68.4
 - 3.68.3
 - 3.68.2
 - 3.68.1
 - 3.68.0
 - 3.67.4
 - 3.67.3
 - 3.67.2
 - 3.67.1
 - 3.67.0
 - 3.66.1
 - 3.66.0
 - 3.65.3
 - 3.65.2
 - 3.65.1
 - 3.65.0
 - 3.64.4
 - 3.64.3
 - 3.64.2
 - 3.64.1
 - 3.64.0
 - 3.63.1
 - 3.63.0
 - 3.62.4
 - 3.62.3
 - 3.62.2
 - 3.62.1
 - 3.62.0
 - 3.61.7
 - 3.61.6
 - 3.61.5
 - 3.61.3
 - 3.61.2
 - 3.61.1
 - 3.61.0
 - 3.60.12
 - 3.60.11
 - 3.60.10
 - 3.60.8
 - 3.60.7
 - 3.60.5
 - 3.60.3
 - 3.60.1
 - 3.60.0
 - 3.59.0
 - 3.58.9
 - 3.58.8
 - 3.58.7
 - 3.58.5
 - 3.58.4
 - 3.58.2
 - 3.58.1
 - 3.58.0
 - 3.57.12
 - 3.57.11
 - 3.57.10
 - 3.57.9
 - 3.57.7
 - 3.57.6
 - 3.57.5
 - 3.57.4
 - 3.57.3
 - 3.57.1
 - 3.57.0
 - 3.56.4
 - 3.56.3
 - 3.56.2
 - 3.56.1
 - 3.56.0
 - 3.55.9
 - 3.55.8
 - 3.55.7
 - 3.55.6
 - 3.55.5
 - 3.55.4
 - 3.55.3
 - 3.55.2
 - 3.55.1
 - 3.55.0
 - 3.54.5
 - 3.54.4
 - 3.54.3
 - 3.54.2
 - 3.54.1
 - 3.54.0
 - 3.53.7
 - 3.53.3
 - 3.53.2
 - 3.53.1
 - 3.53.0
 - 3.52.0
 - 3.51.2
 - 3.51.0
 - 3.50.6
 - 3.50.5
 - 3.50.3
 - 3.50.2
 - 3.50.1
 - 3.50.0
 - 3.49.2
 - 3.49.1
 - 3.49.0
 - 3.48.2
 - 3.48.1
 - 3.48.0
 - 3.47.2
 - 3.47.0
 - 3.46.12
 - 3.46.11
 - 3.46.10
 - 3.46.9
 - 3.46.8
 - 3.46.7
 - 3.46.6
 - 3.46.5
 - 3.46.4
 - 3.46.3
 - 3.46.2
 - 3.46.1
 - 3.46.0
 - 3.45.3
 - 3.45.2
 - 3.45.1
 - 3.45.0
 - 3.44.6
 - 3.44.5
 - 3.44.4
 - 3.44.3
 - 3.44.2
 - 3.44.1
 - 3.44.0
 - 3.43.3
 - 3.43.2
 - 3.43.1
 - 3.43.0
 - 3.42.1
 - 3.42.0
 - 3.41.2
 - 3.41.1
 - 3.41.0
 - 3.40.7
 - 3.40.6
 - 3.40.5
 - 3.40.4
 - 3.40.3
 - 3.40.2
 - 3.40.1
 - 3.40.0
 - 3.39.5
 - 3.39.4
 - 3.39.3
 - 3.39.2
 - 3.39.1
 - 3.38.2
 - 3.38.1
 - 3.38.0
 - 3.37.1
 - 3.37.0
 - 3.36.3
 - 3.36.2
 - 3.36.0
 - 3.35.5
 - 3.35.4
 - 3.35.2
 - 3.35.1
 - 3.35.0
 - 3.34.3
 - 3.34.0
 - 3.33.1
 - 3.33.0
 - 3.32.4
 - 3.32.3
 - 3.32.2
 - 3.32.0
 - 3.31.1
 - 3.31.0
 - 3.30.1
 - 3.30.0
 - 3.29.2
 - 3.29.1
 - 3.29.0
 - 3.28.0
 - 3.27.9
 - 3.27.8
 - 3.27.7
 - 3.27.5
 - 3.27.4
 - 3.27.3
 - 3.27.2
 - 3.27.0
 - 3.26.1
 - 3.26.0
 - 3.25.5
 - 3.25.4
 - 3.25.3
 - 3.25.2
 - 3.25.1
 - 3.25.0
 - 3.24.7
 - 3.24.6
 - 3.24.5
 - 3.24.4
 - 3.24.3
 - 3.24.2
 - 3.24.1
 - 3.24.0
 - 3.23.9
 - 3.23.8
 - 3.23.3
 - 3.23.1
 - 3.23.0
 - 3.22.0
 - 3.21.4
 - 3.21.3
 - 3.21.0
 - 3.20.3
 - 3.20.1
 - 3.20.0
 - 3.19.5
 - 3.19.4
 - 3.19.3
 - 3.19.2
 - 3.19.1
 - 3.19.0
 - 3.18.0
 - 3.17.4
 - 3.17.3
 - 3.17.1
 - 3.17.0
 - 3.16.1
 - 3.16.0
 - 3.15.6
 - 3.15.5
 - 3.15.4
 - 3.15.3
 - 3.15.1
 - 3.13.5
 - 3.13.4
 - 3.13.2
 - 3.13.0
 - 3.12.1
 - 3.11.3
 - 3.11.2
 - 3.11.1
 - 3.11.0
 - 3.10.3
 - 3.10.1
 - 3.10.0
 - 3.9.2
 - 3.8.2
 - 3.8.1
 - 3.8.0
 - 3.7.3
 - 3.7.1
 - 3.7.0
 - 3.6.3
 - 3.6.2
 - 3.6.1
 - 3.6.0
 - 3.5.0
 - 3.4.0
 - 3.3.0
 - 3.2.6
 - 3.2.5
 - 3.2.4
 - 3.2.3
 - 3.2.2
 - 3.2.1
 - 3.2.0
 - 3.1.4
 - 3.1.3
 - 3.1.2
 - 3.1.1
 - 3.1.0
 - 3.0.4
 - 3.0.3
 - 3.0.2
 - 3.0.1
 - 3.0.0
 - 2.6.0
 - 2.5.1
 - 2.5.0
 - 2.4.2
 - 2.4.1
 - 2.4.0
 - 2.3.0
 - 2.2.0
 - 2.1.0
 - 2.0.0
 - 1.4.0
 - 1.3.0
 - 1.2.1
 - 1.2.0
 - 1.1.5
 - 1.1.4
 - 1.1.3
 - 1.1.2
 - 1.1.1
 - 1.1.0
 - 1.0.0
 - v0.10.9
 - v0.10.8
 - v0.10.7
 - v0.10.6
 - v0.10.5
 - v0.10.4
 - v0.10.3
 - v0.10.2
 - v0.10.1
 - v0.10.0
 - v0.9.1
 - v0.9.0
 - v0.8.3
 - v0.8.2
 - v0.8.1
 - v0.8.0
 - v0.7.2
 - v0.7.1
 - v0.7.0
 - v0.6.1
 - v0.6.0
 - v0.5.3
 - v0.5.2
 - v0.5.1
 - v0.5.0
 - v0.4.2
 - v0.4.1
 - v0.4.0
 - v0.3.1
 - v0.3
 - v0.2.4
 - v0.2.3
 - v0.2.2
 - v0.2.1
 - v0.2
 - v0.1.4
 - v0.1.3
 - v0.1.2
 - v0.1.1
 - v0.1
 - dev-main
 - dev-master
 - dev-surname-fix
 - dev-develop
 - dev-feat/user-config-datagrid
 - dev-role-serialize
 
This package is auto-updated.
Last update: 2025-10-09 07:24:33 UTC
README
Install
$ composer require uxf/cms
Config
// config/routes/uxf.php
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return static function (RoutingConfigurator $routes): void {
    $routes->import('@UXFCmsBundle/config/routes.php');
    $routes->import('@UXFStorageBundle/config/routes.php');
    $routes->import('@UXFSecurityBundle/config/routes.php');
    $routes->import('@UXFContentBundle/config/routes.php');
    $routes->import('@UXFDataGridBundle/config/routes.php');
    $routes->import('@UXFFormBundle/config/routes.php');
};
// config/packages/uxf.php
use UXF\CMS\Entity\User;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('uxf_cms', [
        'audit_token' => 'xxx', # optional
        'mailing' => [
            'email_from' => 'info@uxf.cz',
            'email_name' => 'UXF info',
            'invitation_url' => 'https://uxf.cz/renew-password/',
            'recovery_url' => 'https://uxf.cz/renew-password/',
            'cms_recovery_url' => 'https://uxf.cz/admin/cms/renew-password/',
            'tag' => env('PROJECT_TAG'),
            'email_previews' => '%kernel.project_dir%/src/EmailZone/Email',
        ],
        'storage' => [
            'default_upload_namespace' => 'cms',
        ],
        'cron' => [
            'stage' => 'wow',                         # optional (default value from logger.sentry.environment)
            'sources' => [__DIR__ . '/../Project'],   # optional (default ./src)
            'destinations' => [__DIR__ . '/cron'],    # optional (default ./docker/cron)
            'enabled_stages' => ['magic'],            # optional (default [prod, dev])
        ],
        'loggable' => [
            'sources' => '%kernel.project_dir%/src/Entity',
        ],
        'logger' => [
            'stdout' => [
                'enabled' => true, # default false
                'level' => 'notice', # optional
            ],
            'sentry' => [
                'dsn' => '%env(SENTRY_DSN)%',
                'environment' => '%env(SENTRY_ENV)%',
                'release' => 'none', # optional
                'level' => 'warning', # optional
                'traces_sample_rate' => 0.5, # default 0
            ],
        ],
    ]);
};
CronJob
- Send monitoring info to sentry
 - Generate crontab file
 - Enable run commands only on enabled stages
 - use 
FORCE_RUN=1environmental variable to skip stage check 
$ bin/console uxf:cron-gen
use Symfony\Component\Console\Attribute\AsCommand;
use UXF\CMS\Attribute\CronJob;
#[CronJob(crontab: '*/5 * * * *', slug: 'Ring', args: '--wizard', enabledStages: ['prod'])]
#[AsCommand('app:cron:magic')]
final class MagicCronCommand extends Command
{
    ...
}
Autocomplete
A) CmsMeta attribute
Add autocompleteFields to CmsMeta. New autocomplete is registered automatically with name by alias.
#[ORM\Entity]
#[ORM\Table(name: 'users', schema: 'uxf_cms')]
#[CmsMeta(alias: 'user', title: 'User', autocompleteFields: ['name', 'email'])]
class User
{
    ...
}
B) CmsForm/CmsGrid attribute (override default autocomplete)
#[CmsForm(label: 'Uživatelská role', targetField: 'title', autocomplete: 'role')]
#[CmsGrid(label: 'Uživatelská role', targetColumn: 'title', autocomplete: 'role')]
#[ORM\ManyToOne]
private Role $role;
C) AutocompleteType
final class CategoryType implements AutocompleteType
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
    ) {
    }
    /**
     * @param mixed[] $options
     */
    public function buildAutocomplete(AutocompleteBuilder $builder, array $options = []): void
    {
        // you can use 4th $labelQuery argument - eg. '{name} {surname} ({email})'
        $autocomplete = DoctrineAutocomplete::create($this->entityManager, Category::class, ['name']);
        // you can modify QB conditions
        $autocomplete->qb->andWhere('e.id > 1');
        $builder->setAutocomplete($autocomplete);
    }
    public static function getName(): string
    {
        return 'content-category';
    }
}
D) AutocompleteInterface - total custom
class TestAutocomplete implements Autocomplete
{
    /**
     * @return AutocompleteResult[]
     */
    public function search(string $term, int $limit): array
    {
        ...
    }
}
Security
use Symfony\Component\Routing\Attribute\Route;
use UXF\Core\Attribute\Security;
final readonly class TestController
{
    #[Route(path: '/api/test', name: 'test', methods: 'GET')]
    #[Security(UserRole::ROLE_PROFILE)] // use 'PUBLIC' for anonymous access, 'LOGGED' for logged user (role is ignored)
    public function __invoke(AppRequest $appRequest): mixed
    {
        ...
    }
}
Email previews
All email previews configured in source directory uxf_cms.mailing.email_previews are listed at /api/cms/email/list 
final class SampleEmail extends PreviewableEmail
{
    public function __construct(
        public readonly string $url,
    ) {
        parent::__construct('/email-templates.twig');
    }
    /**
     * @return self[]
     */
    public static function getPreviewData(): array
    {
        return [
            new self('https://uxf.cz'),
        ];
    }
}
send email preview command
To test email clients there is command:
bin/console uxf:email:send-preview your-email@uxf.cz app_email-zone_email_organization-application-accepted-email
email identifier is same as preview url
Loggable
You can log changes in entities to cms change_log table.
// config/packages/uxf.php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('uxf_cms', [
        ...
        'loggable' => [
            'sources' => '%kernel.project_dir%/src/Entity',
        ],
    ]);
};
use Doctrine\ORM\Mapping as ORM;
use UXF\CMS\Attribute\Loggable;
use UXF\CMS\Contract\NormalizedLoggable;
#[ORM\Entity]
class Article
{
    #[Loggable]
    #[ORM\Column]
    private int $integer = 0;
    #[Loggable]
    #[ORM\Column]
    private string $name = '';
    #[Loggable] // call Category::normalize() method
    #[ORM\ManyToOne]
    private Category $category;
    #[Loggable(['id', 'name'])] // pick values from id + name properties (by getters)
    #[ORM\ManyToOne]
    private Category $category2;
}
#[ORM\Entity]
class Category implements NormalizedLoggable
{
    ...
    /**
     * @return array<string, mixed>
     */
    public function normalize(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
        ];
    }
}