I have this situation:
unit:
sqkm: Square Kilometers
my_translation: Size is %size% ## I want to append the value of unit.sqkm here ##
Is there a way to reference the translation of the unit.sqkm inside the my_translation key?
Edit: Please note that i do know how i can do this via twig. My question is: is there a way to do this in the translation files.
I extended Symfony Tanslator for this:
<?php
namespace Bundle\Program\Translation;
use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator;
class Translator extends BaseTranslator
{
/**
* Uses Symfony Translator to translate, but enables referencing other translations via ##code##
*/
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
{
$text = parent::trans($id, $parameters, $domain, $locale);
$translations = [];
$delimiter = "##";
$strLen = strlen($delimiter);
$pos = strpos($text, $delimiter);
while ($pos !== false) {
$startsAt = $pos + $strLen;
$endsAt = strpos($text, $delimiter, $startsAt);
$translations[] = $delimiter . substr($text, $startsAt, $endsAt - $startsAt) . $delimiter;
$pos = strpos($text, $delimiter, $endsAt + $strLen);
}
foreach ($translations as $translation) {
$translationTrim = str_replace($delimiter, '', $translation);
$text = str_replace($translation, $this->trans($translationTrim, $parameters, $domain, $locale), $text);
}
return $text;
}
}
Then replace the Symfony translator class via parameters:
parameters:
translator.class: Bundle\Program\Translation\Translator
Now you can reference other translations via ##other.translation## INSIDE your yml file.
In your Twig template, try this :
{{ 'my_translation' | trans({'%size%': size, 'unit.sqkm' : ('unit.sqkm'|trans)}) }}
You can use translated values inside other translations.
{{ 'paragraph' | trans({ '%size%': 3, '%unit%': 'unit' | trans()}) }}
Where unit itself is another key for a translation. Your translation file however could look like this:
paragraph: Size is %size% %unit%
unit: Square Kilometers
If, like me, you want to achieve this in Symfony 4.1, here's your solution
(many thanks to #Kim's answer and #Aurelijus Rozenas's answer, all credits -apart my 4 hours trying that- go to them)
First, create your new Translator class (here: src/Common/ReferenceTranslator.php)
I can't manage to find a solution where I would extend the base translator class straight in the class code, let me know if you have one
# src/Common/ReferenceTranslator.php
namespace App\Common;
use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Component\Translation\TranslatorInterface;
class ReferenceTranslator implements TranslatorInterface, TranslatorBagInterface
{
/** #var TranslatorBagInterface|TranslatorInterface */
protected $translator;
/**
* #param TranslatorInterface|TranslatorBagInterface $translator
*/
public function __construct($translator)
{
$this->translator = $translator;
}
/**
* Uses Symfony Translator to translate, but enables referencing other translations via ##code##
* #param $id
* #param array $parameters
* #param null $domain
* #param null $locale
* #return mixed|string
*/
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
{
$text = $this->translator->trans($id, $parameters, $domain, $locale);
$translations = [];
$delimiter = "##";
$strLen = strlen($delimiter);
$pos = strpos($text, $delimiter);
while ($pos !== false) {
$startsAt = $pos + $strLen;
$endsAt = strpos($text, $delimiter, $startsAt);
$translations[] = $delimiter . substr($text, $startsAt, $endsAt - $startsAt) . $delimiter;
$pos = strpos($text, $delimiter, $endsAt + $strLen);
}
foreach ($translations as $translation) {
$translationTrim = str_replace($delimiter, '', $translation);
$text = str_replace($translation, $this->trans($translationTrim, $parameters, $domain, $locale), $text);
}
return $text;
}
/**
* #param string $id
* #param int $number
* #param array $parameters
* #param null $domain
* #param null $locale
*
* #return string
*/
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
{
return $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
}
/**
* #param string $locale
*/
public function setLocale($locale)
{
$this->translator->setLocale($locale);
}
/**
* #return string
*/
public function getLocale()
{
return $this->translator->getLocale();
}
/**
* #param string|null $locale
*
* #return \Symfony\Component\Translation\MessageCatalogueInterface
*/
public function getCatalogue($locale = null)
{
return $this->translator->getCatalogue($locale);
}
}
And then edit your services.yaml file
# app/config/services.yml
#[...]
services:
#[...]
# Custom Translator (References)
# Overrides the Translator Service (is still available as #app.decorating_translator.inner)
app.decorating_translator:
class: App\Common\ReferenceTranslator
decorates: translator
arguments:
- '#app.decorating_translator.inner'
public: false
And voilĂ !
Again, don't hesitate if you know how to improve this, as I'm not a Symfony expert !
The TBG answer works,
for Symfony 4.4 here is the code in service.yaml
Services
App\Common\ReferenceTranslator:
arguments:
$translator: '#translator'
And dont forget to implement LocaleAwareInterface too !
Related
I'm trying to clean up some code done in a messy way and right now I'm having trouble with doctrine's paginator.
When I'm accessing a page that handle paginator in order to show all different articles of my blog I'm getting this error:
Neither the property "id" nor one of the methods "id()", "getid()"/"isid()"/"hasid()" or "__call()" exist and have public access in class "Doctrine\ORM\Tools\Pagination\Paginator".
In doctrine vendor bundle those methods are not set but my entity have them and I know that it is forbidden to edit a vendor file. I'm missing something because I don't know if I should extend my paginator entity and add those missing methods or is there a little bit more to do ?
I just started symfony and I know that my bases are not enough to understand it all by myself.
Thank you very much for you time and attention.
Here is my Article controller for route category:
/**
* #Route("/categorie/{id}", name="categorie")
*
* #param Request $request
* #param Helper $helper
* #param AuthorizationCheckerInterface $authChecker
* #param DocumentCategory $categorie
* #param TwitterService $twitterService
*
* #return RedirectResponse|Response
*/
public function categorie(
Request $request,
Helper $helper,
AuthorizationCheckerInterface $authChecker,
DocumentCategory $categorie,
TwitterService $twitterService
) {
if (!$authChecker->isGranted('IS_AUTHENTICATED_FULLY')
&& !$authChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirectToRoute('login');
}
$page = (int) ($request->get('page'));
if (0 === $page) {
$page = 1;
}
$userType = $this->getDoctrine()->getRepository('App:User')
->getManagerExpertCollabo($this->getUser());
$articleAlaUneListe = [];
$articleIdListe = $helper->getArticleIdAuth($authChecker);
$articleListe = $this->getDoctrine()
->getRepository('App:Document')
->getPage(
self::ITEM_PER_PAGE * ($page - 1),
self::ITEM_PER_PAGE,
'document.dateCreated',
'DESC',
'(documentCategory.id = \''.$categorie->getId().'\' and '.$helper->baseRequestArticle().')',
7,
[],
$articleIdListe
);
[$articlePopulaireListe, $categorieListe, $totalPage] = $this->getPopularArticleList(
$articleListe,
$helper,
$articleIdListe
);
$articlesList->getDocuments();
$feedData = $twitterService->getTwitterFeed();
return $this->render('article/list.html.twig', [
'pageClass' => 'backoffice withFooterLarge dashboard',
'totalPage' => $totalPage,
'page' => $page,
'feedData' => $feedData,
'categorieListe' => $categorieListe,
'categorie' => $categorie,
'articleAlaUneListe' => $articleAlaUneListe,
'articlePopulaireListe' => $articlePopulaireListe,
'articleListe' => $articleListe, ]);
}
Here is the document entity for categories field:
/**
* #ORM\JoinTable(name="ht_lk_document_category"),
* #ORM\ManyToMany(targetEntity="App\Entity\DocumentCategory", inversedBy="documents")
*/
private $categories;
/**
* #return Collection|array<DocumentCategory>
*/
public function getCategories(): Collection
{
return $this->categories;
}
public function setCategories($category): self
{
$this->categories = $category;
return $this;
}
Here is the DocumentCategory entity :
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Document", mappedBy="categories")
*/
private $documents;
/**
* #return Collection|Document[]
*/
public function getDocuments(): Collection
{
return $this->documents;
}
Here is the Document Repository :
public function getPage($first_result, $max_results, $orderby, $direction, $criteria, $documentType = null, $searchWordArray = [], $articleIdListe = '')
{
$qb = $this->createQueryBuilder('docArticle');
$qb->select('docArticle')
->addSelect('documentCategory', 'documentCategory')
->addSelect('user', 'user')
/*
if(sizeof($searchWordArray) > 0){
$fieldIndice = 1;
foreach($searchWordArray as $searchWord){
$qb->andWhere('(document.name_fr LIKE ?'.$fieldIndice.' or document.name_en LIKE ?'.$fieldIndice.' or document.content_fr LIKE ?'.$fieldIndice.' or document.content_en LIKE ?'.$fieldIndice.')');
$qb->setParameter($fieldIndice++, '%'.$searchWord.'%');
}
} */
->leftJoin('docArticle.categories', 'documentCategory')
->leftJoin('docArticle.author', 'user')
->setFirstResult($first_result)
->setMaxResults($max_results);
if (!empty($criteria)) {
$qb->where('('.$criteria.')');
}
if (!empty($orderby)) {
$qb->orderBy($orderby, $direction);
}
$pag = new Paginator($qb->getQuery());
$qb->setFirstResult(0);
$qb->setMaxResults(PHP_INT_MAX);
$sql = $qb->getQuery()->getSql();
if ('()' !== $articleIdListe) {
$qb->where('(docArticle.id IN '.$articleIdListe);
}
$compte = \count($qb->getQuery()->getScalarResult());
return ['page' => $pag, 'compte' => $compte];
}
And finally here is the Document Category Repository :
/**
* #param $first_result
* #param $max_results
* #param $orderby
* #param $direction
* #param $criteria
* #param int|null $documentType
* #param array $searchWordArray
* #param string $articleIdListe
*
* #return array
*/
public function getPage(
$first_result,
$max_results,
$orderby,
$direction,
$criteria,
$documentType = null,
$searchWordArray = [],
$articleIdListe = ''
) {
$qb = $this->createQueryBuilder('document');
$qb->select('document')
->addSelect('documentCategory', 'documentCategory')
->addSelect('user', 'user')
->addSelect('documentType', 'documentType');
if (\count($searchWordArray) > 0) {
$fieldIndice = 1;
foreach ($searchWordArray as $searchWord) {
$qb->andWhere(
'('
.'document.name_fr LIKE ?'.$fieldIndice
.' or document.name_en LIKE ?'.$fieldIndice
.' or document.content_fr LIKE ?'.$fieldIndice
.' or document.content_en LIKE ?'.$fieldIndice
.')'
);
$qb->setParameter($fieldIndice++, '%'.$searchWord.'%');
}
}
if ($documentType) {
if (\mb_strlen($articleIdListe) > 3) {
$qb->andWhere('(documentType.id = :documentType OR document.id IN '.$articleIdListe.')')
->setParameter('documentType', $documentType);
} else {
$qb->andWhere('(documentType.id = :documentType)')
->setParameter('documentType', $documentType);
}
}
$qb->leftJoin('document.categories', 'documentCategory')
->leftJoin('document.documentType', 'documentType')
->leftJoin('document.author', 'user')
->setFirstResult($first_result)
->setMaxResults($max_results)
->andWhere('document.documentType<>6');
if (!empty($criteria)) {
$qb->andWhere('('.$criteria.')');
}
if (!empty($orderby)) {
$qb->orderBy($orderby, $direction);
}
$sql = $qb->getQuery()->getSql();
$pag = new Paginator($qb->getQuery());
dump($pag);
$qb->setFirstResult(0);
$qb->setMaxResults(PHP_INT_MAX);
$sql = $qb->getQuery()->getSql();
$compte = \count($qb->getQuery()->getScalarResult());
return ['page' => $pag, 'compte' => $compte];
}
/**
* #param int|null $documentType
*
* #return array
*/
public function getArticleIdList($documentType = null)
{
$qb = $this->createQueryBuilder('document');
$qb->select('document.id');
if ($documentType) {
$qb->where('(document.documentType = :documentType)')
->setParameter('documentType', $documentType);
}
$compte = $qb->getQuery()->getScalarResult();
return $compte;
}
(I deleted all unnecessary method for this question)
Add the following code to the entity class from which you want to show data:
public function getId(): ?string
{
return $this->id;
}
Or
if you do not want the property "id" to be displayed in the view, comment out or delete the lines of code in your Twig template for the entity in question. For example, delete
<td>{{ Category.id }}</td>
It just my thought i just want to do like the same, I haven't try this because of i haven't any idea about this means how it will be done.
For Example:
I have - mysite.com/view?user_id=12 , I don't want to show url's parameters (?user_id=12) on url, On the place of this, I want to show like
mysite.com/view?_signature=encryptedparameter
(like : mysite.com/view?_signature=853ef7a0ff5aea6f24152b1d1ed4d771)
853ef7a0ff5aea6f24152b1d1ed4d771 will denotes user_id=12.
If i have multiple parameters it would be like the same and i will have a single encrypted string and i will get all parameters with that string.
Yes but i am using in Laravel 5.1
assume if i have "mysite.com/view?user_id=12"
And i want "mysite.com/view?_signature=encryptedparameter"
Please fallow some steps
laravel>packages>myfolder>core
+=>folder
-=>file
+packages
+Folder
+core
+src
+Faundation
-Application.php
+Routing
-RoutingServiceProvider.php
-UriGenerator.php
+Support
+Middleware
-UrlParamRevealerMiddleware.php
+ServiceProvider
-CoreServiceProvider.php
-UriParamProtector.php
<<IN APPLICATION.PHP>>
<?php
namespace Folder\Core\Foundation;
use Illuminate\Events\EventServiceProvider;
use Folder\Core\Routing\RoutingServiceProvider;
use Illuminate\Foundation\Application as BaseApplication;
use Folder\Core\Support\ServiceProvider\CoreServiceProvider;
class Application extends BaseApplication
{
/**
* Register all of the base service providers.
*
* #return void
*/
protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new CoreServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
}
<<//IN APPLICATION.PHP>>
<<-RoutingServiceProvider>>
<?php
namespace Folder\Core\Routing;
use Folder\Core\Routing\UrlGenerator;
use Illuminate\Routing\RoutingServiceProvider as BaseServiceProvider;
class RoutingServiceProvider extends BaseServiceProvider
{
/**
* Register the URL generator service.
*
* #return void
*/
protected function registerUrlGenerator()
{
$this->app['url'] = $this->app->share(function ($app) {
$routes = $app['router']->getRoutes();
// The URL generator needs the route collection that exists on the router.
// Keep in mind this is an object, so we're passing by references here
// and all the registered routes will be available to the generator.
$app->instance('routes', $routes);
$url = $this->getUrlGenerator($routes);
$url->setSessionResolver(function () {
return $this->app['session'];
});
// If the route collection is "rebound", for example, when the routes stay
// cached for the application, we will need to rebind the routes on the
// URL generator instance so it has the latest version of the routes.
$app->rebinding('routes', function ($app, $routes) {
$app['url']->setRoutes($routes);
});
return $url;
});
}
/**
* Get the url generator instance.
*
* #param \Illuminate\Routing\RouteCollection $routes
* #return \Folder\Core\Routing\UrlGenerator
*/
protected function getUrlGenerator($routes)
{
$url = new UrlGenerator(
$routes,
$this->app->rebinding(
'request',
$this->requestRebinder()
)
);
return $url;
}
}
<</-RoutingServiceProvider>>
<<UriGenerator.php>>
<?php
namespace Folder\Core\Routing;
use ErrorException;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\UrlGenerator as BaseUrlGenerator;
class UrlGenerator extends BaseUrlGenerator
{
/**
* Get the URL to a named route.
*
* #param string $name
* #param mixed $parameters
* #param bool $absolute
* #return string
*
* #throws \InvalidArgumentException
*/
public function route($name, $parameters = [], $absolute = true)
{
$encryptedParameters = $parameters;
if (Auth::guest() === false) {
$encryptedParameters = $this->encrypt($name, $parameters);
}
return parent::route($name, $encryptedParameters, $absolute);
}
/**
* Get the cryptic engine.
*
* #return \Folder\Core\Support\UrlParamEncrypter
*
* #throws \ErrorException
*/
protected function getCrypt()
{
$app = App::getInstance();
if (isset($app['urlencryptor'])) {
return $app['urlencryptor'];
}
throw new ErrorException('URL Encryptor was not found.');
}
/**
* Get the protector engine.
*
* #return #return \Folder\Core\Support\UrlParamProtector
*
* #throws \ErrorException
*/
protected function getProtector()
{
$app = App::getInstance();
if (isset($app['urlprotector'])) {
return $app['urlprotector'];
}
throw new ErrorException('URL Protector was not found.');
}
/**
* Encrypts the parameter passed as querystring in URL.
*
* #param array $parameters
* #return array
*/
protected function encrypt($routeName, $parameters = [])
{
if (! is_array($parameters)) {
return $parameters;
}
if (count($parameters) === 0) {
return [];
}
if (Auth::guest() === true) {
return $parameters;
}
$protected = $this->getProtector()->protect($routeName, $parameters);
return ['__signature' => $protected];
}
}
<<//UriGenerator.php>>
<<UrlParamRevealerMiddleware.php>>
<?php
namespace Folder\Core\Support\Middleware;
use Closure;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Folder\Core\Support\UrlParamProtector;
class UrlParamRevealerMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
(! Auth::guest()) && App::make(UrlParamProtector::class)->reveal($request);
return $next($request);
}
}
<<//UrlParamRevealerMiddleware.php>>
<<CoreServiceProvider.php>>
<?php
namespace Folder\Core\Support\ServiceProvider;
use Illuminate\Support\ServiceProvider;
use Folder\Core\Support\UrlParamProtector;
class CoreServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$this->app->make('Illuminate\Contracts\Http\Kernel')
->pushMiddleware('Folder\Core\Support\Middleware\UrlParamRevealerMiddleware');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->registerUrlProtector();
}
/**
* Register UrlProtector class.
*/
protected function registerUrlProtector()
{
$this->app->singleton('urlprotector', function () {
return new UrlParamProtector();
});
}
}
<<//CoreServiceProvider.php>>
<<-UriParamProtector.php>>
<?php
namespace Folder\Core\Support;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
class UrlParamProtector
{
/**
* Session key.
*
* #var string
*/
protected $sessionKey = '__url_protector__';
/**
* Request class.
*
* #var \Illuminate\Http\Request
*/
protected $request;
/**
* Values those needs to be merged in request object.
*
* #var array
*/
protected $valuesToBeMerged;
/**
* Create and returns VALID RFC 4211 COMPLIANT
* Universally Unique IDentifiers (UUID) version 4.
*
* #return string
*/
protected function getNewGuid()
{
if (function_exists('com_create_guid') === true) {
return trim(com_create_guid(), '{}');
}
return sprintf(
'%04X%04X-%04X-%04X-%04X-%04X%04X%04X',
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(16384, 20479),
mt_rand(32768, 49151),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535)
);
}
/**
* Create the route key.
*
* #param string $routeName
* #param array $parameters
* #return string
*/
protected function getRouteKey($routeName, array $parameters = [])
{
if (count($parameters) <= 0) {
$paramToString = '';
} else {
$paramToString = implode('-', array_map(
function ($k, $v) {
return $k . '-' . $v;
},
array_keys($parameters),
array_values($parameters)
));
}
$routeKey = 'route__' . $routeName . (empty($paramToString) ? '' : '-' . $paramToString);
return $routeKey;
}
/**
* Returns a GUID for a URL parameter.
*
* #param string $routeName
* #param array $parameters
* #return string
*/
public function protect($routeName, array $parameters)
{
$routeKey = $this->getRouteKey($routeName, $parameters);
if (Session::has($this->sessionKey . '.' . $routeKey) === false) {
$guid = Str::lower($this->getNewGuid());
Session::set($this->sessionKey . '.' . $routeKey, [
'guid' => $guid,
'loggedin_user_id' => (Auth::guest() ? 0 : Auth::user()->id),
'params' => $parameters,
]);
} else {
$guid = Session::get($this->sessionKey . '.' . $routeKey . '.guid');
}
return $guid;
}
/**
* Check whether guid passed is a valid one or not.
*
* #param string $guid
* #return boolean
*/
protected function isValidGuid($guid)
{
foreach (Session::get($this->sessionKey) as $key => $value) {
if (!isset($value['guid'])) {
list($innerKey, $val) = each($value);
} else {
$val = $value;
}
if ($val['guid'] === $guid) {
$this->valuesToBeMerged = $val['params'];
return true;
}
}
return false;
}
/**
* Check whether guid passed is a valid one or not.
*
* #param string $guid
* #return boolean
*/
public function isValidGuidForPost($guid)
{
foreach (Session::get($this->sessionKey) as $key => $value) {
if ($value['guid'] === $guid && Auth::user()->id === $value['loggedin_user_id']) {
$this->valuesToBeMerged = $value['params'];
return true;
}
}
return false;
}
/**
* Merge the request with our revealed values.
*/
protected function mergeRequest()
{
$this->request->merge($this->valuesToBeMerged);
}
/**
* Check whether a "__signature" is correct or not.
*
* #param \Illuminate\Http\Request $request
* #return boolean
*/
public function reveal(Request &$request)
{
$this->request = $request;
$guid = ($this->request->query('__signature') ? : false);
if ($guid === false) {
return false;
}
if ($this->isValidGuid($guid) === false) {
App::abort(400);
}
$this->mergeRequest();
}
}
<<//-UriParamProtector.php>>
==============================================
after that in "bootstrap>App.php"
use this=>
$app = new Folder\Core\Foundation\Application(
realpath(__DIR__.'/../')
);
instad of =>
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
in any link use "data-href"
<a data-href="route('modify_lead_status',['user_id' => $users->id])" href="javascript:void(0)"><i class=\"fa fa-random\"></i></a>"
and after that any controller,Routing,middleware will be same.....
>>composer auto-dump
<<Please check spealing be sure use same>>
i hope this is help full....thanks
I know its against the framework to make an entity container aware, but this is a special case, i have a credit card entity, and i want to do this:
/**
* #return mixed
*/
public function getNumber()
{
$number = $this->number;
$crypt = base64_decode($number);
$number = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $crypt, MCRYPT_MODE_ECB);
return trim($number);
}
/**
* #param $number
* #return $this
*/
public function setNumber($number)
{
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $number, MCRYPT_MODE_ECB);
$number = trim(base64_encode($crypt));
$this->number = $number;
return $this;
}
And i want the $key to be the secret from parameters.yml, since i dont want to save it in the code.
I can't pass it as a parameter, when i use the FormType, cause the form type will not pass it when it binds the request.
$credit_card = new CreditCard();
$credit_card->setCustomer($customer);
$payment_form = $this->createPaymentForm($credit_card);
$payment_form->handleRequest($request);
Remove data modifications from your Entity, and add it to your FormType.
public function getNumber()
{
return $this->number;
}
public function setNumber($number)
{
$this->number = $number;
return $this;
}
Make your FormType take the parameter as argument.
class CreditCardType extends AbstractType {
private $key;
public function __construct($key) {
$this->key = $key;
}
// ...
// Listen on the PRE_BIND event to update your value before binding
$builder->addEventListener(FormEvents::PRE_BIND, function (FormEvent $event)
{
$data = $event->getData();
$number = $data['number'];
$crypt = $this->encryptNumber($number);
$data['number'] = $crypt;
$event->setData($data);
});
public function encryptNumber($key, $number)
{
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $number, MCRYPT_MODE_ECB);
$number = trim(base64_encode($crypt));
return $number;
}
}
Now, in your createPaymentForm, add the parameter to your FormType instance, like this :
$param = $this->container->getParameter('yourkeyparam');
$form = $this->createForm(new CreditCardType($param), $credit_card, array());
Hope this is what you need.
I'm building a multi-tenant application. In Symfony1 I would restrict access to data by accessing the user details and extending the createQuery function:
class PersonTable extends Doctrine_Table{
public function createQuery($alias = '')
{
$query = parent::createQuery($alias);
try {
$user = sfContext::getInstance()->getUser();
}catch(Exception $e){
if ($e->getMessage() == 'The "default" context does not exist.'){
return $query;
}else{
throw $e;
}
}
if ($user->hasGroup('Team1')){
//all good
}else if ($user->hasGroup('Team2')){
$user_id = $user->getGuardUser()->getStaff()->getId();
$alias = $query->getRootAlias();
$time = date('Y-m-d H:i:s',time());
$query->andWhere("$alias.type='type1' and pe.assigned_psw_id");
}
$query->orderBy('name asc');
return $query;
}
}
I know there are downsides to accessing the user object through sfContext in sf1, but this method seemed superior to others, as you can't "forget" to secure a controller against wrong user access.
How can I achieve the same in Symfony2?
I have solved this problem the following way.
Standardise how EntityRepository is fetched among controllers:
public function getUserRestrictedRepository($entity, $em = null )
{
$securityContext = $this->get( 'security.context' );
if (!$em){
$em = $this->getDoctrine()->getManager();
}
return $em
->getRepository( 'MyBundle:' . $entity )
->setSecurityContext( $securityContext );
}
Add a trait to provide queries with injected security query:
trait UserRestrictedEntityRepository {
private $securityContext;
/**
* #return mixed
*/
public function getSecurityContext()
{
return $this->securityContext;
}
/**
* #param mixed $securityContext
*/
public function setSecurityContext($securityContext)
{
$this->securityContext = $securityContext;
return $this;
}
/**
* #return mixed
*/
public function getUser()
{
return $this->getSecurityContext()->getToken()->getUser();
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
function secureQueryWithUser($alias, $qb)
{
$qb->where("1=0");
}
function appendOrderBy($qb, $orderBy)
{
$first = true;
foreach ($orderBy as $field => $dir) {
if (!$dir) $dir = 'asc';
if ($first) {
$qb->orderBy('c.' . $field, $dir);
$first = false;
}else{
$qb->addOrderBy('c.' . $field, $dir);
}
}
}
public function createUnrestrictedQueryBuilder($alias)
{
return parent::createQueryBuilder($alias);
}
/**
* Creates a new QueryBuilder instance that is prepopulated for this entity name.
*
* #param string $alias
*
* #return QueryBuilder
*/
public function createQueryBuilder($alias, $indexBy=NULL)
{
if ($this->getUser()) {
$qb = $this->_em->createQueryBuilder()
->select($alias)
->from($this->_entityName, $alias);
if (isset($this->defaultOrder) && $this->defaultOrder){
$this->appendOrderBy($qb, $this->defaultOrder);
}
if ($this->getUser()->isSuperAdmin()){
return $qb;
}else{
return $this->secureQueryWithUser($alias, $qb);
}
}else{
throw new Exception('Run setUser() before querying ' . $this->getName() .' model.');
}
}
/**
* Finds all entities in the repository.
*
* #return array The entities.
*/
public function findAll()
{
return $this->findBy(array());
}
/**
* Finds entities by a set of criteria.
*
* #param array $criteria
* #param array|null $orderBy
* #param int|null $limit
* #param int|null $offset
*
* #return array The objects.
*/
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
{
$qb = $this->createQueryBuilder('c');
foreach ($criteria as $fkey => $fval){
$qb->andWhere($fkey.' = :'.$fval);
}
if ($limit){
$qb->setMaxResults($limit);
}
if ($offset){
$qb->setFirstResult($offset);
}
$query = $qb->getQuery();
return $query->getResult();
}
}
Implement query additions based on user access in the EnityRepository
class FarmerRepository extends EntityRepository
{
use UserRestrictedEntityRepository;
private $name = 'Farmer';
private $defaultOrder = array('name' => 'asc');
function secureQueryWithUser($alias, $qb)
{
if ($this->getSecurityContext()->isGranted( 'ROLE_CLINIC_ADMIN' )) {
return $qb
->innerJoin("$alias.vet", 'v')
->innerJoin("v.clinic", "cl")
->innerJoin("cl.VetsOfClinic", "vc")
->andWhere('vc.user_id= :userid')
->setParameter('userid', $this->getUser()->getId());
}else if ($this->getSecurityContext()->isGranted( 'ROLE_VET' )){
return $qb
->innerJoin("$alias.vet", 'v')
->andWhere('v.user_id= :userid')
->setParameter('userid', $this->getUser()->getId());
}else{
return $qb
->where("$alias.user_id= :userid")
->setParameter('userid', $this->getUser()->getId());
}
}
}
Anyone know which option is needed to compress all css in one line. I am using a wordpress plugin called bwp-minify, however the plugin's css level of compression is low and i am trying to change it through the YUICompressor.php
I tried changing line-break to 0 and to 100000 but none have effect.
Is it the following;
--line-break
Some source control tools don't like files containing lines longer than,
say 8000 characters. The linebreak option is used in that case to split
long lines after a specific column. It can also be used to make the code
more readable, easier to debug (especially with the MS Script Debugger)
Specify 0 to get a line break after each semi-colon in JavaScript, and
after each rule in CSS.
Source Code:
<?php
/**
* Class Minify_YUICompressor
* #package Minify
*/
/**
* Compress Javascript/CSS using the YUI Compressor
*
* You must set $jarFile and $tempDir before calling the minify functions.
* Also, depending on your shell's environment, you may need to specify
* the full path to java in $javaExecutable or use putenv() to setup the
* Java environment.
*
* <code>
* Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.3.5.jar';
* Minify_YUICompressor::$tempDir = '/tmp';
* $code = Minify_YUICompressor::minifyJs(
* $code
* ,array('nomunge' => true, 'line-break' => 1000)
* );
* </code>
*
* #todo unit tests, $options docs
*
* #package Minify
* #author Stephen Clay <steve#mrclay.org>
*/
class Minify_YUICompressor {
/**
* Filepath of the YUI Compressor jar file. This must be set before
* calling minifyJs() or minifyCss().
*
* #var string
*/
public static $jarFile = null;
/**
* Writable temp directory. This must be set before calling minifyJs()
* or minifyCss().
*
* #var string
*/
public static $tempDir = null;
/**
* Filepath of "java" executable (may be needed if not in shell's PATH)
*
* #var string
*/
public static $javaExecutable = 'java';
/**
* Minify a Javascript string
*
* #param string $js
*
* #param array $options (verbose is ignored)
*
* #see http://www.julienlecomte.net/yuicompressor/README
*
* #return string
*/
public static function minifyJs($js, $options = array())
{
return self::_minify('js', $js, $options);
}
/**
* Minify a CSS string
*
* #param string $css
*
* #param array $options (verbose is ignored)
*
* #see http://www.julienlecomte.net/yuicompressor/README
*
* #return string
*/
public static function minifyCss($css, $options = array())
{
return self::_minify('css', $css, $options);
}
private static function _minify($type, $content, $options)
{
self::_prepare();
if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) {
throw new Exception('Minify_YUICompressor : could not create temp file.');
}
file_put_contents($tmpFile, $content);
exec(self::_getCmd($options, $type, $tmpFile), $output);
unlink($tmpFile);
return implode("\n", $output);
}
private static function _getCmd($userOptions, $type, $tmpFile)
{
$o = array_merge(
array(
'charset' => ''
,'line-break' => 5000
,'type' => $type
,'nomunge' => false
,'preserve-semi' => false
,'disable-optimizations' => false
)
,$userOptions
);
$cmd = self::$javaExecutable . ' -jar ' . escapeshellarg(self::$jarFile)
. " --type {$type}"
. (preg_match('/^[a-zA-Z0-9\\-]+$/', $o['charset'])
? " --charset {$o['charset']}"
: '')
. (is_numeric($o['line-break']) && $o['line-break'] >= 0
? ' --line-break ' . (int)$o['line-break']
: '');
if ($type === 'js') {
foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) {
$cmd .= $o[$opt]
? " --{$opt}"
: '';
}
}
return $cmd . ' ' . escapeshellarg($tmpFile);
}
private static function _prepare()
{
if (! is_file(self::$jarFile)) {
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
}
if (! is_dir(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
}
if (! is_writable(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.');
}
}
}
Have you tried not using the --line-break option?
When I use YUI compressor I don't specify that option and the output is on a single line.
Judging from the source code you provided wherever you call
Minify_YUICompressor::minifyCss('/path/to.css');
You need to set the line-break option to -1 like this:
Minify_YUICompressor::minifyCss('/path/to.css', array('line-break' => -1));
put the following code at the beginning of you php script
<?php header('Content-Type:application/javascript'); ?>