$request->request->replace() what does it do? - symfony

I was going through some code in symfony, and I found
$request->request->replace()
Actually, a form is posted and its value is fetched in a function say,
public function someFunction(Request $request){
$data = $request->request->all() ? : json_decode($request->getContent(), true);
$request->request->replace($data);
}
When I dumped,
$request->request->replace($data)
The result is null. I didn't understand why is it used and what are its benefits?
I searched about it, some say it is used to sanitise the data, some say we should not use it as replaces all of the parameters in the request instead we should use set method.
And I did not get any of it as I am new to symfony.
What does $request->request->replace() does with the parameter provided to it?

Your $request is an instance of Symfony\Component\HttpFoundation\Request
. Using $request you have access to properties such as request, query, cookies, attributes, files, server, headers. Each of these properties is of type Symfony\Component\HttpFoundation\ParameterBag. Instance of ParameterBag provides access to request parameters using method $request->request->all(). This method will return 'parameters' property of ParameterBag instance.
The $request->request->replace($data) will set 'parameters' property in ParameterBag instance to $data.
Also replace() method does not have any return type that's why when you dumped $request->request->replace($data) you got null as output.
If you want to add some extra parameters to your request then replace() is not the right choice rather you should use set() method in ParameterBag.

Related

Entity expected object returned symfony

I'm trying to get an item from the database and pass it to a new item to push to the database.
$post = $entityManager->getRepository('App:Post')
->find($id);
$comment->setPost($post)
the setPost looks like the following:
public function setPost(Post $post): self
{
$this->post = $post;
return $this;
}
and the $post variable:
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Post", inversedBy="comments")
* #ORM\JoinColumn(nullable=false)
*/
private $post;
But when i try to set the post like setPost($post) it gives me the following error:
Expected parameter of type '\App\Entity\Post', 'object' provided
I assume, that the error you see is from your integrated developent environment (IDE), for example eclipse, vs code, phpstorm, and others. But the code - when actually executed - should work.
Now, the error most likely stems from a static code analysis running in the background of said IDE, which will look at the statement and trying to analyze according to the called methods, accessed properties etc. of which type your variables are.
So, let's do this slowly (and you can probably hover over the $vars and ->methods() do verify. The line I'm interested in is
$post = $entityManager->getRepository('App:Post')
->find($id);
so $entityManager is of type EntityManagerInterface, which has a getRepository method with one required parameter of type string ('App:Post' in your case), and it will return an object of type ObjectRepository, which has a method find which requires one parameter (mixed, don't ask), and returns ?object which means, an object or null. So, $post is of type object (best case, or null, in which case it would fail!). Now, the next line obviously expects a parameter of type Post and not of type object, thus the warning/notice/error.
Now, static code analysis is quite helpful up to a certain level, but it isn't infallible because it has limitations. It doesn't know what runtime will actually return, it just assumes that the type hints found in the code (of doctrine) are sufficiently specific - which they aren't in your case.
the easy fix
add a doc string to tell static code analysis what the variable $post's type actually is:
/** #var Post $post */
$post = $entityManager->getRepository('App:Post')
->find($id);
this explicitly tells the static analysis tool, that $post is of type Post, maybe you have to write App\Entity\Post or even \App\Entity\Post.
the hard fix
Alternatively, you could implement your own PostRepository (doctrine provides some help) and define a function like function findById($id) :Post - which would explicitly tell static code analysis, what the return type is when you call it in your code (injected in your function via dependency injection: PostRepostory $postRepository):
$post = $postRepository->findById($id);
If you're using lots and lots of different entities, this is a very verbose solution but depending on your project it might be worth it, since you explicitly name the dependencies instead of injecting the very unspecific (as we have seen) EntityManagerInterface. Using the EntityManagerInterface might make testing HELL (imho!).

What is the best way to create a singleton entity in Symfony 4?

I want to create a settings page, which only has a form in it. If the form is submitted it only updates settings entity but never creates another one. Currently, I achieved this like:
/**
* #param SettingsRepository $settingsRepository
* #return Settings
*/
public function getEntity(SettingsRepository $settingsRepository): Settings
{
$settings = $settingsRepository->find(1);
if($settings == null)
{
$settings = new Settings();
}
return $settings;
}
In SettingsController I call getEntity() method which returns new Settings entity (if the setting were not set yet) or already existing Settings entity (if setting were set at least once).
However my solution is quite ugly and it has hardcoded entity id "1", so I'm looking for a better solution.
Settings controller:
public function index(
Request $request,
SettingsRepository $settingsRepository,
FlashBagInterface $flashBag,
TranslatorInterface $translator,
SettingsService $settingsService
): Response
{
// getEntity() method above
$settings = $settingsService->getEntity($settingsRepository);
$settingsForm = $this->createForm(SettingsType::class, $settings);
$settingsForm->handleRequest($request);
if ($settingsForm->isSubmitted() && $settingsForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($settings);
$em->flush();
return $this->redirectToRoute('app_admin_settings_index');
}
return $this->render(
'admin/settings/index.html.twig',
[
'settings_form' => $settingsForm->createView(),
]
);
}
You could use Doctrine Embeddables here.
Settings, strictly speaking, should not be mapped to entities, since they are not identifiable, nor meant to be. That is, of course, a matter of debate. Really, a Settings object is more of a value object than an entity. Read here for more info.
So, in cases like these better than having a one to one relationship and all that fuzz, you probably will be fine with a simple Value Object called settings, that will be mapped to the database as a Doctrine Embeddable.
You can make this object a singleton by creating instances of it only in factory methods, making the constructor private, preventing cloning and all that. Usually, it is enough only making it immutable, meaning, no behavior can alter it's state. If you need to mutate it, then the method responsible for that should create a new instance of it.
You can have a a method like this Settings::createFromArray() and antoher called Settings::createDefaults() that you will use when you new up an entity: always default config.
Then, the setSettings method on your entity receieves only a settings object as an argument.
If you don't like inmutablity, you can also make setter methods for the Settings object.

Set up non-persistent relation in Doctrine 2

I have an object $user that has a one to many relation with $establishment. I can use:
$user->getEstablishments();
The user can select a stablishment to work on. I have this method that I call in the controller:
$user->setCurrentEstablishment($establishment);
And this one that I call in the view:
$establishment = $user->getCurrentEstablishment();
I want to be able to call:
$user->setCurrentEstablishmentBy Slug($establishment_slug);
where the slug is a string, and let the user object look for the establishment.
Doctrine discourages the practice of accessing the Entity Manager inside the Entity object, but I think that using it in the controller is even worse.
I suspect that some special Doctrine annotation exists that takes care of non persistent relations like this, or some method other than serving the Entity Manager through a service should be used here. Some easy way of referencing other entities from inside the model.
¿Is there any? ¿How could I do that?
There is no Annotation in Doctrine which could convert slug into object.
What can help You is ParamConverter, with it you can automatically convert slug from query into object. But it still must be used in Controller.
Example usage:
/**
* #Route("/some-route/{slug}")
* #ParamConverter("object", class="AppBundle:Establishment", options={"id" = "slug", "repository_method" = "findEstablishmentBySlug"})
*/
public function slugAction(Establishment $object)
{
...
Docs about param converter: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

Return a value from entity to view file in symfony

I want to return a value from entity to view file. Below is my entity function
public function getVisitorName($id)
{
$repository = $this->getDoctrine()->getRepository('SystemVmsBundle:VisitorsDetails');
$product = $repository->findOneBy(array('id' =>$id));
$name=$product->getFirstname();
return $name;
}
This is the line in my view file which calls that function
{{ entity.visitorName(entity.visitorId) }}
Its not giving me any error. But only a blank page. How can i fix this?
This is my controller code
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('SystemVmsBundle:EntryDetails')->findAll();
return array(
'entities' => $entities,
);
}
I am trying to fetch the visitors name(from visitors table) corresponding to the visitor id(in entry table).How will i do it then?
you have two ways of doing it:
1) Map your SystemVmsBundle:EntryDetails entity, to SystemVmsBundle:VisitorsDetails as OntToOne by adding field details to your EntryDetails; , and then in twig template just call it via
{{ entity.details.name }}
2) instead of creating getVisitorName(), it is better to create twig function for this, with same functionality.
Your indexAction() is not returning a response object, it is just returning an array of entities. Controller actions should return a Response containing the html to be displayed (unless they are for e.g. ajax calls from javascript). If you are using twig templates you can use the controller render() method to create your response, something like this:
return $this->render('<YourBundle>:<YourViewsFolder>:<YourView>.html.twig', array(
'entities' => $entities,
));
When you've corrected that I suspect you'll get an error because $this->getDoctrine() won't work from an entity class. The code you have in the getVisitorName() method just shouldn't be in an entity class.
As #pomaxa has already suggested, I believe there should be a relationship between your EntryDetails and VisitorsDetails entities although I don't know enough about your data from the question to know what type of relationship it should be (OneToOne / ManyToOne). If your EntryDetails entity had a relationship to VisitorsDetails, the EntryDetails class would then contain a $visitorsDetails attribute and methods to get/set it. Then the line in your twig file would look like this:
{{ entity.visitorsDetails.firstName }}
There is a section on Entity Relationships / Associations in the Symfony Manual.
Also, I hope you don't mind me giving you a little advice:
Be careful when you copy and paste code as it appears you have done in getVisitorName(). You have kept the variable name '$product' although there are no products in your system. This sort of thing can cause bugs and make the code more difficult to maintain.
I recommend you avoid tacking 'Details' onto the end of entity names unless you genuinely have two separate and related entities such as Visitor + VisitorDetails and a good reason for doing so. I think the entities in your example are actually 'Visitor' and 'VistorEntry'.
Unless you are writing a re-usable component, I recommend you use specific variable names like '$visitorEntries' rather than '$entities' in your controller and twig.
In general, the more meaningful your variable names, the more readable, maintainable and bug-free your code is likely to be. Subsequently, it will also be much easier for people on SO to understand your code and give you help when you need it.

In Drupal, how to change the values passed to Pathauto?

I have Pathauto configured to generate an alias based on the title of a node, for a specific content type. The problem is that I want to make small changes in this title before Pathauto uses it to generate the alias.
The first comment in this post suggests the use of hook_token_values, but I couldn't really understand how to use it, even after reading the docs. In my tests, when I implement this hook, the alias generated is always "array", which means I'm missing something.
Any help? Thanks.
It might be that you missed to implement hook_token_list as well. Providing a new token is a two step process:
Implement hook_token_list to declare the tokens you are going to provide. This will just be the name of the tokens, along with a short explanation, and the information to what type of objects the tokens will apply (e.g. node, user, taxonomy, ...)
Implement hook_token_value to actually generate the content of the tokens. This will be called when the tokens are to be replaced with the content they should stand for.
As you just want to provide an alternative version of the title token already provided by the token module, it is probably best to just copy the relevant portions from token_node.inc, stripped down to the relevant cases and adjusted to be used in another module:
/**
* Implementation of hook_token_list().
*/
function yourModule_token_list($type = 'all') {
if ($type == 'node' || $type == 'all') {
$tokens['node']['yourModule-title'] = t('Node title (customized version by yourModule)');
return $tokens;
}
}
This simply says that yourModule provides a token for node objects, named yourModule-title, along with a short description. The main work gets done in the other hook:
/**
* Implementation of hook_token_values().
*/
function yourModule_token_values($type, $object = NULL, $options = array()) {
$values = array();
switch ($type) {
case 'node':
$node = $object;
// TODO: Replace the check_plain() call with your own token value creation logic!
$values['yourModule-title'] = check_plain($node->title);
break;
}
return $values;
}
This will be called whenever the tokens for node objects are needed, with the node in question being passed as the $object parameter (for a user token, the $type would be 'user', and $object would be the user object, and so on for other types). What it does is creating an array of values, keyed by the token name, with the replacement for that token as the value. The original code from token_node.inc just runs the title through check_plain(), so this would be the place to insert your own logic.
In Drupal 7, the token functionality has been moved to core. Tokens are implemented by the hook_tokens and hook_token_info methods. For usage examples, follow the links provided, and look for links to functions that implement hook_tokens and hook_token_info… I found the statistics_tokens and statistics_token_info functions helpful in understanding how this hook works.
It's probably also worth noting that this hook needs to be implemented by a module… my first attempt I dropped my test functions into the theme's template.php, only to have nothing happen at all :-p

Resources