Useful features for Symfony, Doctrine, Twig etc.
If you are using PhpStorm, then an easy way to use this feature is to create an external tool (File-> Settings-> Tools-> External Tools) with parameters:
- Name: Runner
- Program: /usr/bin/php
- Arguments: -d xdebug.remote_autostart=1 -d xdebug.remote_enable=1 bin/console symfony-common:runner $FilePath$ $LineNumber$
- Working Directory: $ProjectFileDir$
After that, select Tools -> External Tools -> Runner - the command will try to execute a function or method from where the cursor is currently located.
At this point, execution will not automatically stop at the specified location - you must manually set a breakpoint.
Cosmologist\Bundle\SymfonyCommonBundle\Doctrine\ExtraConnection is Doctrine DBAL-connection wrapper that add useful features and methods to DBAL.
Add the wrapper_class parameter to the Doctrine DBAL connection configuration in config.yml to use:
default:
driver: pdo_mysql
dbname: ~
user: ~
password: ~
host: ~
wrapper_class: \Cosmologist\Bundle\SymfonyCommonBundle\Doctrine\ExtraConnection
postBeginTransaction, postCommit, postRollback
Connection::fetchAllIndexed prepares and executes an SQL query and returns the result as an associative array, each row in the result set array is indexed by the value of the first column.
$connection->fetchAllIndexed('SELECT id, name FROM users');
// 1 => [id: 1, name: Ivan]
// 7 => [id: 7, name: Vasiliy]
// ...
Get Doctrine utils
$utils = $container->get(Cosmologist\Bundle\SymfonyCommonBundle\Doctrine\DoctrineUtils::class);
// or
$utils = $container->get('symfony_common.doctrine.utils');
Get real class of Doctrine entity (resolve entity proxy class)
Supports Doctrine < 3.x and Doctrine > 3.x
$entity = $entityManager->find(App\Entity\Foo::class, $identifier);
DoctrineUtils::getRealClass($entity); \\ "App\Entity\Foo"
DoctrineUtils::getRealClass(App\Entity\Foo::class); \\ "App\Entity\Foo"
Simple way to get doctrine entity metadata
$utils->getClassMetadata($entity);
$utils->getClassMetadata(Entity::class);
Get the target class name of the given association path (ie "contact.user") recursively
$doctrineUtils->getAssociationTargetClassRecursive('AppBundle/Entity/Company', 'contact.user'); // 'AppBundle/Entity/User'
Get entity identifier field name (does not support multiple identifiers - throws DoctrineUtilsException)
$utils->getEntitySingleIdentifierField($entity);
$utils->getEntitySingleIdentifierField(Entity::class);
Get entity identifier value (does not support multiple identifiers - throws DoctrineUtilsException)
$utils->getEntitySingleIdentifierValue($entity);
Determine if the object or FQCN is a Doctrine entity (under Doctrine control) or not
$utils->isEntity($entity);
Get the readable alias for the doctrine entity
$this->getEntityAlias(FooBundle\Entity\Bar\Baz::class); // 'foo.bar.baz'
$this->decodeEntityAlias('foo.bar.baz'); // 'FooBundle\Entity\Bar\Baz'
Perform recursively join operation of the given association path (ie "contact.user.type")
$qb = $entityManager->getRepository(Company::class)->createQueryBuilder('company');
# Recursive joins
DoctrineUtils::joinRecursive($qb, 'contact.user.type');
// equivalent to
$qb
->join('company.contact', 'contact')
->join('contact.user', 'user')
->join('user.type', 'type');
Attention: method doesn't care about alias uniqueness
Add a join to the query once
// Adds join and returns an alias of added join
DoctrineUtils::joinOnce($qb, 'contact.user', 'u1'); // "u1"
// If a join with specified parameters exists then only returns an alias of existed join
DoctrineUtils::joinOnce($qb, 'contact.user', 'u2'); // "u1"
Merge multiple Doctrine\Common\Collections\Criteria
into a one Doctrine\Common\Collections\Criteria
$resultCriteria = DoctrineUtils::mergeCriteria($firstCriteria, $secondCriteria);
Forwards to another URI.
Like Symfony\Bundle\FrameworkBundle\Controller\Controller::forward, but using URI.
$utils = $container->get('symfony_common.routing.utils');
$utils->forwardToUri('/products/programmers-t-shirts');
// or
$utils->forwardToUri('https://myshop.com/products/programmers-t-shirts');
bin/console symfony-common:acl:set
Cosmologist\Bundle\SymfonyCommonBundle\Security\Voter\SuperUserRoleVoter adds a special role "ROLE_SUPER_USER" which effectively bypasses any, and all security checks.
The service Crypto
provides functions for the simple symmetric encryption.
The framework.secret used as a key to encryption.
$crypto = $container->get(Cosmologist\Bundle\SymfonyCommonBundle\Security\Crypto::class);
$crypto->decrypt($crypto->encrypt('The sensitive string')); // 'The sensitive string'
DependencyInjectionUtils::getDoctrineDbalConnectionReference('default'); // doctrine.dbal.default_connection
DependencyInjectionUtils::getDoctrineOrmEntityManagerReference('default'); // doctrine.orm.default_entity_manager
Useful for:
- to simplify your configuration
- to avoid problem of losing the key when you merge config across files (Symfony Issue #29817)
Usage:
# AppBundle\DependencyInjection\Configuration.php
...
use Cosmologist\Bundle\SymfonyCommonBundle\DependencyInjection\DependencyInjectionUtils;
...
->arrayNode('events')
->beforeNormalization()
->always(ConfigurationUtils::useKeyAsAttribute('server'))
->end()
->prototype('array')
...
Config like this:
something:
servers:
serverA:
username: userA
password: passwordA
serverB:
username: userB
password: passwordB
comes out like:
servers [
serverA => [username: userA, password: passwordA, server: serverA],
serverB => [username: userB, password: passwordB, server: serverB],
]
A convenient way to dynamically access symfony services.
# app/config/routing.yml
admin.service:
resource: "@SymfonyCommonBundle/Resources/config/routing.yml"
prefix: /admin
URL example:
yourdomain.com/bridge/mybundle.foo/bar
or
yourdomain.com/bridge/MyBundle\Foo/bar
- /bridge is a ServiceBridge route suffix
- mybundle.foo (or MyBundle\Foo) is a service name
- process is service method name
Method arguments must be passed as POST parameters. ServiceBridge automatically fetches a Doctrine entity if the method expects an argument of the entity (the hint type of the argument).
The method arguments should be passed as POST-parameters.
ServiceBridge fetch entity from Doctrine automatically, by the identifier from request, if method expects entity argument (argument type-hint).
Caution: Use security access_control option to restrict access to the service controller.
- array|object -> json
- binary string -> response with content-disposition=attachment and binary content-type
- another scalar -> simple response
use Cosmologist\Bundle\SymfonyCommonBundle\DependencyInjection\ContainerStatic;
ContainerStatic::getContainer();
ContainerStatic::get('serivice_id');
ContainerStatic::getParameter('parameter_id');
{% include '@SymfonyCommon/pagination.html.twig' with { page: current_page, count: items_total, limit: items_per_page } %}
{# Parameters:
* page (int) : The current page you are in
* limit (int): Number of records to display per page
* count (int): Total count of records
* currentFilters (array)(optional) : associative array that contains route-arguments #}
# app/config/config.yml
symfony_common:
twig:
php_extension:
filters:
- strip_tags # register php "strip_tags" function as twig "strip_tags" filter
-
foo_bar: # register static method MyApp\Foo::bar as twig filter "foo_bar"
- MyApp\Foo
- bar
functions:
- time # register php "time" function as twig "time" function
See also: umpirsky/twig-php-function
Monolog NotFoundActivationStrategy (activation_strategy, excluded_404s and excluded_http_codes options) does not work in Symfony 3.0 as currently monolog-bundle injects a reference to request from the service container into the NotFoundActivationStrategy.
- Other HTTP-codes support
- Configure default actionLevel value via Configuration
main:
type: fingers_crossed
handler: grouped
activation_strategy: symfony_common.monolog.fingers_crossed.ignore_http_not_found_activation_strategy
Add the specified HTTP-header to the prepared BrowserKit request
use Cosmologist\Bundle\SymfonyCommonBundle\BrowserKit\BrowserKitUtils;
/** @var \Symfony\Component\BrowserKit\Client $cient */
BrowserKitUtils::addHeader($client, 'header-name', 'header-value');
Useful when you want to deduplicate application parameters (like db-connections, paths etc) and store related external applications configurations (backup-systems, crontab etc) inside the project.
Configuration for abstract backup-system
Configuration file template:
# app/config/external/dist/backup.yml.twig
backup:
mysql:
{{ name }}
{{ user }}
{{ password }}
compress: yes
sync-to: amazon-s3
Define parameters for dist:
# app/config/config.yml
symfony_common:
external_config:
superbackup:
name: '%doctrine.connection.default.database_name%'
user: '%doctrine.connection.default.database_user%'
password: '%doctrine.connection.default.database_password%'
Run dumper:
php app/console symfony-common:external-config:dump superbackup backup.yml.twig --env=prod --no-debug
And config should be dumped to app/cache/prod/external_config/backup.yml (without .twig extension)