Symfony2 REST Translation from database - symfony

I am facing very difficult problem to handle my situation. Im saving title in database for en the name is title and for the translation column the name is bntitle.
now im use FosRest with jms serializer to provide the api response. but i can't find a way to send respond based on local. because it always calls the
getTitle()
method to get the title, my question is if local is en then the title key will be getTitle() if local is bn title should call getBnTitle();
this the controller:
public function getAction(Content $entity, Request $request)
{
$locale = $request->getLocale();
$data = array();
$data['_embedded']['content'] = $entity;
eturn $data;
}
how can I do that?

This is not the best way to handle the translation for sure but if you just need this for the title attribute you can pass the local to the entity as an argument and then in getTitle() method you do the test.
public class YourEntity{
private $locale ;
//......
public function setLocale($locale){
$this->locale = $locale
}
public function getTitle(){
// your test here
if ( $locale === 'bn' ) return $this->getBnTitle();
return $title ;
}
Then in your controller :
public function getAction(Content $entity, Request $request)
{
$locale = $request->getLocale();
// pass local to entity
$entity->setLocale($locale);
$data = array();
$data['_embedded']['content'] = $entity;
eturn $data;
}
Edit :
If you want a better solution there is many doctrine extensions that do the translation one of them is this
https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/translatable.md

Related

Symdony5.3 - How to pass parameters from a Controller to a Service because the service calls a repo query?

I am working on a project where Symfony serves as API backend (with ApiPlatform) and Angular the Front End and the lead decided we will use Services and to create a function inside called updateData().
In my Service:
public function updateData(array $dates, Hotel $hotel): ?array
{
$bookings= $this->em->getRepository(Booking::class)->findAllByIdAndDate($id, $date);
foreach ($bookings as $booking) {
...
}
...
}
In my controller:
/**
* #Route("/update_data", name="update_data")
*/
public function index(UpdateData $updateData)
{
$this->em = $this->getDoctrine()
->getManager()
->getRepository(Hotel::class);
$date = new \DateTime('2021-06-13');
$id = 1;
$hotel = $this->em->find($id);
$message = $updateData->updateData([$date], $hotel);
}
My question is how can I receive the data here and pass the parameters from this controller to the service?
Thanks
In order to update the data for a specific hotel, you can use url parameters or query parameters to customize your controller.
for example, you could use a URL like this: /update_data/1?date=2021-06-13
Then your code would be using Symfony route parameters and parameter conversion.
Here is a quick example of what this would look like.
/**
* #Route("/update_data/{id<\d+>}", name="update_data")
*/
public function update_data(Hotel $hotel, Request $request): Response
{
// the $hotel variable is autoconverted using parameter conversion
$date = new \DateTime($request->query->get('date'));
$message = $updateData->updateData([$date], $hotel);
// rest of your code.
}

Symfony 4 - Creation form - Object is null

Symfony 4.3
Custom users provider (no FOS)
PHP 7.1 / MariaDB 10.2
Wamp local server
I already made users edit and users delete functions. It work PERFECT !
Now I want to create a registration form in my website but I don't understand the error !
Return value of App\Entity\User::getFirstname() must be of the type string, null returned
The exception :
in \src/Entity/User.php (line 100)
/**
* #ORM\Column(type="string")
* #Assert\NotBlank()
*/
private $firstname;
public function getFirstname(): string
{
return $this->firstname; // THIS IS LINE 100
}
Below is an extract from my UserController :
/**
* #Route("/users/add", name="app_users_add")
*/
public function addUser(Request $request, EntityManagerInterface $em): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user); // This line generates the error
[...]
return $this->render('user/add.html.twig', [
'form' => $form->createView()
]);
}
I really don't understand.
My UserEntity is working with my edit method in controller.
MY template user/add.html.twig is good (even if I let it empty)
My UserType form builder work well (I use the same for editing users)
you should add
public function getFirstname(): ?string
return $this->firstname;
}
The reason $form = $this->createForm(UserType::class, $user); generates an error is because you are passing $user as data to the form UserType. (this is refering to a file App\Form\UserType, right?). Since $user is a new object, $firstname of this user is not yet defined, thus the error occurs when you are passing the data of $user to the form. Simply removing the $user argument will work.
If you do not have a file App\Form\UserType, you can either create it or use createFormBuilder() in your controller. See the documentation for more information.

PHP using interfaces to browse multiple data source

I am creating a Symphony application that browses different data sources.
the controller that I created knows too much about the data source but the application is designed in a way to not expect that.
The data source could be DB, JSON or XML.
is there any way to implement interfaces to do that?
My controller knows the location of the XML file, and browse different data seperatly. I want to do it in one action.
That's my current controller ;
public function searchAction(Request $request) {
if ($request->getMethod() == 'POST') {
$search_for = $request->get('search');
//getting the searched products from the database
$repository = $this->getDoctrine()->getRepository('TyreTyreBundle:Products');
$query = $repository->createQueryBuilder('u')
->where("u.name LIKE '%".$search_for."%' or u.manufacturer LIKE '%".$search_for."%'")
->getQuery();
$results = $query->getResult();
//adding the XML file products
$file_url = "bundles/tyretyre/xml/products.xml";
//Convert the products.XML file into a SimpleXMLElement object
$simpleXMLElementObject = simplexml_load_file($file_url);
$i=0;
//the array where will saved the searched products from the XML file
$xml_result = [];
//looping the xml object to find matching results
while ($simpleXMLElementObject->product[$i]) {
//first we will convert to lower case both searched item and the tested name
if (strstr(strtolower($simpleXMLElementObject->product[$i]->name),strtolower($search_for))){
//push that element into the array to display it later in the twig file
array_push($xml_result, $simpleXMLElementObject->product[$i]);
}
$i++;
}
//end of products searching from the XML source
//display the detail page with passing the DB result and XML result arrays
return $this->render('TyreTyreBundle:Default:detail.html.twig', array('results' => $results,'xml_result' => $xml_result));
}
return $this->render('TyreTyreBundle:Default:search.html.twig');
}
My products entity :
namespace Tyre\TyreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Products
*/
class Products
{
//some getter and setters and private attribute
}
EDIT following VolCh solution,
I registered the service as following (I think I am doing it wrong) in /src/Tyre/TyreBundle/Resources/config/services.yml:
services:
Tyre\TyreBundle\Repository\DoctrineProductRepository:
class: Tyre\TyreBundle\Repository\DoctrineProductRepository
Tyre\TyreBundle\Repository\ProductRepositoryInterface:
class: Tyre\TyreBundle\Repository\ProductRepositoryInterface
But then I get the following
ContextErrorException: Notice: Undefined index: in
/home/smiles/Documents/tyre/src/Tyre/TyreBundle/Controller/DefaultController.php
line 56
Line 56: is this line : $serviceName = $repositoryMap[$request->get('db')];
You could:
declare \TyreTyreBundle\ProductRepository interface (or ProductDataSource if you wish) with method ->search(string $needle): array (or some DTO)
implement it in DoctrinreProductRepository, XmlProductRepository, JsonProductRepository as service with constructor injection of \Doctrine\EntityRepository, xml-filename, json-filename
get properly repository from container in actions
(optional) create ProductRepositoryFactory whith createFor('db|xml|json') method and pass type to controller as part of route like '/datasource/{db|xml|json}' or request parameter like datasource?type=db'and create properly repository in one common action
Added:
Example (proof of concept, don't use, php7+):
src/TyreBundle/Repository/ProductRepositoryInterface.php
namespace Tyre\TyreBundle\Repository;
interface ProductRepositoryInterface
{
function search(string $needle): array;
}
src/TyreBundle/Repository/DoctrineProductRepository.php
namespace Tyre\TyreBundle\Repository;
class DoctrineProductRepository implements ProductRepositoryInterface
{
public function __constructor(EntityManager $em)
{
$this->em = $em;
}
public function search(string $needle): array
{
$repository = $this->em->getRepository('TyreTyreBundle:Products');
$query = $repository->createQueryBuilder('u')
->where("u.name LIKE '%".$needle."%' or u.manufacturer LIKE '%".$needle."%'")
->getQuery();
return $query->getArrayResult();
}
}
src/TyreBundle/Repository/XmlProductRepository.php
src/TyreBundle/Repository/JsonProductRepository.php
controller
public function searchAction(Request $request)
{
$repositoryMap = [
'db' => DoctrineProductRepository::class,
'xml' => XmlProductRepository::class,
'json' => JsonProductRepository::class,
];
$serviceName = $repositoryMap[$request->get('type')];
/** #var ProductRepositoryInterface */
$repository = $this->get($serviceName);
$results = $repository->search($request->get('serxh_for'));
return $this->render('TyreTyreBundle:Default:detail.html.twig', array('results' => $results));
}
also you should register Repository classes as services with their names.

Doctrine2 Filter Parameter empty value twig extensions

In my application a company has their own subdomain. Im listening to kernel request event and setting the Company Filter(Doctrine Filter) parameter based on the company matching the subdomain.
public function setCompanyFilter($companyId)
{
/** #var EntityManager $entityManager */
$entityManager = $this->container->get('doctrine')->getManager();
$filters = $entityManager->getFilters();
$companyFilter = $filters->isEnabled('company_filter')
? $filters->getFilter('company_filter')
: $filters->enable('company_filter');
$companyFilter->setParameter('company', $companyId);
}
The issue im having is that on twig extensions(filter/functions) the parameter is not setted. If i set the value before execute a filter/function everything works as expected.
Is there any way to execute some code before every twig filter/function/tag? Like listening to an twig event? Or how can i solve this issue without calling the setCompanyFilter on every twig filter/function/tag.
Thanks
Why not set the custom value in the same event (i.e. kernel.request) that you are already listening to?
I assume you are using a custom twig extension. If not extend the filter/function you are already using and do the same:
<?php
// src/AppBundle/Twig/AppExtension.php
namespace AppBundle\Twig;
class AppExtension extends \Twig_Extension
{
private $customParameter;
public function getFilters()
{
return array(
new \Twig_SimpleFilter('price', array($this, 'priceFilter')),
);
}
public function priceFilter($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',')
{
$price = number_format($number, $decimals, $decPoint, $thousandsSep);
$price = '$'.$price;
return $price;
}
public function getName()
{
return 'app_extension';
}
public function setCustomParameter($parameter)
{
$this->customParameter = $parameter;
}
}
Inject the twig extension into your current listener and then call the method setCustomParameter, inject your custom parameter for use later in the request lifecycle, and then just call the filter/function as your normally would in your existing twig template.

Symfony 2 twig bad credentials trans bug

Good day.
I'm having 2 projects in Symfony 2. In first, i'm using {{ error.message|trans }} to translate
"Bad credentials" authorization error message. It calls Translator class trans method from Component\Translation\Translator.php to translate this string.
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
{
if (null === $locale) {
$locale = $this->getLocale();
}
if (null === $domain) {
$domain = 'messages';
}
if (!isset($this->catalogues[$locale])) {
$this->loadCatalogue($locale);
}
return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters);
}
It works correctly, and returns translated string from messages.domain.yml file. In second project, i'm using same settings, and trying to translate error string in twig in the same way. But it doesn't working, and the original 'Bad credentials' string is returned. After inspection, i found, that Component\Translation\IdentityTranslator.php class is creating(instead of Translator.php), and it's method trans is being called:
/**
* IdentityTranslator does not translate anything.
*
* #author Fabien Potencier <fabien#symfony.com>
*
* #api
*/
class IdentityTranslator implements TranslatorInterface
{
/// More code here
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
{
return strtr((string) $id, $parameters);
}
}
So, it just returns the original message. What could be potential source of such problem? Is it Symfony bug? (Both projects uses Symfony 2.4.4)

Resources