Symfony2 Sluggable multiple separators - symfony

Using the Gedmo Sluggable behavior in Symfony2, I need to know if there is a way to allow both slashes (/) and dashes (-) as word separators. In other words, one specific separator as usual, but leaving alone the other specific special character so it is ignored. I want to do something like this as a slug:
products/some-product
This allows me to use slugs in the URL that are categorized via the slash and separate the spaces via the dash. But, for instance, if the separator is "/", the "-" will be replaced as well instead of left alone.
I've looked through the related Sluggable class code (Urlizer) and see a lot of regex going on, but I'm not sure where I should override to allow slashed and/or dashes to NOT be substituted along with everything else.

Turns out you can accomplish this by creating your own class that extends Urlizer, then setting it as the callable for the listener instead of Gedmo's class.
When using STOF doctrine extensions, a sluggable listener is created as a service, but it is set as private so you can't normally access. So you must first create an alias to this listener in your own config:
services:
sluggable.listener:
alias: stof_doctrine_extensions.listener.sluggable
You must then create your class. There is a setter called setTransliterator() that you can use to call your own transliterator, which you can then use to inject what you need to modify the slugging process. The function postProccessText() is what you really want to modify, the transliterate() function is just what is callable:
namespace My\Bundle\Util;
use Gedmo\Sluggable\Util\Urlizer as BaseUrlizer;
class Urlizer extends BaseUrlizer
{
public static function transliterate($text, $separator = '-')
{
// copy the code from the parent here
}
private static function postProcessText($text, $separator)
{
// copy code from parent, but modify the following part:
$text = strtolower(preg_replace('/[^A-Z^a-z^0-9^\/]+/', $separator,
preg_replace('/([a-z\d])([A-Z])/', '\1_\2',
preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2',
preg_replace('/::/', '/', $text)))));
}
}
The regular expressions of postProcessText() are what you want to modify to your liking. After that, you must make your function the callable right before you persist, and you're good to go:
// custom transliterator
$listener = $this->get('sluggable.listener');
$listener->setTransliterator(array('My\Bundle\Util\Urlizer', 'transliterate'));
$em->flush();

Related

ZF2 Translation inside autoload dictionaries

I've got a ZF2 project with basic/skeleton structure. I've got /var/www/project/module/Application/language with a languages and
/var/www/project/config/autoload/dictionaries.php which contain month names and so on.
I need to translate values of dictionary to desired language. I have tried to make it the same way as I did inside View /var/www/project/module/Application/view/application/module-name/×××.phtml:
$this->plugin('translate')->getTranslator()->setLocale('en_US');
$this->translate("foreign language staff");
But $this have no idea what I'm talking about. Then I try the way I try it inside Controllers /var/www/project/module/Application/src/Application/Controller/ModuleController.php:
use Zend\I18n\Translator\Translator;
class CompanyController extends AbstractActionController {
public function indexAction() {
$translator = new \Zend\I18n\Translator\Translator;
define('LOCALE', substr($translator->getLocale(),0,5));
$translator->setLocale(LOCALE);
$translator->addTranslationFile('gettext', '/....../language/' . LOCALE . '.mo', 'messages', LOCALE);
$translator->translate("foreign language staff"),
But no in the dictionary neither in Controller I can not get translate, even addTranslationFile file path and LOCALE is correctly settled.

How to render a view from service class in symfony?

I'm trying to make a function in my service class, that render a twig page. I've tried to do like this:
service.yml:
********
parameters:
error.class: AppBundle\Utils\Error
services:
app.error:
class: '%error.class%'
arguments: [#templating]
Error.php (service class):
****
class Error
{
public function __construct($templating)
{
$this->templating = $templating;
}
public function redirectToError($condition,$message)
{
if($condition){
return $this->templating->render('default/error.html.twig',array(
'error_message' => $message,
));
}
}
}
and error.html.twig that have some random text to see if it gets there.
After that I get this answer from browser:
Can somebody to tell me what is the problem?
YAML can be a bit iffy when it comes to syntax, make sure your using all spaces (no tab chars). And makes sure every indentation is the same amount of space characters. Like 2/4/6/8 for each level or 4/8/12 etc if you prefer 4 wide.
The code you posted should be fine, but its probably something silly as described above. If it was actually a wrong section/ parameter in the file symfony should tell you what is unexpected as it actually validates YAML files on its content.
Allright so ['#templating'] takes care of the YAML parse error, the next part is how to use a service. Which is done using the service container.
In a controller there is an alias for it and you can do something like:
// required at the top to use the response class we use to return
use Symfony\Component\HttpFoundation\Response;
// in the action we use the service container alias
// short for $this->container->get('app.error');
$content = $this->get('app.error')->redirectToError(true, 'Hello world');
// as your redirectToError function returns a templating->render, which only returns a
// string containing the the rendered template, however symfony
// requires a Response class as its return argument.
// so we create a response object and add the content to it using its constructor
return new Response($content);
A few small things:
$condition, is probably likely to change if not it seems it should not be in the function but around the function call, as it seems weird to call an redirectToError but there is no error, instead we just call it when we do have an error.
And its recommended to if you are setting a class variable to define it (details on visibility):
class Error {
// visibility public, private, protected
protected $templating;
You should put ' around #templating
services:
app.error:
class: AppBundle\Utils\Error
arguments: ['#templating']

getting the gettext behavior using the Po File Loader in the translation provider in Silex

I'm using the translation provider and the PoFileLoader in Silex and everything works super great.
$app['translator'] = $app->share($app->extend('translator', function($translator, $app) {
$translator->addLoader('po', new PoFileLoader());
$translator->addResource('po', __DIR__.'/resources/translations/de.po', 'de');
}
The only problem that I have is how it treats strings that doesn't have translation yet. I want them to be ignored and use the source instead of an empty string. Like the way gettext function treats the po files.
Is there any option for that or should I override the PoFileLoader class?
The only problem that I have is how it treats strings that doesn't have translation yet. I want them to be ignored and use the source instead of an empty string. Like the way gettext function treats the po files.
This is something the translator does, not the file loader. If there is no translation found in the message catalogue, the translator will just replace the parameters and return the source.
See also the source:
public function get($id, $domain = 'messages')
{
// ... all the loading logic
// if everything failed, just return the source
return $id;
}
This method is called in the Translator#trans method.

Controller filenames starting with P cause Routing problems

I recently created a controller called PublishBannerController.php It was a cut and paste of a previous Controller with all the various parts adjusted accordingly. The only problem is, I get this error when I try and load it:
FatalErrorException: Error: Class 'Me\MyBundle\Controller?ublishBannerController' not found in /.../public_html/app/cache/dev/appDevDebugProjectContainer.php line 3190
I have replaced the square that appears, with a ? as the square really messes with stackOverflows editor.
It seems that the Symfony 2 parser converts paths containing \P into the special character that that represents.
As you can see below in appDevDebugProjectContainer.php anywhere where it is \P it converts it, even in the comments. Anywhere it contains _P etc. it is fine.
/*
* Gets the 'me.controller.publishbanner' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* #return Me\MyBundle\Controller?ublishBannerController A Me\MyBundle\Controller?ublishBannerController instance.
*/
protected function getMe_Controller_PublishbannerService()
{
$this->services['me.controller.publishbanner'] = $instance = new \Me\MyBundle\Controller?ublishBannerController();
$instance->setContainer($this);
return $instance;
}
Here is my routing.yml
me_site_publishbanner:
pattern: /publishbanner
defaults: { _controller: me.controller.publishbanner:indexAction }
And services.yml
me.controller.publishbanner:
class: "Me\MyBundle\Controller\PublishBannerController"
shared: true
calls:
- [ setContainer, ["#service_container"] ]
Am I making a mistake somewhere or is this a bug in Symfony 2? Are you basically not allowed to create controller names starting with P?
Obviously, it is a Unicode issue and relates to this:
http://php.net/manual/en/regexp.reference.unicode.php
And I have this set in my php.ini:
default_charset = "UTF-8"
I just wasn't expecting to come across this sort of issue in Symfony 2.
Do not use double quotes in your yaml file for string delimiters. It would appear that, with double quotes, \ characters get converted in to their escaped values.
No real need to use any quotes at all for class names.
If you do want to quote things like #service to avoid warnings that some broken yaml processor issue then use single quotes.

Display nested list with doctrine2 and zf2

Following this tutorial and putting in all together to make it work in my project, just to display a nested list (using doctrine 2 and zf2) , I can not enter into the foreach. Using this snippet of code:
$root_categories = $em->getRepository('Controleitor\Model\Entity\Category')->findBy(array('parent_category' => null));
$collection = new \Doctrine\Common\Collections\ArrayCollection($root_categories);
$category_iterator = new \MYMODULE\Model\Entity\RecursiveCategoryIterator($collection);
$recursive_iterator = new \RecursiveIteratorIterator( $category_iterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($recursive_iterator as $index => $child_category){
echo 'test';
}
Debug::dump($recursive_iterator);die;
I'm expecting to print the 'test' string but it only print this:
object(RecursiveIteratorIterator)#414 (0) {}
But when I do before the dump:
$recursive_iterator->current()->getTitle();
I got the title.. It fails somehow looping the \Doctrine\Common\Collections\ArrayCollection object.
If you're using different Debug class instead of Doctrine's one, that may the suspect. Try Doctrine\Common\Util\Debug::dump().
Explain comes from official documentation:
Lazy load proxies always contain an instance of Doctrine’s
EntityManager and all its dependencies. Therefore a var_dump() will
possibly dump a very large recursive structure which is impossible to
render and read. You have to use Doctrine\Common\Util\Debug::dump() to
restrict the dumping to a human readable level. Additionally you
should be aware that dumping the EntityManager to a Browser may take
several minutes, and the Debug::dump() method just ignores any
occurrences of it in Proxy instances.
I had the same issue. I've discussed with the author of this tutorial, he recommended me to check the valid() function of the RecursiveCategoryIterator class and there was the problem.
Since I was using "use" statetment and left a backslash before th class name:
use Entity\Category;
use Doctrine\Common\Collections\Collection;
class RecursiveCategoryIterator implements \RecursiveIterator
{
//.......
public function valid()
{
return $this->posts->current() instanceof \Category;
}
There ware two ways to solve this problem:
1. To remove the backslash:
return $this->posts->current() instanceof Category;
2. To use full namespace:
use Entity\Category; // remove this line
//.......
return $this->posts->current() instanceof \Entity\Category;
Hope that helps.

Resources