I create a service to encrypt and decrypt my data in my database.
So when I create a new Fiche or update one, I encrypt the name and the surname
Here my subscriber FicheEntitySubscriber :
class FicheEntitySubscriber implements EventSubscriberInterface
{
private $security;
private $encryptionService;
public function __construct(Security $security, EncryptionService $encryptionService)
{
$this->security = $security;
$this->encryptionService = $encryptionService;
}
public static function getSubscribedEvents(): array
{
return [
BeforeEntityPersistedEvent::class => ['setFicheEntity', 10],
BeforeEntityUpdatedEvent::class => ['setFicheEntity', 10]
];
}
/**
* #throws Exception
*/
public function setFicheEntity(AbstractLifecycleEvent $event)
{
$entity = $event->getEntityInstance();
if (!($entity instanceof FicheEntity)) {
return;
}
if ($event instanceof BeforeEntityPersistedEvent) {
$entity->setUtilisateur($this->security->getUser());
}
$entity->setNom($this->encryptionService->encrypt_decrypt('encrypt', mb_strtoupper($entity->getNom())));
$entity->setPrenom($this->encryptionService->encrypt_decrypt('encrypt', mb_strtoupper($entity->getPrenom())));
}
}
Here my FicheController :
class FicheEntityCrudController extends AbstractCrudController
{
private $_adminContextFactory;
private $encryptService;
private $ficheEntityRepo;
public function __construct(AdminContextFactory $adminContextFactory, EncryptionService $encryptionService, FicheEntityRepository $ficheEntityRepo)
{
$this->_adminContextFactory = $adminContextFactory;
$this->encryptService = $encryptionService;
$this->ficheEntityRepo = $ficheEntityRepo;
}
public static function getEntityFqcn(): string
{
return FicheEntity::class;
}
public function configureCrud(Crud $crud): Crud
{
return $crud
->setEntityLabelInPlural('Fiches')
->setEntityLabelInSingular('Fiche informative')
->setSearchFields(['nom', 'prenom', 'nomAntibio'])
->setPaginatorPageSize(10)
->setPaginatorRangeSize(2);
}
public function configureFilters(Filters $filters): Filters
{
return $filters
->add(TextFilter::new('nomAntibio')->setLabel('Nom ATB'))
->add(DateTimeFilter::new('dateDebut')->setLabel('Date Debut'))
->add(DateTimeFilter::new('dateRappel3Jour')->setLabel('Rappel 3e Jour'))
->add(DateTimeFilter::new('dateRappel7Jour')->setLabel('Rappel 7e Jours'));
}
public function configureActions(Actions $actions): Actions
{
$export = Action::new('exportAction', 'Export')
->setIcon('fa fa-download')
->linkToCrudAction('exportAction')
->setCssClass('btn')
->createAsGlobalAction();
return $actions
->add(Crud::PAGE_INDEX, $export);
}
public function exportAction(Request $request): Response
{
$context = $this->_getEasyAdminRefererContext($request);
$searchDto = $this->_adminContextFactory->getSearchDto($request, $context->getCrud());
$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
$filters = $this->get(FilterFactory::class)->create($context->getCrud()->getFiltersConfig(), $fields, $context->getEntity());
$result = $this->createIndexQueryBuilder(
$searchDto, $context->getEntity(), $fields, $filters
)
->getQuery()->getResult();
$data = [];
/**
* #var $record FicheEntity
*/
foreach ($result as $record) {
$data[] = [
'Nom Complet' => $record->getFullname(),
'Chambre' => $record->getChambre(),
'Date Debut' => $record->getDateDebut()->format('y-m-d'),
'Duree ATB' => $record->getDureeJour(),
'Nom ATB' => $record->getNomAntibio(),
'Rappel 3e Jour' => ($record->getDateRappel3Jour() !== null ? $record->getDateRappel3Jour()->format('y-m-d') : $record->getDateRappel3Jour()),
'Réévalué' => ($record->getDateRappel3Jour() !== null ? ($record->getReevalue() === true ? 'oui' : 'non') : ''),
'Rappel 7e Jour' => ($record->getDateRappel7Jour() !== null ? $record->getDateRappel7Jour()->format('y-m-d') : $record->getDateRappel7Jour()),
'Justifié' => ($record->getDateRappel7Jour() !== null ? ($record->getJustifie() === true ? 'oui' : 'non') : ''),
'Pathologie' => $record->getPathologie(),
'Hospitalier' => ($record->getHospitalier() === true ? 'oui' : '')
];
}
$filename = 'export_fiche_' . date_create()->format('d-m-y H:i:s') . '.csv';
$serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder()]);
$response = new Response($serializer->encode($data, CsvEncoder::FORMAT));
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', "attachment; filename=\"$filename\"");
return $response;
}
private function _getEasyAdminRefererContext(Request $request)
{
\parse_str(\parse_url($request->query->get(EA::REFERRER))[EA::QUERY], $referrerQuery);
if (array_key_exists(EA::FILTERS, $referrerQuery)) {
$request->query->set(EA::FILTERS, $referrerQuery);
}
return $request->attributes->get(EA::CONTEXT_REQUEST_ATTRIBUTE);
}
public function configureFields(string $pageName): iterable
{
return [
IntegerField::new('id')->hideOnForm()->hideOnIndex(),
TextField::new('nom')->hideOnIndex()->setColumns(6),
TextField::new('prenom')->hideOnIndex()->setColumns(6),
TextField::new('fullname')->setLabel('Nom complet')->hideOnForm(),
IntegerField::new('chambre')->setColumns(4),
TextField::new('nomAntibio')->setLabel('Nom ATB')->setColumns(4),
IntegerField::new('dureeJour')->setLabel('Durée ATB TTT')->setColumns(4),
DateField::new('dateDebut'),
DateField::new('dateRappel3Jour')->setLabel('Rappel 3e Jour')->hideOnForm(),
BooleanField::new('reevalue')->setLabel('Réévalué')->hideOnForm(),
DateField::new('dateRappel7Jour')->setLabel('Rappel 7e Jour')->hideOnForm(),
BooleanField::new('justifie')->setLabel('Justifié')->hideOnForm(),
TextField::new('pathologie'),
AssociationField::new('utilisateur', 'Admin')->setLabel('Utilisateur')->hideOnForm(),
BooleanField::new('hospitalier')
];
}
My issue is that when I display my list of fiches, I want to decrypt the encrypted data, for now I try :
use the AfterEntityBuiltEvent (did not working)
listen on Event postLoad
create an custom action
but none of these are working. Does someone try something similar ?
Thanks in advance
Related
I currently have a big problem on my Symfony project since I switched to version 4.4. My versioning was correctly done but I have a "Project" page that displays all the projects created in the website database. The problem is that the project creation is feasible and the projects are well displayed in the database but the site does not display them. I checked the code of my ProjectController and everything seems to be normal. However, I changed one line of it because the syntax for calling classes through the getRepository has changed between versions 3.4 and 4.4. Before, I used to call my classes by doing getRepository('App::$className') with a className variable whose value changed depending on the classes that were called on my page. Now a getRepository doesn't accept the 'App::' and so I had to define the path of my classes by setting getRepository('App::$className'). And I have the impression that the problem can come from here because maybe it only retrieves the first class called and doesn't go to the next one.
I can't solve the problem because it's not an error message, so I'm looking for a needle in a haystack. I don't have a lot of experience with symfony because I've never used this framework before, so I came up with this project that just needed an upgrade.
I put the code of my ProjectController just below to better understand my explanation.
<?php
namespace App\Controller;
use App\Entity\Advancement;
use App\Entity\Alert;
use App\Entity\Project;
use App\Entity\State;
use App\Form\Search\ProjectSearchType;
use App\Form\Type\AdvancementType;
use App\Form\Type\AlertType;
use App\Form\Type\ProjectType;
use App\Model\ProjectSearch;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ProjectController extends BaseController
{
protected function listAction($className, $params = array())
{
return array_merge(array(
'title' => 'title.' . $className . '.list',
'pagetitle' => 'title.' . $className . '.list',
$className . 's' => $this->getRepository('App\\Entity\\' . $className)->getList(),
), $params);
}
protected function createAction($request, $project, $form, $className)
{
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$entity = $form->getData();
$entity->setCreatedBy($this->getUser());
$entity->setCreatedAt(new \DateTime());
$this->persist($entity);
$this->flush();
$this->addFlash('success', 'flash.success.created.' . $className);
return $this->redirect($this->generateUrl('project_edit', array('id' => $project->getId())) . '#tab-' . $className);
}
return array(
'form' => $form->createView(),
'title' => $this->trans('title.' . $className . '.create'),
'pagetitle' => $this->trans('title.' . $className . '.create'),
'projectLink' => $this->generateUrl('project_edit', array('id' => $project->getId())),
);
}
protected function editAction($request, $project, $form, $className, $class)
{
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$entity = $form->getData();
$entity->setUpdatedBy($this->getUser());
$entity->setUpdatedAt(new \DateTime());
$this->flush();
$this->addFlash('success', 'flash.success.updated.' . $className);
return $this->redirect($this->generateUrl('project_edit', array('id' => $project->getId())) . '#tab-' . $className);
}
return array(
'form' => $form->createView(),
'title' => $this->trans('title.' . $className . '.edit', array('%name%' => $class)),
'pagetitle' => $this->trans('title.' . $className . '.edit', array('%name%' => $class)),
'projectLink' => $this->generateUrl('project_edit', array('id' => $project->getId())),
);
}
protected function deleteAction($class, $className)
{
try {
$this->remove($class);
$this->flush();
$this->addFlash('success', 'flash.success.deleted.' . $className);
} catch (ForeignKeyConstraintViolationException $e) {
$this->addFlash('error', 'flash.error.deleted.' . $className);
}
if ($className != 'project') {
$id = $class->getProject()->getId();
$route = $this->generateUrl('project_edit', array('id' => $id)) . '#tab-' . $className;
} else {
$route = $this->generateUrl('project_list');
}
return $this->redirect($route);
}
/**
* #Route("/projects/{page}", defaults={"page":1}, name="project_list")
* #Template("Project\listProject.html.twig")
* #Security("has_role('ROLE_READER')")
*/
public function projectListAction(Request $request, $page = 1)
{
$searchModel = new ProjectSearch();
if (!$this->isGranted('ROLE_READER')) {
$searchModel->setCompany($this->getUser()->getCompany());
}
$searched = $searchModel;
$searchForm = $this->get('form.factory')->createNamed('', ProjectSearchType::class, $searchModel, array(
'method' => 'GET',
'action' => $this->generateUrl('project_list') . '#results',
));
$searchForm->handleRequest($request);
if ($searchForm->isSubmitted() && $searchForm->isValid()) {
$searched = $searchForm->getData();
}
$pager = $this->getPager($page, $this->getRepository(Project::class)->getSearchQuery($searched), $searchModel->getPerPage());
return $this->listAction('project', array(
'pager' => $pager,
'projects' => $pager->getCurrentPageResults(),
'searchForm' => $searchForm->createView(),
));
}
/**
* #Route("/project/new",name="project_create")
* #Template("Project\createProject.html.twig")
* #Security("has_role('ROLE_READER')")
*/
public function projectCreateAction(Request $request)
{
$project = new Project();
$project->setBeginAt(new \DateTime());
$project->setState($this->getRepository(State::class)->find(State::INITIALIZED));
$project->setCompany($this->getUser()->getCompany());
$form = $this->createForm(ProjectType::class, $project, array(
'mode' => 'create',
'display_company_select' => $this->isGranted('ROLE_SUPERADMIN'),
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$project = $form->getData();
$project->setCreatedBy($this->getUser());
$this->persist($project);
$this->flush();
$this->addFlash('success', 'flash.success.created.project');
return $this->redirect($this->generateUrl('project_list'));
}
return array(
'modeEdit' => false,
'form' => $form->createView(),
'title' => $this->trans('title.project.create'),
'pagetitle' => $this->trans('title.project.create'),
'project' => $project,
);
}
/**
* #Route("/project/edit/{id}", name="project_edit")
* #Template("Project\createProject.html.twig")
* #Security("is_granted('edit', project)")
*/
public function projectEditAction(Request $request, Project $project)
{
$project = $this->getManager(Project::class)->initForEdition($project);
$form = $this->createForm(ProjectType::class, $project, array(
'display_company_select' => $this->isGranted('ROLE_SUPERADMIN'),
));
try {
$alerts = $this->getRepository(Alert::class)->getAlertsByProject($project);
} catch (Exception $e) {
$alerts = array(new Alert());
}
try {
$advancements = $this->getRepository(Advancement::class)->getAdvancementsByProject($project);
} catch (Exception $e) {
$advancements = array(new Advancement());
}
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$project = $this->getManager(Project::class)->updateProject($form->getData());
$this->flush();
$this->addFlash('success', 'flash.success.updated.project');
return $this->redirect($this->generateUrl('project_list'));
}
return array(
'modeEdit' => true,
'form' => $form->createView(),
'advancements' => $advancements,
'alerts' => $alerts,
'title' => $this->trans('title.project.edit', array('%name%' => $project)),
'pagetitle' => $this->trans('title.project.edit', array('%name%' => $project)),
'project' => $project,
);
}
/**
* #Route("/project/view/{id}", name="project_view")
* #Template("viewProject.html.twig")
* #Security("is_granted('view', project)")
*/
public function projectViewAction(Request $request, Project $project)
{
return $this->projectEditAction($request, $project);
}
/**
* #Route("/project/delete/{id}", name="project_delete")
*/
public function projectDeleteAction(Request $request, Project $project)
{
// #todo : voir le delete en cascade
return $this->deleteAction($project, 'project');
}
/**
* #Route("/project/print", name="project_print")
*/
public function projectPrintAction(Request $request)
{
$projects = $this->getRepository(Project::class)->findById(array_keys($request->request->all()));
$html = '';
foreach ($projects as $project) {
$html .= $this->renderView('resume.html.twig', array(
'project' => $project,
));
}
if ($html == '') {
$this->addFlash('error', 'warn.project.check');
return $this->redirect($this->generateUrl('project_list'));
}
// Génération du pdf
$html2pdf = $this->get('html2pdf_factory')->create();
$html2pdf->WriteHTML($html);
return new Response(
$html2pdf->Output(),
200,
array(
'Content-Type' => 'application/pdf; charset=utf-8',
)
);
}
/**
* #Route("/advancements",name="advancement_list")
* #Template("listAdvancement.html.twig")
*/
public function advancementListAction(Request $request)
{
return $this->listAction('advancement');
}
/**
* #Route("/advancement/new/{id}",name="advancement_create")
* #Template("createAdvancement.html.twig")
*/
public function advancementCreateAction(Request $request, Project $project)
{
$avancement = new Advancement();
$avancement->setProject($project);
$form = $this->createForm(AdvancementType::class, $avancement, array());
return $this->createAction($request, $project, $form, 'advancement');
}
/**
* #Route("/advancement/edit/{id}", name="advancement_edit")
* #Template("createAdvancement.html.twig")
*/
public function advancementEditAction(Request $request, Advancement $advancement)
{
$form = $this->createForm(AdvancementType::class, $advancement, array());
return $this->editAction($request, $advancement->getProject(), $form, 'advancement', $advancement);
}
/**
* #Route("/advancement/delete/{id}", name="advancement_delete")
*/
public function advancementDeleteAction(Request $request, Advancement $advancement)
{
return $this->deleteAction($advancement, 'advancement');
}
/**
* #Route("/alerts",name="alert_list")
* #Template("listAlert.html.twig")
*/
public function alertListAction(Request $request)
{
return $this->listAction('alert');
}
/**
* #Route("/alert/new/{id}",name="alert_create")
* #Template("createAlert.html.twig")
*/
public function alertCreateAction(Request $request, Project $project)
{
$alerte = new Alert();
$alerte->setProject($project);
$form = $this->createForm(AlertType::class, $alerte, array());
return $this->createAction($request, $project, $form, 'alert');
}
/**
* #Route("/alert/edit/{projectid}/{alertid}", name="alert_edit")
* #ParamConverter("project", class="Project", options={"id" = "projectid"})
* #ParamConverter("alert", class="Alert", options={"id" = "alertid"})
* #Template("createAlert.html.twig")
*/
public function alertEditAction(Request $request, Project $project, Alert $alert)
{
$form = $this->createForm(AlertType::class, $alert, array());
return $this->editAction($request, $project, $form, 'alert', $alert);
}
/**
* #Route("/alert/delete/{id}", name="alert_delete")
*/
public function alertDeleteAction(Request $request, Alert $alert)
{
return $this->deleteAction($alert, 'alert');
}
/**
* #Template("_projectLoads.html.twig")
*/
public function projectLoadsAction(Request $request, $projectId)
{
$project = $this->getManager(Project::class)->getProject($projectId);
$slippingCalendar = $this->get('date.handler')->slippingCalendar();
// Returned loads can be outside start-end, so we limit to this year
$validLoads = array();
foreach ($project->getLoads() as $l) {
$id = $l->getUser()->getId();
$year = $l->getYear();
if (!array_key_exists($id, $validLoads)) {
$validLoads[$id] = array('user' => $l->getUser());
}
$validLoads[$id][$year][] = $l;
}
$activities = $this->getActivitiesByMonth($project);
return array(
'project' => $project,
'loads' => $validLoads,
'activities' => $activities,
'slippingCalendar' => $slippingCalendar, // yyyy-11-01, yyyy-12-01, yyyy-01-01,...
);
}
/**
* Build an array with the project activies spread by month and year
* #param Project $project
* #return array
*/
protected function getActivitiesByMonth(Project $project)
{
$validActivities = array();
foreach ($project->getActivities() as $a) {
$id = $a->getUser()->getId();
$date = $a->getMondayDate();
$i = 0;
do {
$year = $date->format('Y');
$month = $date->format('m');
if (!array_key_exists($id, $validActivities)) {
$validActivities[$id] = array('user' => $a->getUser());
}
if (!array_key_exists($year, $validActivities[$id])) {
$validActivities[$id][$year] = array();
}
$validActivities[$id][$year][$month][] = $a->getTimeDay($i);
$date->modify('+1 day');
$i++;
} while ($i < 7);
}
return $validActivities;
}
}
I am looking to see the projects in the database reappear on my web page.
The table is empty, although it should be populated by the projects in the DB.
This question already has answers here:
Laravel 5.4 field doesn't have a default value
(10 answers)
Closed 1 year ago.
Good afternoon to y'all!
Somewhere in the past week, I changed something in the website that caused the following error:
SQLSTATE[HY000]: General error: 1364 Field 'identifier' doesn't have a default value (SQL: insert into `classifieds` (`vehicle_id`, `vehicle_type`, `updated_at`, `created_at`) values (19983, App\Models\Car, 2021-04-27 16:27:56, 2021-04-27 16:27:56))
It's is very weird, because the $fillable is set (and it worked before).
This is the content being used:
Classified Model:
<?php
namespace App\Models;
use App\Http\Controllers\Controller;
use App\Rules\FileUploader;
use App\Rules\VehicleRegDate;
use Auth;
use Cache;
use CyrildeWit\EloquentViewable\Contracts\Viewable;
use CyrildeWit\EloquentViewable\InteractsWithViews;
use Eloquent;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Rennokki\QueryCache\Traits\QueryCacheable;
use ShiftOneLabs\LaravelCascadeDeletes\CascadesDeletes;
use Throwable;
/**
* App\Models\Classified
*
* #property int $id
* #property string $identifier
* #property int|null $vehicle_id
* #property string|null $vehicle_type
* #property int $proprietor_id
* #property string $proprietor_type
* #property float $price
* #property Carbon|null $created_at
* #property Carbon|null $updated_at
* #property-read Collection|Equipment[] $equipments
* #property-read int|null $equipments_count
* #property-read Collection|Media[] $medias
* #property-read int|null $medias_count
* #property-read Model|Eloquent $proprietor
* #property-read Model|Eloquent $vehicle
* #method static Builder|Classified newModelQuery()
* #method static Builder|Classified newQuery()
* #method static Builder|Classified query()
* #method static Builder|Classified whereCreatedAt($value)
* #method static Builder|Classified whereId($value)
* #method static Builder|Classified whereIdentifier($value)
* #method static Builder|Classified wherePrice($value)
* #method static Builder|Classified whereProprietorId($value)
* #method static Builder|Classified whereProprietorType($value)
* #method static Builder|Classified whereUpdatedAt($value)
* #method static Builder|Classified whereVehicleId($value)
* #method static Builder|Classified whereVehicleType($value)
* #mixin Eloquent
* #property string|null $identifier_old
* #property float $lat
* #property float $lng
* #property string|null $video_embed
* #property int|null $phone
* #property int|null $type
* #property int $status
* #property-read Collection|Advertising[] $adverts
* #property-read int|null $adverts_count
* #property-read Collection|Feature[] $features
* #property-read int|null $features_count
* #property-read Collection|Message[] $messages
* #property-read int|null $messages_count
* #property-read Collection|PriceOption[] $price_options
* #property-read int|null $price_options_count
* #property-read Sharing|null $sharing
* #method static Builder|Classified whereIdentifierOld($value)
* #method static Builder|Classified whereLat($value)
* #method static Builder|Classified whereLng($value)
* #method static Builder|Classified wherePhone($value)
* #method static Builder|Classified whereStatus($value)
* #method static Builder|Classified whereType($value)
* #method static Builder|Classified whereVideoEmbed($value)
*/
class Classified extends Model implements Viewable
{
use CascadesDeletes, QueryCacheable, InteractsWithViews;
const STATUS_INACTIVE = 0;
const STATUS_ACTIVE = 1;
const STATUS_PENDING = 2;
const STATUS_RETOUCH = 3;
const STATUS_ARCHIVED = 4;
const STATUS_REFUSED = 5;
const STATUS_EXPIRED = 6;
protected static $flushCacheOnUpdate = true;
public $cacheFor = 86400;
protected $fillable = [
'identifier',
'identifier_old',
'proprietor_id',
'proprietor_type',
'price',
'lat',
'lng',
'video_embed',
'phone',
'type',
'status',
'created_at',
'updated_at'
];
protected $hidden = [
'id',
'identifier_old',
'proprietor_id',
'proprietor_type',
'vehicle_id',
'vehicle_type',
'lat',
'lng',
'phone',
];
protected array $cascadeDeletes = ['medias', 'equipments', 'features', 'price_options', 'messages', 'adverts', 'sharing'];
public array $rules = [
'classified',
'car',
'motorcycle',
'bike'
];
public function __construct()
{
$this->rules['classified'] = [
'vehicle_type' => 'required|alpha|in:car,motorcycle,bike',
'type' => 'required|integer|exists:vehicle_data,id',
'price' => 'required|numeric|min:1',
'price_options.*' => 'nullable|integer|min:1',
'features.*' => 'nullable|integer|exists:vehicle_data,id',
'equipments.*' => 'nullable|integer|exists:vehicle_data,id',
'fileuploader-list-files' => ['required', 'json', new FileUploader],
'phone' => 'nullable|numeric|digits:9',
'address' => 'nullable|string',
'terms' => 'required|boolean',
];
$this->rules['car'] = [
'make' => 'required|integer|exists:vehicle_data,id',
'model' => 'required|integer|exists:vehicle_data,id',
'version' => 'nullable|string',
'fuel' => 'required|integer|exists:vehicle_data,id',
'firstRegDate' => ['required', new VehicleRegDate()],
'mileage' => 'required|integer|min:0',
'displacement' => 'required|integer|min:1',
'power_kw' => 'nullable|integer|min:1',
'power_hp' => 'nullable|integer|min:1',
'bodyType' => 'required|integer|exists:vehicle_data,id',
'bodyColour' => 'required|integer|exists:vehicle_data,id',
'vin' => 'nullable|string|min:17|max:17',
'annotations' => 'nullable|string',
'transmission' => 'nullable|integer|exists:vehicle_data,id',
'gears' => 'nullable|integer|exists:vehicle_data,id',
'doors' => 'nullable|integer|exists:vehicle_data,id',
'seats' => 'nullable|integer|exists:vehicle_data,id',
'vehicle_class' => 'nullable|integer|exists:vehicle_data,id',
'driveTrainType' => 'nullable|integer|exists:vehicle_data,id',
'maxFuelRange' => 'nullable|numeric|min:1',
'emission' => 'nullable|numeric|min:0.01',
'iuc' => 'nullable|numeric|min:1',
'particleFilter' => 'nullable|boolean',
'warrantyDate' => 'nullable|date_format:d-m-Y',
'warrantyKM' => 'nullable|integer|min:1',
'inspectionDate' => 'nullable|date_format:d-m-Y',
'registries' => 'nullable|integer|exists:vehicle_data,id',
'origin' => 'nullable|integer|exists:vehicle_data,id',
'license' => 'nullable|string',
'fuelConsumptionCity' => 'nullable|numeric|min:1',
'fuelConsumptionHighway' => 'nullable|numeric|min:1',
'fuelConsumptionAverage' => 'nullable|numeric|min:1',
'vintage' => 'nullable|boolean',
'video_embed' => 'nullable|string'
];
$this->rules['bike'] = [
'framework' => 'nullable|string',
'wheel-size' => 'nullable|numeric|min:1',
'material' => 'nullable|string',
'suspension' => 'nullable|string',
'suspension-travel' => 'nullable|string',
'shock-absorber' => 'nullable|string',
'damping-travel' => 'nullable|string',
'type-of-brake' => 'nullable|string',
'brakes' => 'nullable|string',
'speeds' => 'nullable|string',
'gearshift-lever' => 'nullable|string',
'rear-change' => 'nullable|string',
'casset' => 'nullable|string',
'chain' => 'nullable|string',
'pedal' => 'nullable|string',
'roses' => 'nullable|string',
'cubes' => 'nullable|string',
'tires' => 'nullable|string',
'steering-gearbox' => 'nullable|string',
'advance' => 'nullable|string',
'guideline' => 'nullable|string',
'fingers' => 'nullable|string',
'saddle' => 'nullable|string',
'seat-post' => 'nullable|string',
'brand' => 'nullable|string',
'warranty' => 'nullable|string',
'hard-tail-full-suspension' => 'nullable|string',
'year' => 'nullable|integer|min:1990|max:' . date('Y'),
'engine' => 'nullable|string',
'battery' => 'nullable|string',
];
parent::__construct();
}
public function proprietor(): MorphTo
{
return $this->morphTo();
}
public function vehicle(): MorphTo
{
return $this->morphTo();
}
public function equipments(): BelongsToMany
{
return $this->belongsToMany(VehicleData::class, 'classified_equipment', 'classified_id', 'equipment_id');
}
public function features(): BelongsToMany
{
return $this->belongsToMany(VehicleData::class, 'classified_feature', 'classified_id', 'feature_id');
}
public function price_options(): BelongsToMany
{
return $this->belongsToMany(VehicleData::class, 'classified_price_option', 'classified_id', 'price_option_id');
}
public function messages(): HasMany
{
return $this->hasMany(Message::class);
}
public function adverts(): HasMany
{
return $this->hasMany(Advertising::class);
}
public function sharing(): MorphOne
{
return $this->morphOne(Sharing::class, 'object');
}
public function medias(): MorphMany
{
return $this->morphMany(Media::class, 'mediable');
}
public function getFeaturedMedia($size = null): string
{
try {
if ($media = $this->medias()->orderBy('index', 'ASC')->first())
return $media->getMediaRoute($size);
if ($this->video_embed)
return sprintf("https://i.ytimg.com/vi/%s/hqdefault.jpg", $this->video_embed);
throw new Exception();
} catch (Throwable $exception) {
return asset_cdn('assets/img/default_listing.jpg');
}
}
public function getRoute(): string
{
return route("classified.show", [$this->identifier, $this->getSlug()]);
}
public function getSlug(): string
{
return Str::slug($this->getTitle());
}
public function getTitle($size = null)
{
try {
if ($this->isOtherMake() && $this->isOtherModel())
$title = $this->vehicle->version;
elseif ($this->isOtherMake())
$title = $this->getModelName() . " " . $this->vehicle->version;
else
$title = $this->getMakeName() . " " . $this->getModelName() . " " . $this->vehicle->version;
if ($size)
return Str::limit($title, $size);
return $title;
} catch (Throwable $exception) {
return $this->vehicle->version;
}
}
public function getVehicleType(): ?string
{
try {
return strtolower(explode("\\", $this->vehicle_type)[2]);
} catch (Throwable $exception) {
return null;
}
}
public function getMakeName()
{
try {
return (new Controller())->getVehicleMakeByAttr($this->getVehicleType(), $this->vehicle->make, 'id', 'value');
} catch (Throwable $exception) {
return null;
}
}
public function getMakeNameOld()
{
try {
return config('constants.' . $this->getVehicleType() . '.makes.' . $this->vehicle->make);
} catch (Throwable $exception) {
return null;
}
}
public function getModelName()
{
try {
return (new Controller())->getVehicleModelByModelAttr($this->getVehicleType(), $this->vehicle->make, $this->vehicle->model, 'id', 'value');
} catch (Throwable $exception) {
return null;
}
}
public function getModelNameOld()
{
try {
return config('constants.' . $this->getVehicleType() . '.models.' . $this->vehicle->make . '.' . $this->vehicle->model);
} catch (Throwable $exception) {
return null;
}
}
public function getFirstRegDate()
{
try {
return Carbon::parse($this->vehicle->firstRegDate);
} catch (Throwable $exception) {
return Carbon::parse($this->vehicle->firstRegDate);
}
}
public function getFuelType()
{
$fuelType = Cache::get(sprintf("vehicle_data_%s_%s_%s_leaf", "classified", "fuel", $this->vehicle->fuel));
try {
return $fuelType->value;
} catch (Throwable $exception) {
return "Outro";
}
}
public function getVersion($size = null)
{
try {
if ($size)
return Str::limit($this->vehicle->version, $size);
else
return $this->vehicle->version;
} catch (Throwable $exception) {
return null;
}
}
public function getFormattedNumber($number, $decimal = 0)
{
return number_format($number, $decimal, ',', ' ');
}
public function getBodyTypeName()
{
try {
$bodyType = Cache::get(sprintf("vehicle_data_%s_%s_%s", $this->getVehicleType(), "bodyTypes", $this->vehicle->bodyType));
return $bodyType->first()->value;
} catch (Throwable $exception) {
return "Outro";
}
}
public function getBodyColourName() // Fix
{
try {
$object = VehicleData::findOrFail($this->vehicle->bodyColour);
return $object->value;
} catch (Throwable $exception) {
return "Outro";
}
}
public function getTransmissionName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->transmission);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getGearsNumber()
{
try {
$object = VehicleData::findOrFail($this->vehicle->gears);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getDoorsNumber()
{
try {
$object = VehicleData::findOrFail($this->vehicle->doors);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getClassName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->vehicle_class);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getOriginName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->origin);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getLicenseFormated()
{
try {
$license = strtoupper($this->vehicle->license);
if (strlen($license) == 6) {
$parts = str_split($license, 2);
return implode('-', $parts);
}
return $license;
} catch (Throwable $exception) {
return "00-00-00";
}
}
public function getDriveTrainTypeName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->driveTrainType);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getDateFormated($date)
{
return Carbon::parse($date)->format('d-m-Y');
}
public function getDateStatus($date)
{
if (Carbon::parse($this->vehicle->$date) >= Carbon::today()->addDays(30))
return "warning";
elseif (Carbon::parse($this->vehicle->$date) < Carbon::today())
return "danger";
else
return "info";
}
public function getVehicleTypeClassByName($name, $class = null)
{
switch ($name) {
case "car":
if (!$class)
return "App\Models\Car";
else
return Car::class;
case "motorcycle":
if (!$class)
return "App\Models\Motorcycle";
else
return Motorcycle::class;
default:
return null;
}
}
public function getVehicleTypeByClass()
{
switch ($this->vehicle_type) {
case Car::class:
return 'car';
case Motorcycle::class:
return 'motorcycle';
default:
return null;
}
}
public function getVehicleTypeNameByClass()
{
switch ($this->vehicle_type) {
case Car::class:
return 'Carro';
case Motorcycle::class:
return 'Moto';
default:
return null;
}
}
public function getPhoneViews()
{
return 0;
}
public function getStatusElements()
{
return config('constants.status.' . $this->status);
}
public function getAddress()
{
try {
return (new Controller())->getAddressFromGeoPosition($this->lat, $this->lng, 'city');
} catch (Throwable $exception) {
return "";
}
}
public function getArticleCategory()
{
switch ($this->vehicle_type) {
case Car::class:
return 1;
case Motorcycle::class:
return 2;
default:
return null;
}
}
public function isOtherMake(): bool
{
try {
$controller = new Controller();
if ($this->vehicle->make == $controller->getVehicleMakeOtherByVTypeAttr($this->getVehicleType(), 'slug', 'id'))
return true;
return false;
} catch (Throwable $exception) {
return false;
}
}
public function isOtherModel(): bool
{
try {
if ($this->vehicle->model == 0)
return true;
return false;
} catch (Throwable $exception) {
return false;
}
}
public function flushCache()
{
try {
Cache::forget('classified_' . $this->identifier);
Cache::forget('medias_classified_' . $this->identifier);
Cache::remember('classified_' . $this->identifier, 33600, function () {
return $this;
});
Cache::remember('medias_classified_' . $this->identifier, 33600, function () {
return $this->medias()->orderBy('index', 'ASC')->get();
});
} catch (Throwable $exception) {
}
}
public function isProprietor()
{
try {
if (Auth::check()) {
if (session()->has('professional_user') && $this->proprietor_type == Branch::class && $this->proprietor_id == session()->get('professional_user'))
return true;
elseif ($this->proprietor_type == User::class && $this->proprietor_id == Auth::id())
return true;
elseif (Auth::user()->isAdmin())
return true;
}
} catch (Throwable $exception) {
return false;
}
}
public function getFavourites()
{
try {
return $this->favourites->count();
} catch (Throwable $exception) {
return 0;
}
}
public function isMyFavourite(): bool
{
try {
$controller = new Controller();
if ($this->favourites()->where([
'proprietor_id' => $controller->getProprietorId(),
'proprietor_type' => $controller->getProprietorType()
])->count() > 0)
return true;
} catch (Throwable $exception) {
}
return false;
}
public function favourites()
{
return $this->hasMany(ClassifiedFavourite::class);
}
}
store method:
public function store(Request $request): JsonResponse
{
$rules = (new Classified)->rules;
$request->validate($rules['classified']);
$request->validate($rules[$request->input('vehicle_type')]);
DB::beginTransaction();
try {
$vehicleData = $request->all();
$vehicleData['firstRegDate'] = Carbon::createFromFormat('m-Y', $vehicleData['firstRegDate'])->toDateString();
$vehicle = (new Classified())->getVehicleTypeClassByName($request->input('vehicle_type'))::create($vehicleData);
if ($request->has('address'))
$geoData = $this->getGeoPositionFromAddress($request->input('address'));
else
$geoData = (object)[
"lat" => 0,
"lng" => 0
];
$formData = $request->all();
$formData['identifier'] = $this->generateIdentifier();
$formData['proprietor_id'] = $this->getProprietorId();
$formData['proprietor_type'] = $this->getProprietorType();
$formData['lat'] = $geoData->lat;
$formData['lng'] = $geoData->lng;
$formData['video_embed'] = $this->getYoutubeVideoID($request->input('video_embed'));
$formData['status'] = Classified::STATUS_PENDING;
$classified = $vehicle->classified()->create($formData);
$vehicle->classified->price_options()->attach($request->input('price_options'));
$vehicle->classified->features()->attach($request->input('features'));
$vehicle->classified->equipments()->attach($request->input('equipments'));
$medias = json_decode($request->{'fileuploader-list-files'}, true);
foreach ($medias as $media) {
$file = Media::where('name', $media->file)->first();
if ($file) {
$file->mediable_id = $vehicle->classified->id;
$file->saveOrFail();
}
}
if ($formData['proprietor_type'] == User::class && $request->has('phone') && $request->has('address'))
$this->updateUserPhoneAndAddress($formData['phone'], $formData['address']);
$classified->sharing()->create([
'status' => Sharing::STATUS_PENDING,
]);
if ($classified->status == Classified::STATUS_PENDING)
$this->adminAlert($classified);
DB::commit();
toastr()->success("Anúncio submetido para aprovação.");
return response()->json([
'redirect_url' => route('classified.feature', $vehicle->classified->identifier),
]);
} catch (Throwable $exception) {
DB::rollBack();
return response()->json([
'errors' => [trans('custom.error_occurred'), $exception->getMessage()]
], 500);
}
}
Stack Error: https://pastebin.com/jPypBG8P
Anyone has any idea on may be causing this?
Apparently it was the constructor in the Classified Model that was preventing.
A special Thanks to #Tim Lewis !
I'm using an eventSubscriber to dynamically load a field (Paciente) into a form, in its preSubmit function I need to get in addition to the ID of the paciente, the dni of paciente. The id I can get directly, but the dni need to bring the entity, and I do not know how I can do it from here.
My event in question is as follows:
class AddHistoriaClinicaFieldSubscriber implements EventSubscriberInterface
{
private $propertyPathToHistoriaClinica;
public function __construct($propertyPathToHistoriaClinica)
{
$this->propertyPathToHistoriaClinica = $propertyPathToHistoriaClinica;
}
public static function getSubscribedEvents()
{
return array(
FormEvents::POST_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit'
);
}
private function addHistoriaClinicaForm($form, $paciente_id)
{
$formOptions = array(
'class' => 'BiobancoBundle:HistoriaClinica',
'empty_value' => '-- SELECCIONAR HISTORIA CLINICA --',
'label' => 'Historia Clínica',
'attr' => array(
'class' => 'historia_clinica_selector',
),
'query_builder' => function (EntityRepository $repository) use ($paciente_id) {
$qb = $repository->createQueryBuilder('h')
->innerJoin('h.paciente', 'p')
->where('p.id = :p')
->setParameter('p', $paciente_id)
;
return $qb;
},
);
$form->add($this->propertyPathToHistoriaClinica, 'entity', $formOptions);
}
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
$accessor = PropertyAccess::createPropertyAccessor();
$h = $accessor->getValue($data, $this->propertyPathToHistoriaClinica);
$paciente_id = ($h) ? $h->getPaciente()->getNumeroIdentificacion() : null;
$this->addHistoriaClinicaForm($form, $paciente_id);
}
public function preSubmit(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
$paciente_id = array_key_exists('paciente', $data) ? $data['paciente'] : null;
//HERE IS WHERE I NEED TO OBTAIN THE DNI, TO PASS IT TO THE FORM
//dump($data);die();
$this->addHistoriaClinicaForm($form, $paciente_id);
}
}
EDIT 1 OF METHOD preSubmit with LifecycleEventArgs :
use Doctrine\ORM\Event\LifecycleEventArgs;
...
public function preSubmit(FormEvent $event, LifecycleEventArgs $args)
{
$data = $event->getData();
$form = $event->getForm();
$paciente_id = array_key_exists('paciente', $data) ? $data['paciente'] : null;
dump($args->getEntityManager()->getRepository("BiobancoBundle:Paciente")->find($paciente_id));die();
$this->addHistoriaClinicaForm($form, $paciente_id);
}
ERROR in line declaration of method:
Catchable Fatal Error: Argument 2 passed to BiobancoBundle\Form\EventListener\AddHistoriaClinicaFieldSubscriber::preSubmit() must be an instance of Doctrine\ORM\Event\LifecycleEventArgs, string given.
create a factory to inject the EntityManager or Repository into your subscriber.
class AddHistoriaClinicaFieldSubscriberFactory
{
public static function create($entityManager)// typehint this
{
// You could retrieve the repo here, so you don't pass the whole em to the instance
$instance = new AddHistoriaClinicaFieldSubscriber($entityManager);
// ...
return $instance;
}
}
Register it
# app/config/services.yml
services:
# ...
app.add_historia_clinica_field_subscriber_factory:
class: YOURNAMESPACE\AddHistoriaClinicaFieldSubscriberFactory
app.add_historia_clinica_field_subscriber:
class: YOURNAMESPACE\AddHistoriaClinicaFieldSubscriber
factory: 'add_historia_clinica_field_subscriber_factory:create'
arguments: ['#doctrine.orm.default_entity_manager']
tags:
- { name: WHATEVERYOUHAVEHERE }
And add a constructor to you Subscriber
class AddHistoriaClinicaFieldSubscriber implements EventSubscriberInterface
{
// ...
protected $entityManager;
public function __construct($entityManager) {// typehint this
$this->entityManager = $entityManager;
}
// ...
}
Let me know if this is clear enough
For more info check: http://symfony2-document.readthedocs.io/en/latest/cookbook/service_container/factories.html
My code is working prefectly on sending http request and in case a website is down or a response code is not 200, it sends a slack notification. What I am trying to figure out now is, in the notifications table I have check_frequency and alert_frequence. If a website is down, instead of using check frequency to calculate the elapse time, it should use alert_frequence.
namespace App\Http\Controllers;
use GuzzleHttp\Client;
use App\Utilities\Reporter;
use GuzzleHttp\Exception\ClientException;
use App\Notification;
use App\Status;
use App\Setting;
class GuzzleController extends Controller
{
private $default_check_frequency;
protected $client;
protected $reporter;
public function __construct()
{
$this->client = new Client;
$this->reporter = new Reporter;
$this->default_check_frequency = Setting::defaultCheckFrequency();
}
public function status()
{
$notifications = Notification::where('active', 1)->get();
$status = Status::where('name', 'health')->first();
foreach ($notifications as $notification) {
$this->updateStatus($notification, $status);
}
}
private function updateStatus(Notification $notification, Status $status)
{
$status_health = $notification->status('health');
$frequency = $this->getFrequency($notification);
$elapsed_time = \Carbon\Carbon::parse($status_health['timestamp'])->diffInMinutes();
if($elapsed_time >= $frequency) {
$response = $this->client->get($notification->website_url, [
'http_errors' => false
]);
$resCode = $response->getStatusCode();
$notification->statuses()->attach($status, [
'values' => $resCode === 200 ? 'up' : 'down'
]);
if($resCode != 200){
/* how to send slack to different slach channels, now it is sending only to one channel!*/
$this->reporter->slack($notification->website_url.':'.' is down'. ' please check your email for the status code!'.' #- '.$notification->email,
$notification->slack_channel);
$this->reporter->mail($notification->email,$resCode );
}
}
}
private function getFrequency(Notification $notification)
{
return isset($notification->check_frequency)
? intval($notification->check_frequency)
: $this->default_check_frequency;
}
}
I'm not sure this is what you need, but here's what you can do to select a different column from your table, depending on the status:
<?php
class GuzzleController extends Controller
{
private $default_check_frequency;
protected $client;
protected $reporter;
public function __construct()
{
$this->client = new Client;
$this->reporter = new Reporter;
$this->default_check_frequency = Setting::defaultCheckFrequency();
}
public function status()
{
$notifications = Notification::where('active', 1)->get();
$status = Status::where('name', 'health')->first();
foreach ($notifications as $notification) {
$this->updateStatus($notification, $status);
}
}
private function updateStatus(Notification $notification, Status $status)
{
$status_health = $notification->status('health');
/// move it here
$response = $this->client->get($notification->website_url, [
'http_errors' => false
]);
$resCode = $response->getStatusCode();
/// --- end
$frequency = $this->getFrequency($notification, $resCode);
$elapsed_time = \Carbon\Carbon::parse($status_health['timestamp'])->diffInMinutes();
if($elapsed_time >= $frequency) {
$notification->statuses()->attach($status, [
'values' => $resCode === 200 ? 'up' : 'down'
]);
if($resCode != 200){
/* how to send slack to different slach channels, now it is sending only to one channel!*/
$this->reporter->slack($notification->website_url.':'.' is down'. ' please check your email for the status code!'.' #- '.$notification->email,
$notification->slack_channel);
$this->reporter->mail($notification->email,$resCode );
}
}
}
private function getFrequency(Notification $notification, $resCode)
{
/// -- select your column here
$column = $resCode == '200' ? 'check_frequency' : 'alert_frequence';
return isset($notification->{$column})
? intval($notification->{$column})
: $this->default_check_frequency;
}
}
And I took the liberty to refactor it, separating method concerns:
<?php
use Carbon\Carbon;
class GuzzleController extends Controller
{
private $default_check_frequency;
protected $client;
protected $reporter;
public function __construct()
{
$this->client = new Client;
$this->reporter = new Reporter;
$this->default_check_frequency = Setting::defaultCheckFrequency();
}
private function addStatusToNotification(Notification $notification, Status $status, $resCode)
{
$notification->statuses()->attach($status, [
'values' => $resCode === 200
? 'up'
: 'down'
]);
}
private function report(Notification $notification, $resCode)
{
/* how to send slack to different slach channels, now it is sending only to one channel!*/
$this->reporter->slack($notification->website_url . ':' . ' is down' . ' please check your email for the status code!' . ' #- ' . $notification->email,
$notification->slack_channel);
$this->reporter->mail($notification->email, $resCode);
}
private function sendNotification(Notification $notification, Status $status, $status_health, $frequency, $resCode)
{
$elapsed_time = Carbon::parse($status_health['timestamp'])->diffInMinutes();
if ($elapsed_time >= $frequency) {
$this->addStatusToNotification($notification, $status, $resCode);
if ($resCode != 200) {
$this->report($notification, $resCode);
}
}
}
public function status()
{
$notifications = Notification::where('active', 1)->get();
$status = Status::where('name', 'health')->first();
foreach ($notifications as $notification) {
$this->updateStatus($notification, $status);
}
}
private function updateStatus(Notification $notification, Status $status)
{
$resCode = $this->getStatusCode($notification->website_url);
$this->sendNotification(
$notification,
$status,
$notification->status('health'),
$this->getFrequency($notification, $resCode),
$resCode
);
}
private function getFrequency(Notification $notification, $resCode)
{
$column = $resCode == '200' ? 'check_frequency' : 'alert_frequence';
return isset($notification->{$column})
? intval($notification->{$column})
: $this->default_check_frequency;
}
private function getStatusCode($url)
{
$response = $this->client->get($url, [
'http_errors' => false
]);
return $response->getStatusCode();
}
}
I'm building an API using FOSRestBundle for adding products to a basket. For the sake of keeping this example simple we have a range of products which come in different sizes.
I'd like to be able to specify the size code in the JSON request. For example:
{
"product": 3,
"size": "S"
}
(I'd also like to use the product code instead of the database ID, but that's for another day!)
Other parts of the project I have done similar tasks using data transformers, but these were simpler forms where the values didn't change based on other fields selected values.
So my current basket form...
class BasketAddType extends AbstractType
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'entity', [
'class' => 'CatalogueBundle:Product',
]);
$builder->get('product')->addEventListener(FormEvents::POST_SUBMIT, [$this, 'onPostSubmit']);
}
public function onPostSubmit(FormEvent $event)
{
// this will be Product entity
$form = $event->getForm();
$this->addElements($form->getParent(), $form->getData());
}
protected function addElements(FormInterface $form, Product $product = null)
{
if (is_null($product)) {
$sizes = [];
} else {
$sizes = $product->getSizes();
}
$form
->add('size', 'size', [
'choices' => $sizes
]);
}
public function getName()
{
return '';
}
}
The custom size form type I'm using above is so I can add the model transformer. As found in this answer https://stackoverflow.com/a/19590707/3861815
class SizeType extends AbstractType
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer(new SizeTransformer($this->em));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'class' => 'CatalogueBundle\Entity\Size'
]);
}
public function getParent()
{
return 'entity';
}
public function getName()
{
return 'size';
}
}
And finally the transformer.
class SizeTransformer implements DataTransformerInterface
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function transform($size)
{
if (null === $size) {
return '';
}
return $size->getCode();
}
public function reverseTransform($code)
{
// WE NEVER GET HERE?
$size = $this->em->getRepository('CatalogueBundle:Size')
->findOneByCode($code);
if (null === $size) {
throw new TransformationFailedException('No such size exists');
}
return $size;
}
}
So I did a quick exit; in reverseTransform and it's never fired so I will always get an error on the size element about it being invalid.
What would be the best way to getting a data transformer onto the size field here?
So the problem was that I was using an entity type instead of a text type when using the model data transformer.
Here is my working code albeit probably not perfect, the primary form
class BasketAddType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'entity', [
'class' => 'CatalogueBundle:Product'
]);
$builder->get('product')->addEventListener(FormEvents::POST_SUBMIT, [$this, 'onPostSubmit']);
}
public function onPostSubmit(FormEvent $event)
{
$form = $event->getForm()->getParent();
$product = $event->getForm()->getData();
$form
->add('size', 'size', [
'sizes' => $product->getSizes()->toArray() // getSizes() is an ArrayCollection
);
}
public function getName()
{
return '';
}
}
My custom form size type which applies the model transformer with the provided size options.
class SizeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer(new SizeTransformer($options['sizes']));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setRequired([
'sizes'
]);
}
public function getParent()
{
return 'text';
}
public function getName()
{
return 'size';
}
}
And finally the size transformer.
class SizeTransformer implements DataTransformerInterface
{
protected $sizes;
public function __construct(array $sizes)
{
$this->sizes = $sizes;
}
public function transform($size)
{
if (null === $size) {
return '';
}
return $size->getCode();
}
public function reverseTransform($code)
{
foreach ($this->sizes as $size) {
if ($size->getCode() == $code) {
return $size;
}
}
throw new TransformationFailedException('No such size exists');
}
}
This solution wouldn't work too well if there were a high number of sizes available for each product. Guess if that was the case I'd need to pass both the EntityManager and the product into the transformer and query the DB accordingly.
This is a dependent fields
I have a Product entity wich in relation with a Category entity which in relation with a Collection entity
here is my code for the add product form
class ProductsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$propertyPathToCategory = 'category';
$builder
->add('title')
->add('description','textarea')
->add('collection','entity', array(
'class' => 'FMFmBundle:Collections',
'empty_value' => 'Collection',
'choice_label' => 'title'
))
->addEventSubscriber(new AddCategoryFieldSubscriber($propertyPathToCategory));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'FM\FmBundle\Entity\Products'
));
}
public function getName()
{
return 'fm_fmbundle_products';
}
}
the AddCategoryFieldSubscriber
//Form/EventListener
class AddCategoryFieldSubscriber implements EventSubscriberInterface
{
private $propertyPathToCategory;
public function __construct($propertyPathToCategory)
{
$this->propertyPathToCategory = $propertyPathToCategory;
}
public static function getSubscribedEvents()
{
return array(
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit'
);
}
private function addCategoryForm($form, $collection_id)
{
$formOptions = array(
'class' => 'FMFmBundle:Categories',
'empty_value' => 'Category',
'label' => 'Category',
'attr' => array(
'class' => 'Category_selector',
),
'query_builder' => function (EntityRepository $repository) use ($collection_id) {
$qb = $repository->createQueryBuilder('category')
->innerJoin('category.collection', 'collection')
->where('collection.id = :collection')
->setParameter('collection', $collection_id)
;
return $qb;
}
);
$form->add($this->propertyPathToCategory, 'entity', $formOptions);
}
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
$accessor = PropertyAccess::createPropertyAccessor();
$category = $accessor->getValue($data, $this->propertyPathToCategory);
$collection_id = ($category) ? $category->getCollection()->getId() : null;
$this->addCategoryForm($form, $collection_id);
}
public function preSubmit(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
$collection_id = array_key_exists('collection', $data) ? $data['collection'] : null;
$this->addCategoryForm($form, $collection_id);
}
}
add new action in the controller
public function SelectCategoryAction(Request $request)
{
$collection_id = $request->get('collecton_id');
$em = $this->getDoctrine()->getManager();
$categories = $em->getRepository('FMFmBundle:Categories')->findByCollection($collection_id);
$Jcategories=array();
foreach($categories as $category){
$Jcategories[]=array(
'id' => $category->getId(),
'title' => $category->getTitle()
);
}
return new JsonResponse($Jcategories);
}
add new route for the action
select_category:
path: /selectcategory
defaults: { _controller: FMFmBundle:Product:SelectCategory }
and some ajax
$("#collectionSelect").change(function(){
var data = {
collecton_id: $(this).val()
};
$.ajax({
type: 'post',
url: 'selectcategory',
data: data,
success: function(data) {
var $category_selector = $('#categorySelect');
$category_selector.empty();
for (var i=0, total = data.length; i < total; i++)
$category_selector.append('<option value="' + data[i].id + '">' + data[i].title + '</option>');
}
});
});
References:
Dependent Forms