Symfony 4 : slashes unscaped on JSON response - php

Good morning guys,
I have a probleme on my symfony 4 Api.
I should return a json response, but the serializer return a string with slashes. I Don't know how escape it.
Bellow my controller :
use App\Entity\Category;
use App\Form\CategoryType;
use App\Repository\CategoryRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface as SerializerInterfaceAlias;
use FOS\RestBundle\Controller\Annotations as Rest;
/**
* Category Controller
* #Route("/api", name="api_")
*/
class CategoryController extends AbstractController
{
/**
* #Rest\Get("/categories")
* #param CategoryRepository $categoryRepository
* #param SerializerInterfaceAlias $serializer
*/
public function index(CategoryRepository $categoryRepository, SerializerInterfaceAlias $serializer)
{
$jsonContent = $serializer->serialize($categoryRepository->findall(), 'json', ['json_encode_options' => JSON_UNESCAPED_SLASHES]);
return $jsonContent;
}
[....]
}
And my return is look like :
"[{\"id\":3,\"name\":\"toto\",\"logo\":\"tata\",\"description\":\"lolo\",\"dateCreated\":\"2019-05-09T10:30:39+00:00\"},{\"id\":4,\"name\":\"tata\",\"logo\":\"titi\",\"description\":\"tutu\",\"dateCreated\":\"2019-05-09T10:30:49+00:00\"}]"
For information I using PHP 7.1 & Symfony 4.2.
So I want a proper json format... without this slashes :(
Do you have any suggestion ? :)
Thanks in advance !

I finaly resolve my problem #RubberDuckDebugging
I don't need to use the serializer here.
I need just to return :
return $this->json($categoryRepository->findall());
That's so simple. Sorry :)

Related

Symfony 5 NormalizerInterface not found

i'm following a tutorial online on how to use Symfony
i followed all the step but for some reason when is try to use NormalizeInterface i get this error :
Cannot determine controller argument for "App\Controller\ApiPostController::index()": the $normalizer argument is type-hinted with the non-existent class or interface: "App\Controller\NormalizerInterface". Did you forget to add a use statement?
I tried multiple solutions and none of them worked
My code is
<?php
namespace App\Controller;
use App\Repository\PostRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer;
class ApiPostController extends AbstractController
{
/**
* #Route("/api/post", name="api_post_index", methods={"GET"})
*/
public function index(PostRepository $postRepository, NormalizerInterface $normalizer )
{
$posts = $postRepository->findAll();
$postsNormalises = $normalizer->normalize($posts, null, ['groups' => 'post:read']);
return $this->render('api_post/index.html.twig', [
'controller_name' => 'ApiPostController',
]);
}
}
Thank you for taking the time to read and thank you for you help in advance
Add use line:
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

Symfony 2.8 Services issue

Since the last 4 hours I'm trying to understand the logic of Symfony 2 services and how they integrate in the application...
Basically I'm trying to set my EntityManager via a service and use it in a controller
I have the following structure
Bundle1/Controller/Bundle1Controller.php
Bundle1/Services/EntityService.php
Bundle2/Controller/Bundle2Controller.php
Bundle3/Controller/Bundle3Controller.php
....
I'm trying to make a REST API with different entry points, that's why I use multiple bundles bundle2,bundle3....
The logic is the following:
A POST is fired to Bundle2/Controller/Bundle2Controller.php
Bundle2Controller.php instances a new() Bundle1Controller.php
Inside Bundle1Controller I want to access a service entity_service in order to get my EntityManager
I have 2 cases in which I manage to land...
In Bundle1/Controller/Bundle1Controller if I try $this->container or $this->get('entity_service') I get a null everytime
If I set the container in Bundle2/Controller/Bundle2Controller and try $this->get('entity_service') I get You have requested a non-existent service "entity_service"
I will place all the code below
Bundle1/Controller/Bundle1Controller
<?php
namespace Bundle1\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use EntityBundle\Entity\TestEntity;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
class Bundle1Controller extends Controller
{
/**
* #param $response
* #return array
*/
public function verifyWebHookRespone($response){
$em = $this->get('entity_service')->getEm();
$array = json_decode($response);
$mapping = $em->getRepository('EntityBundle:TestEntity')
->findBy(["phone" => $array['usernumber']]);
return $mapping;
}
}
Bundle2/Controller/Bundle2Controller.php
<?php
namespace Bundle2\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Bundle1\Controller\Bundle1Controller;
class Bundle2Controller extends Controller
{
public function webhookAction(Request $request)
{
$data = $request->request->get('messages');
$model = new Bundle1Controller();
$responseMessage = $model->verifyWebHookRespone($data);
return new Response($responseMessage, Response::HTTP_CREATED, ['X-My-Header' => 'My Value']);
}
}
Bundle1/Services/EntityService.php
<?php
namespace EntityBundle\Services;
use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\Container;
class EntityService
{
protected $em;
private $container;
public function __construct(EntityManager $entityManager, Container $container)
{
$this->em = $entityManager;
$this->container = $container;
}
/**
* #return EntityManager
*/
public function getEm()
{
return $this->em;
}
}
services.yml
services:
entity_service:
class: Bundle1\Services\EntityService
arguments: [ "#doctrine.orm.entity_manager" , "#service_container" ]
Can anyone please help me with something regarding this issue?
How can I register a service and call it from anywhere no matter the bundle or another service?
You should check where your services.yml is located and whether it is imported in the config.yml
You can't just instantiate a controller and expect it to work, you need to set the container.
But you can call EntityManager without needing any other service by using;
$this->get('doctrine.orm.entity_manager');
I can't understand your structure or what you are trying to achieve, but those are the options to go about if you want to keep this structure.

How to pass options to json_encode function in Symfony Serializer component

here is the situation: I work on a rest api, based on symfony3, it uses FOSRestBundle and symfony serializer component, so methods return array and FOSRest handles encoding and response. The problem is serializer use json_encode with default settings and api return data like '\u00c9S' for some symbols. So I need to pass 'JSON_UNESCAPED_UNICODE' to json_encode() somehow. Is there any proper way to reach this goal?
Example of a method:
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use FOS\RestBundle\Controller\Annotations as Rest;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Component\HttpFoundation\Request;
/**
* Class ExampleController
* #package AppBundle\Controller
*/
class ExampleController extends Controller
{
/**
* #Rest\Get("/get-some-data")
* #param Request $request
* #return array
*/
public function getSomeDataAction(Request $request)
{
$someData = [
'prop1' => 'Value',
'prop2' => 'Value',
'prop3' => 'Value',
'prop4' => 'Value',
];
return $someData;
}
So when I do request to '/get-some-data', it returns me:
{"prop1":"Value with \/","prop2":"Value with \u00c9"}
, but I need it to return:
{"prop1":"Value with /","prop2":"Value with É"}
I use Symfony 3 and the "Doctrine JSON ODM Bundle" to store my data as JSON document. I had the same problem. All the data that contained unicode characters where automatically escaped which was not what I wanted.
After some experiments I finally managed to pass JSON_UNESCAPED_UNICODE option to json_encode().
Below is my solution:
# config/services.yml
serializer.encode.json.unescaped:
class: Symfony\Component\Serializer\Encoder\JsonEncode
arguments:
- !php/const JSON_UNESCAPED_UNICODE
serializer.encoder.json:
class: Symfony\Component\Serializer\Encoder\JsonEncoder
arguments:
- '#serializer.encode.json.unescaped'
Solution for Symfony 5.
Passing an integer as first parameter of the "Symfony\Component\Serializer\Encoder\JsonEncode::__construct()" method is deprecated since Symfony 4.2, use the "json_encode_options" key of the context instead.
Add to config/services.yaml:
serializer.encode.json.unescaped:
class: Symfony\Component\Serializer\Encoder\JsonEncode
arguments:
- { "json_encode_options": !php/const JSON_UNESCAPED_UNICODE }
serializer.encoder.json:
class: Symfony\Component\Serializer\Encoder\JsonEncoder
arguments:
- '#serializer.encode.json.unescaped'
When set json type in doctrine for column under the hood is using PHP's json_encode() and json_decode() functions for storing and retrieving data from databases.
json_encode() function that convert PHP's array to JSON string has second parameter for assign set of options for set up some convertation rules. One of them is JSON_UNESCAPED_UNICODE that disable encoding multibyte symbols as \uXXXX
We can enable this option for json_encode() by default for doctrine. To levarage this you must do 2 steps.
1. Create class App\Doctrine\Types\JsonType
// App\Doctrine\Types\JsonType.php
<?php
namespace App\Doctrine\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
class JsonType extends \Doctrine\DBAL\Types\JsonType
{
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if ($value === null) {
return null;
}
$encoded = json_encode($value, JSON_UNESCAPED_UNICODE);
if (json_last_error() !== JSON_ERROR_NONE) {
throw ConversionException::conversionFailedSerialization($value, 'json', json_last_error_msg());
}
return $encoded;
}
}
2. Override configuration for DBAL JSON type corresponding to our class
# config/packages/doctrine.yaml
doctrine:
dbal:
types:
json: App\Doctrine\Types\JsonType
You can use an encoder, as found here and in the documentation
<?php
$encoder = new JsonEncoder(new JsonEncode(JSON_UNESCAPED_UNICODE), new JsonDecode(false));
$normalizer = new ObjectNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
EDIT:
In this example, I use a Response object. Note that an Action Controller must return a Response object.
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use FOS\RestBundle\Controller\Annotations as Rest;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Component\HttpFoundation\Request;
/**
* Class ExampleController
* #package AppBundle\Controller
*/
class ExampleController extends Controller
{
/**
* #Rest\Get("/get-some-data")
* #param Request $request
* #return array
*/
public function getSomeDataAction(Request $request)
{
$someData = [
'prop1' => 'Value',
'prop2' => 'Value',
'prop3' => 'Value',
'prop4' => 'Value',
];
$response = new Response($someData);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
$this->serializer->serialize(
$data,
JsonEncoder::FORMAT,
['json_encode_options' => JSON_UNESCAPED_UNICODE]
);
In newer versions of symfony you have to use this format:
$encoders = [new JsonEncoder(new JsonEncode(["json_encode_options" =>
JSON_UNESCAPED_SLASHES]), new JsonDecode([]))];

UploadedFile __toString() exception

I'm trying to insert to database (store function) and I'm getting this error:
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_UNKNOWN)
Method Illuminate\Http\UploadedFile::__toString() must not throw an exception
/home/vagrant/Sites/mySite/vendor/laravel/framework/src/Illuminate/Database/Connection.php
<?php
namespace Illuminate\Database;
use PDO;
use Closure;
use Exception;
use Throwable;
use LogicException;
use RuntimeException; // Highlighted
use DateTimeInterface;
use Illuminate\Support\Arr;
use Illuminate\Database\Query\Expression;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Query\Processors\Processor;
use Doctrine\DBAL\Connection as DoctrineConnection;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Schema\Builder as SchemaBuilder;
use Illuminate\Database\Query\Grammars\Grammar as QueryGrammar;
Arguments
"Method Illuminate\Http\UploadedFile::__toString() must not throw an exception"
store function
/**
* #param Request $request
* #param ReviewProsConsRepository $reviewProsConsRepository
* #param ReviewTextRepository $reviewTextRepository
* #return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request, ReviewProsConsRepository $reviewProsConsRepository, ReviewTextRepository $reviewTextRepository, ReviewLanguageRepository $reviewLanguageRepository, ReviewCurrencyRepository $reviewCurrencyRepository)
{
$review = $this->reviewRepository->create($request->all()); // Here is the error
$this->mutualAction($request, $review->id, $reviewProsConsRepository, $reviewTextRepository, $reviewCurrencyRepository, $reviewLanguageRepository);
return redirect()->route('manager.review.index')->with('message', 'Review criado com sucesso!');
}
-- Edit --
ReviewRepository.php
namespace App\Repositories;
use App\Models\Review;
use Housekeeper\Abilities\Adjustable;
use Housekeeper\Repository;
class ReviewRepository extends Repository
{
use Adjustable;
/**
* Return the name of model that this repository used.
*
* #return string
*/
protected function model()
{
return Review::class;
}
}
I have an image upload that returns the id from the uploaded image to cs_upload_id, but it's getting error and I don't understand why.
Any help is appreciated, thanks.
Not acquainted with the repository package you are using but I'm guessing it's throwing an error because you're simply passing the reviewRepository->create() method $request->all() which will consist of text key pairs which may be fine to process to the DB but will also include Illuminate\Http\UploadedFile which it can figure out how to handle.
What I would recommend is that you prepare the data in a way that the reviewRepository->create() method can understand rather than just passing it the $request->all() and hoping it will handle it just fine.
Hope that makes sense.

"Resources are not supported in serialized data." when using FOSRestBundle and Paginator

I am setting up a REST service for my website with the FOSRestBundle and JMSSerializerBundle.
I made a custom method on a entity repository which returns a Paginator object. The method works great when I use it on the normal website, but when I want to use the method with the REST route, this error is thrown (XML or JSON output throws the same error) :
"Resources are not supported in serialized data."
I really don't know where to search since the error isn't very explicit to me.
Here's my AdsRestController.php :
<?php
namespace MyProject\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use FOS\RestBundle\Controller\Annotations\Get;
class AdsRestController extends Controller
{
/**
* #View
* #Get("/ads/list/all/{page}", requirements={"page" = "\id+"}, defaults={"page" = 1})
*/
public function getAdsListAllAction($page) {
$theAds = $this->getDoctrine()->getRepository('MyProjectMainBundle:Ads')->getAds($page);
return $theAds;
}
}
and my AdsRepository.php :
<?php
namespace MyProject\MainBundle\Entity;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Tools\Pagination\Paginator;
class AdsRepository extends EntityRepository
{
public function getAds($page=1, $maxPerPage=10)
{
$query = $this->createQueryBuilder('a')
->orderBy('a.date', $order)
;
$query->getQuery();
$query
->setFirstResult(($page-1) * $maxPerPage)
->setMaxResults($maxPerPage)
;
return new Paginator($query, true);
}
}
Any help would be highly appreciated !
Thanks.
You can use iterator_to_array to convert iterator of your paginator into array :
return iterator_to_array($theAds->getIterator());
Convert result manually to an array by using getAds()->toArray() in your rest controller.
already answered here, use the search!
Check out the ->getIterator() method available on Paginator objects.
See https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/Tools/Pagination/Paginator.php
If you use iterator_to_array, it will convert the result array to a single object. It is better to fetch them to an array and then serialize it.
$var = [];
foreach ($records as $rec){
array_push($var, $rec);
}
$res = $this->get('jms_serializer')->serialize($var, 'json');
return new JsonResponse(json_decode($res));

Categories