config/packages/nelmio_api_doc.yaml:
```
nelmio_api_doc:
models:
use_jms: true
names:
- { alias: ExamType, type: StudentBundle\Form\ExamType }
- { alias: User, type: App\Entity\User }
- { alias: Pager, type: ApiBundle\Model\Pager }
```
config/packages/nelmio_api_doc.yaml:
```
nelmio_api_doc:
models:
use_jms: true
names:
- { alias: ExamType, type: StudentBundle\Form\ExamType }
- { alias: User, type: App\Entity\User }
- { alias: Pager, type: ApiBundle\Model\Pager }
```
If you make changes in php code and don't see that they work, like code remains the same, do this
be sure your php.ini configuration `opcache.validate_timestamps=0` , not 1. It can be in dev mode when you try to optimize Symfony project workflow.
Sometimes you don't need to use model instead of entity, and then save some data into entity and persist it. It means you cannot use it in Sylius ResourceControllers, because your model must implement ResourceInterface, create dedicated ResourceController, Repository, Manager, and model cannot do it.
If you want it, this means you doing it wrong, because it violated CRUD principles. The best solution is to use Symfony Data Transformers https://symfony.com/doc/current/form/data_transformers.html , add it to your form, implement transform() method, where it will create your model/DTO object from entity, and reverseTransform(), where DTO will be converted into Entity object.
When you need to put new field/database columns into Many-To-Many, relationship, you will need to switch to intermediate entity. In my case it is StudentKlass.
Imagine three entities: Team - StudentTeam - Student
use Doctrine\ORM\Mapping as ORM;
class Team {
/**
* @ORM\OneToMany(targetEntity=StudentTeam::class, mappedBy="team", cascade={"persist"})
*/
private $studentTeams;
public function __construct() {
$this->studentTeams = new ArrayCollection();
}
...
}
class StudentTeam {
/**
* @ORM\ManyToOne(targetEntity=Student::class, inversedBy="teams")
* @ORM\JoinColumn(name="student_id", referencedColumnName="id")
*/
private $student;
/**
* @ORM\ManyToOne(targetEntity=Team::class, inversedBy="studentTeams")
*/
private $team;
...
}
class Student {
/**
* @ORM\OneToMany(targetEntity=StudentTeam::class, mappedBy="student")
*/
private $teams;
private $name;
private $email;
...
}
Also don't forget to create getters, adders & removers!
You can use example how to use it in Symfony forms, which has example how to use nested forms:
class TeamType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('studentTeams', CollectionType::class, [
'entry_type' => TeamStudentType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
]);
...
}
class TeamStudentType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add(
$builder
->create('student', FormType::class, [
'data_class' => Student::class,
])
->add('email', TextType::class)
->add('name', TextType::class)
)
;
}
}
}
It can be not only FormType, also can be any your custom form type.
It can be when you moved your form into new namespace/bundle, but did not registered services in it.
Check that you copied private key, instead of public key. Because their length differs from each other
public function serialize($object, array $serializationGroups)
{
$serializer = SerializerBuilder::create();
$serializer->setPropertyNamingStrategy(new SerializedNameAnnotationStrategy(new IdenticalPropertyNamingStrategy()));
$serializer->addMetadataDir($this->configDir . "/serializer", 'App\Entity');
$serializer->setCacheDir($this->cacheDir . "/jms_serializer");
$serializer = $serializer->build();
$group = new GroupsExclusionStrategy($serializationGroups);
$context = SerializationContext::create();
$context->addExclusionStrategy($group);
return $serializer->serialize($object, 'json', $context);
}
It will make JSON string where property field is camelCased instead of Snake_cased. I highly recommend to use 'App\Entity' in addMetadataDir() because by default in Symfony jms_serializer.yaml config is set 'namespace_prefix' in metadata node, and without 'App\Entity' argument YML/XML entity configs won't work. It is also example how to customize Serializer parameters manually with SerializerBuilder without framework config.
Its because PropertyAccessor thinks form is an array. To change it, set form data_class. For example in your form Type:
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'data_class' => User::class,
...
When you trying to login in Test env, and it does not show any error (you was returned on login form again), and you does not have anything in logs, except Guard authenticator does not support the request. {"firewall_key":"main","authenticator":"App\\Security\\AppAuthenticator"}, you can try this.
I removed lines:
session:
storage_id: session.storage.mock_file
in config/packages/test/framework.yaml and it worked
Add 'data' => [''] (not 'empty_data') to the Collection type form configuration.
It means you forgot to put `grid: gridname` into your route configuration. For example:
admin_user_index:
path: /users
defaults:
_controller: app.controller.user::indexAction
_sylius:
template: "@AdminBundle/grid/index.html.twig"
grid: admin_user
When you need extra manipulations to object data population in form (for example, you need to resolve whether is entered user email is already registered and put existing user object or it needs to create a new user), you might want to set data_class with closure, but there isn't such option.
The right way is to use https://symfony.com/doc/4.4/form/data_mappers.html Data Mappers
If your default serialization group not working (does not ignore fields which should be shown only with specific group, not Default), check that \JMS\Serializer\Exclusion\GroupsExclusionStrategy is added into \JMS\Serializer\Context at \JMS\Serializer\GraphNavigator::accept() method.
If you are using Sylius (or standalone bundles), it occurs when \FOS\RestBundle\Serializer\JMSSerializerAdapter does not add GroupsExclusionStrategy. You can fix it with adding serialization_groups: [Default] like this:
api_building_show:
path: /exam/{id}
methods: [GET]
defaults:
_controller: app.controller.building:showAction
_sylius:
serialization_groups: [Default]
If ./config/packages/fos_rest.yaml:
fos_rest:
exception:
messages:
Symfony\Component\HttpKernel\Exception\HttpException: true
for you too, you can inject this service manually like this in services.yaml:
fos_rest.exception.messages_map:
class: FOS\RestBundle\Util\ExceptionValueMap
public: false
arguments:
- { Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: true }
thanks to https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1522
If your date fields looks like "2021-04-08T00:00:00+00:00", instead of your preferred timezone, set correct timezone in your cli/fpm php.ini:
[Date]
date.timezone = "Europe/Riga"
When you try to get data in json response, check that field is not empty (null)
put `grid: <gridname>` into your route like this:
tests:
path: /tests
defaults:
_controller: app.controller.test:indexAction
_sylius:
template: tests/index.html.twig
grid: app_test
run `php bin/console app:install:database`, after then you will have user "admin@example.com" with password "admin". You can use it in 127.0.0.1:8000/admin/login
If you installed @types/node-sass, enabled enableSassLoader in webpack.config.js, ran yarn add sass-loader@^8.0.0 node-sass --dev , do not forget to add {{ encore_entry_link_tags('main') }} like this (for example in templates/base.html.twig:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}
{{ encore_entry_link_tags('main') }}
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}
{{ encore_entry_script_tags('main') }}
{% endblock %}
</body>
</html>