I need defined several PHP constants and i need use this constants in my bundle (controller, custom classes, entities..) Where best place to add this constants, that would be convenient for them to get?
Why not just create a class to store your constants and use the use statement to autoload it where needed?
Define your constants...
namespace My\CoolBundle\Constants;
class ConstantlyCool {
const DEFAULT_COOLNESS_LEVEL = "newbie";
const MAX_COOLNESS_LEVEL = "phpisuber01";
}
Now use them...
namespace My\CoolBundle\Controller;
use My\CoolBundle\Constants\ConstantlyCool;
class CoolController extends Controller {
public function awesomeAction() {
// Do cool stuff
$cool_level = ConstantlyCool::DEFAULT_COOLNESS_LEVEL;
return new Response(/* blah blah */);
}
}
The best solution for my is setting these constants in Bundle Class, like that:
<?php
namespace AppBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
const SITE_NAME = 'Watchdev AR';
}
And use twig functions constant http://twig.sensiolabs.org/doc/functions/constant.html invoke them
In whatever twig file:
{{ constant('AppBundle\\AppBundle::SITE_NAME') }}
I think this solution follow the best practices that Symfony (without entity in this case) http://symfony.com/doc/current/best_practices/configuration.html
class sample
{const TEST_NUM= 10;}
Related
I have installed a particular module in my SilverStripe installation. The following is the directory structure
- Root
- framework
- cms
- mymodule
- code
- extensions
- CustomClass.php
Here is an example of CustomClass.php
class CustomClass extends Extension {
public function init() {
}
public function customMethod() {
}
}
I need to override the customMethod method of the CustomClass class. I could easily change this method, but changing here will cause trouble in the future if the modules get updated. All the changes made will be lost.
So for this I want to extend the extension class used in modules.
I have created an extension /mysite/extensions/MyCustomClass.php
class MyCustomClass extends Extension {
public function customMethod() {
//do my code here
}
}
but I have no idea how to apply this. I thought CustomClass::add_extension("MyCustomClass ") but surely this will not work because add_extension method doesn't exist in CustomClass.
How do we cope with this scenario? Can I use Injector instead? If yes, how can it be called in mysite/_config.php instead of _config.yml?
Using injector does solve the problem but have to use _config.yml as well. Here is what I did.
File /mysite/extensions/MyCustomClass.php
class MyCustomClass extends CustomClass {
public function customMethod() {
//do my code here
}
}
in /mysite/_config/config.yml I added following lines
Injector:
CustomClass:
class: MyCustomClass
And in /mysite/_config.php I added following line
$object = Injector::inst()->create('CustomClass');
And it all worked fine.
There is another way to achieve similar functionality without straight up replacing a previous extension. With SilverStripe's extension system, we can control not only what configuration settings are loaded but the order they are loaded. This is important to note because the customMethod function from an extension, it uses the first one it finds from all the extensions loaded.
Because of this, it can be only a matter of controlling when your MyCustomClass extension is loaded so you can have your own customMethod function run.
Let's say the "MyModule" module has the following YAML file defined:
---
Name: MyModuleExtensions
After:
- 'framework/*'
- 'cms/*'
---
Page:
extensions:
- CustomClass
All we need to do is specify a separate YAML file to run before this "MyModule" one. This can be accomplished like:
---
Name: MyCustomModule
Before:
- MyModule/#MyModuleExtensions
---
Page:
extensions:
- MyCustomClass
Now, when you call your customMethod function on whatever class you have your extensions on (so in my example, the Page class), it will call the one from your MyCustomClass extension.
Like on Ruby on Rails, you can return Javascript with some prerendering to dynamically update the client site through AJAX.
How do you return Javascript when calling some routes in Symfony2?
For example, when calling updateItemAppearanceAction through \item\{itemId}\update_appearance, return Javascript file updateItemAppearance.js.twig, with array("item"->$item)?
Thank you very much!
Within the action method called updateItemAppearanceAction:
Create a Rendered view
Instantiate a Response object, passing the rendered view in the Constructor.
Set the Content-Type in the Response Header of the Response Object's instance to text/javascript.
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// example controller.
class DefaultController extends Controller
{
/**
* #Route("/updateItemAppearance.js", name="default_update_item_appearance_js")
*/
public function updateItemAppearanceAction()
{
$optionalParams = array('some'=>'param');
$renderedView = $this->renderView('AppBundle:Default:updateItemAppearance.js.twig'); // 1.
$response = new Response($renderedView, $optionalParams)); // 2.
$response->headers->set('Content-Type','text/javascript'); // 3.
return $response;
}
}
As a result, the javascript you write in updateItemAppearance.js.twig file can be embedded as a javascript file via the usual means.
<script src="/updateItemAppearance.js"></script>
Or using the twig path helper.
<script src="{{ path('default_update_item_appearance_js') }}"></script>
Well if you want to return data for your javascript you could do this in your "updateItemAppearance.js.twig"
var javascriptVar = "{{twigVar|json_encode()|raw('js')}}";
If you're using the JMSSerializer you could do
var javascriptVar = "{{twigVar|serialize('json')|raw('js') }}";
More info: twig docs, jms serializer docs
Q1.I want to count the unread messages before every page rendered ,and add the number into twig template.i don't know how to make it
Q2.i have read the symfony tutorial,it seems that i will make a service ,but i don't know how to do it.is the following code right? and i don't know what to write at the seconde argument
namespace App\RepairBundle\Service;
use Symfony\Component\DependencyInjection\ContainerInterface;
use App\RepairBundle\Entity\RepairMessageRepository;
class CountUnReadMessage
{
protected $container;
protected $messageRepository;
public function __construct(ContainerInterface $container,RepairMessageRepository $messageRepository)
{
$this->container = $container;
$this->messageRepository = $messageRepository;
}
public function countUnRead()
{
$number = $this->messageRepository->countByUnread($this->container->get('security.token_storage')->getToken()->getUser()->getId());
return $number;
}
}
parameters:
app.repair.count_unread_message: App\RepairBundle\Service\CountUnReadMessage
services:
app.repair.count_unread_message:
class: %app.repair.count_unread_message%
arguments:
- #service_container
- #
If piece of the twig template containing message counter similar in all templates, you can move it to separate template and call service inside this template. You steps to achieve this might look like this:
Write service for getting message counter (you almost got it, but try to avoid injecting whole container in servce since it is a very bad practice. In this case, i think you could inject only security.token_storage)
Make this service visible in twig templates by declare it in config file.
config.yml
twig:
globals:
count_read_message: #app.repair.count_unread_message
In your separate twig file call this service
message_block.html.twig
{{ count_read_message.countUnRead() }}
And include this twig file to needed template (better idea would be keep main template for most of templates and include you file in this template, but this dependenced of template structure)
I hope you got the main idea =)
P.S. Answering for Q2 - it is #doctrine.orm.entity_manager
If you want to inject repository make another service with your repository:
app.message_repository:
class: Doctrine\ORM\EntityRepository
factory: ["#doctrine.orm.default_entity_manager", getRepository]
arguments:
- App\RepairBundle\Entity\RepairMessage
Then in your service:
app.repair.count_unread_message:
class: %app.repair.count_unread_message%
arguments:
- #service_container
- #app.message_repository
BTW you don't need container, inject only security.token_storage instead of container.
I'm wondering, where I should place constants, e.g. for mapping a status, in Symfony. I'm used to set them in a controller, but it doesn't feel right and I prefer the entity, but not really.
What's right?
It's not a "what do you think?"-Question, I really want to know the best-practise and appreciate explanation or linked source(s). Both work, for now.
Controller or
namespace my\bundle\Controller;
class MyController {
const STATUS_NEW = 1;
const STATUs_PENDING = 2;
// ...
}
Entity ?
namespace my\bundle\Entity;
class MyEntity {
const STATUS_NEW = 1;
const STATUs_PENDING = 2;
// ...
}
Example in twig:
{% set statusNew = constant('my\\bundle\\Controller\\MyController::STATUS_NEW')%} {# or \\Entity\\ #}
{% if data.status == statusNew %}
Hi, I'm new.
{% endif %}
Thanks in advance!
M.
IMHO the entity itself is a good place. For the twig approach, in my previous project, I create some helper method on the entity for check the status like :
namespace my\bundle\Entity;
class MyEntity {
const STATUS_NEW = 1;
const STATUs_PENDING = 2;
// ...
// For each const status
public function isNew(){
return $this->status == self::STATUS_NEW;
}
}
and use in the twig like:
{% if data.isNew %}{# more contract form: if data.new #}
Hi, I'm new.
{% endif %}
And you don't expose the status field outside the entity (incapsulate the logic of new).
Hope this help.
The answer is it depends, but there are now Symfony best practices; in particular there is a section on constants vs. configuration options that speaks to exactly what you're asking.
Use constants to define configuration options that rarely change.
The nice thing about defining constants in classes is that you can easily access them in Twig. For instance, if you have a Post class like the example in the best practices, and pass an instance of that as post to your template, you can access the constant via:
{{ constant('NUM_ITEMS', post) }}
Now, there are definitely times where you might want to specify configurable options - say if you're creating a reusable bundle and want to allow an override of these values. So again it depends, but for your case, Symfony recommends placing them in your entity.
The STATUS constants belong in the entity so that they can be reused in multiple contexts (multiple controllers, for example) without needing to redefine the constants in each controller.
I'm using Symfony2 to develop a application that is to be translatable. The application has Assetic enabled to minify and combine *.js and *.css files. However, I have a jQuery plugin I wrote, that has literal strings in it. For example, consider the following code:
$('<p>Are you sure you want to proceed?</p>').dialog({
buttons: {
"Yes" : function() {
// ...
},
"No" : function() {
// ...
}
}
});
In the above snippet, "Are you sure...", "Yes" and "No" will always be English, and I can't use Twig templating in the .js file to translate it using something like: {{ "yes"|trans }}
What I want to know is, what would be the best way to use Twig to leverage the built in Symfony2 translation mechanism, to translate the literal strings in my JS scripts.
Is there a way to create for example: myscript.js.twig files?
Is there a way to create for example: myscript.js.twig files?
It seems a bad idea.
You can check https://github.com/willdurand/BazingaExposeTranslationBundle
or create it yourself, for example include this in your template:
<script type="text/javascript">
var translations = {
// ...
'yes' : {{ 'yes' | trans }},
// ...
}
</script>
then if your javascript file is included just before </body> you can use translations variable in it.
Here is my solution (Tested on Symfony 4 and 5):
First, we create a controller that will create JS file with all translations according to the current variable locale:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Yaml\Yaml;
/**
* Translation controller.
*/
class TranslationController extends AbstractController
{
/**
* #Route("/translation.js", name="translation")
*/
public function index(Request $request)
{
$locale = $request->getLocale();
$file = __DIR__.'/../../translations/messages.'.$locale.'.yaml';
$parsed = Yaml::parse(file_get_contents($file));
$translations = $this->renderView(
'translation/translation.js.twig',
array(
'json' => json_encode($parsed)
)
);
return new Response($translations, 200,
array('Content-Type' => 'text/javascript')
);
}
}
Then we create a TWIG template to render (/templates/translation/translation.js.twig):
var trans = JSON.parse('{{ json|raw }}');
We place our dynamic translation file in the template before other assets:
<script src="{{ path('translation') }}"></script>
For sample translation file /translations/messages.pl.yaml:
projects: Projekty
medium: Średnio
month:
january: Styczeń
february: Luty
We can display our translation in any JS file:
console.log(trans['month']['january']);
console.log(trans['medium']);
I hope it will be useful to someone
I was searching something to make twig.js work with translations which seems to me like the best solution. Still searching though.
In the meantime, I'm using this jsgettext which is a gettext implementation in Javascript, by Joshua I. Miller. I've uploaded back to github since the original repo is down.
<script language="javascript" src="/path/LC_MESSAGES/myDomain.json"></script>
<script language="javascript" src="/path/Gettext.js"></script>
You load your translation files into your DOM and jsgettext can parse it:
function _(msgid) { return gt.gettext(msgid); }
alert(_("some string"));
To get the path of your translation files from Symfony, you'll have to make some php/twig extension around the Translator service but it works great without duplicating your translation resources.