This commit is contained in:
2024-12-24 17:29:37 +01:00
parent e0aa499940
commit 4c08435bd8
115 changed files with 3613 additions and 152 deletions

View File

@ -39,10 +39,19 @@ class InitCommand extends Command
$io->text('Initialisation of the app');
$io->text('');
// Création du compte admin
$io->text('> Création du compte admin');
// Création d'un company par defaut
$io->text("> Création d'un company par defaut");
$company = $this->em->getRepository("App\Entity\Company")->findOneBy([], ['id' => 'ASC']);
if (!$company) {
$company = new Company();
$company->setTitle($this->params->get('appName'));
$this->em->persist($company);
$this->em->flush();
}
$user = $this->em->getRepository("App\Entity\User")->findOneBy(['username' => 'admin']);
if (!$user) {
$io->text('> Création du compte admin par defaut');
$user = new User();
$hashedPassword = $this->passwordHasher->hashPassword(
@ -54,22 +63,13 @@ class InitCommand extends Command
$user->setPassword($hashedPassword);
$user->setAvatar('medias/avatar/admin.jpg');
$user->setEmail($this->params->get('appNoreply'));
$user->addCompany($company);
$user->setCompany($company);
$this->em->persist($user);
}
$user->setRoles(['ROLE_ADMIN']);
$this->em->flush();
// Création d'un company par defaut
$io->text("> Création d'un company par defaut");
$nbcompanys = $this->em->getRepository("App\Entity\Company")->count([]);
if (0 == $nbcompanys) {
$company = new Company();
$company->setTitle($this->params->get('appName'));
$company->setLogo('logo.png');
$this->em->persist($company);
$this->em->flush();
}
return Command::SUCCESS;
}
}

View File

@ -0,0 +1,108 @@
<?php
namespace App\Controller;
use App\Entity\Accounting;
use App\Form\AccountingType;
use App\Repository\AccountingRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class AccountingController extends AbstractController
{
#[Route('/user/accounting', name: 'app_user_accounting')]
public function list(Request $request, AccountingRepository $accountingRepository): Response
{
$company = $request->getSession()->get('company');
$accountings = $accountingRepository->findBy(['company' => $company], ['num01' => 'ASC', 'num02' => 'ASC']);
return $this->render('accounting/list.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Plan Comptable',
'routesubmit' => 'app_user_accounting_submit',
'routeupdate' => 'app_user_accounting_update',
'accountings' => $accountings,
]);
}
#[Route('/user/accounting/submit', name: 'app_user_accounting_submit')]
public function submit(Request $request, EntityManagerInterface $em): Response
{
$company = $request->getSession()->get('company');
$accounting = new Accounting();
$accounting->setCompany($company);
$form = $this->createForm(AccountingType::class, $accounting, ['mode' => 'submit']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($accounting);
$em->flush();
return $this->redirectToRoute('app_user_accounting');
}
return $this->render('accounting/edit.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Création Compagnie',
'routecancel' => 'app_user_accounting',
'routedelete' => 'app_user_accounting_delete',
'mode' => 'submit',
'form' => $form,
]);
}
#[Route('/user/accounting/update/{id}', name: 'app_user_accounting_update')]
public function update(int $id, Request $request, EntityManagerInterface $em): Response
{
$company = $request->getSession()->get('company');
$accounting = $em->getRepository(Accounting::class)->find($id);
if (!$accounting || $accounting->getCompany() != $company) {
return $this->redirectToRoute('app_user_accounting');
}
$form = $this->createForm(AccountingType::class, $accounting, ['mode' => 'update']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->flush();
return $this->redirectToRoute('app_user_accounting');
}
return $this->render('accounting/edit.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Modification Compagnie = '.$accounting->getTitle(),
'routecancel' => 'app_user_accounting',
'routedelete' => 'app_user_accounting_delete',
'mode' => 'update',
'form' => $form,
]);
}
#[Route('/user/accounting/delete/{id}', name: 'app_user_accounting_delete')]
public function delete(int $id, Request $request, EntityManagerInterface $em): Response
{
$company = $request->getSession()->get('company');
$accounting = $em->getRepository(Accounting::class)->find($id);
if (!$accounting || $accounting->getCompany() != $company) {
return $this->redirectToRoute('app_user_accounting');
}
// Tentative de suppression
try {
$em->remove($accounting);
$em->flush();
} catch (\Exception $e) {
$this->addflash('error', $e->getMessage());
return $this->redirectToRoute('app_user_accounting_update', ['id' => $id]);
}
return $this->redirectToRoute('app_user_accounting');
}
}

View File

@ -2,17 +2,103 @@
namespace App\Controller;
use App\Entity\Company;
use App\Form\CompanyType;
use App\Repository\CompanyRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CompanyController extends AbstractController
{
#[Route('/admin/company', name: 'app_company')]
public function index(): Response
#[Route('/admin/company', name: 'app_admin_company')]
public function list(CompanyRepository $companyRepository): Response
{
return $this->render('company/index.html.twig', [
'controller_name' => 'CompanyController',
$companys = $companyRepository->findAll();
return $this->render('company/list.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Liste des Compagnies',
'routesubmit' => 'app_admin_company_submit',
'routeupdate' => 'app_admin_company_update',
'companys' => $companys,
]);
}
#[Route('/admin/company/submit', name: 'app_admin_company_submit')]
public function submit(Request $request, EntityManagerInterface $em): Response
{
$company = new Company();
$form = $this->createForm(CompanyType::class, $company, ['mode' => 'submit']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($company);
$em->flush();
return $this->redirectToRoute('app_admin_company');
}
return $this->render('company/edit.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Création Compagnie',
'routecancel' => 'app_admin_company',
'routedelete' => 'app_admin_company_delete',
'mode' => 'submit',
'form' => $form,
]);
}
#[Route('/admin/company/update/{id}', name: 'app_admin_company_update')]
public function update(int $id, Request $request, EntityManagerInterface $em): Response
{
$company = $em->getRepository(Company::class)->find($id);
if (!$company) {
return $this->redirectToRoute('app_admin_company');
}
$form = $this->createForm(CompanyType::class, $company, ['mode' => 'update']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->flush();
return $this->redirectToRoute('app_admin_user');
}
return $this->render('company/edit.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Modification Compagnie = '.$company->getTitle(),
'routecancel' => 'app_admin_company',
'routedelete' => 'app_admin_company_delete',
'mode' => 'update',
'form' => $form,
]);
}
#[Route('/admin/company/delete/{id}', name: 'app_admin_company_delete')]
public function delete(int $id, EntityManagerInterface $em): Response
{
// Récupération de l'enregistrement courant
$company = $em->getRepository(Company::class)->find($id);
if (!$company) {
return $this->redirectToRoute('app_admin_company');
}
// Tentative de suppression
try {
$em->remove($company);
$em->flush();
} catch (\Exception $e) {
$this->addflash('error', $e->getMessage());
return $this->redirectToRoute('app_admin_company_update', ['id' => $id]);
}
return $this->redirectToRoute('app_admin_company');
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CropController extends AbstractController
{
#[Route('/user/crop01/{endpoint}', name: 'app_user_crop01')]
public function crop01(string $endpoint): Response
{
return $this->render('crop\crop01.html.twig', [
'useheader' => false,
'usemenu' => false,
'usesidebar' => false,
'endpoint' => $endpoint,
]);
}
#[Route('/user/crop02', name: 'app_user_crop02')]
public function crop02(): Response
{
return $this->render('crop\crop01.html.twig', [
'useheader' => false,
'usemenu' => false,
'usesidebar' => false,
]);
}
}

View File

@ -2,18 +2,24 @@
namespace App\Controller;
use App\Repository\AccountingRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function home(): Response
public function home(Request $request, AccountingRepository $accountingRepository): Response
{
$company = $request->getSession()->get('company');
$accountings = $accountingRepository->findBy(['company' => $company, 'category' => 'actif'], ['num01' => 'ASC', 'num02' => 'ASC']);
return $this->render('home/home.html.twig', [
'usemenu' => true,
'usesidebar' => false,
'accountings' => $accountings,
]);
}
@ -25,4 +31,13 @@ class HomeController extends AbstractController
'usesidebar' => true,
]);
}
#[Route('/user/nocompany', name: 'app_user_nocompany')]
public function nocompany(): Response
{
return $this->render('home/nocompany.html.twig', [
'usemenu' => true,
'usesidebar' => false,
]);
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace App\Controller;
use App\Service\ImageService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class UploadController extends AbstractController
{
private ImageService $imageService;
public function __construct(ImageService $imageService)
{
$this->imageService = $imageService;
}
#[Route('/user/upload/crop01/{endpoint}', name: 'app_user_upload_crop01')]
public function crop01(string $endpoint, Request $request): Response
{
$reportThumb = $request->get('reportThumb');
return $this->render('upload\crop01.html.twig', [
'useheader' => false,
'usemenu' => false,
'usesidebar' => false,
'endpoint' => $endpoint,
'reportThumb' => $reportThumb,
]);
}
#[Route('/user/upload/crop02', name: 'app_user_upload_crop02')]
public function crop02(Request $request): Response
{
$reportThumb = $request->get('reportThumb');
$path = $request->get('path');
$file = $request->get('file');
$image = $this->getParameter('kernel.project_dir').'/public/'.$path.'/'.$file;
$thumb = $this->getParameter('kernel.project_dir').'/public/'.$path.'/thumb_'.$file;
// Redimentionner
$this->imageService->resizeImage($image, 700, 700);
// Construction du formulaire
$form = $this->createFormBuilder()
->add('submit', SubmitType::class, ['label' => 'Valider', 'attr' => ['class' => 'btn btn-success']])
->add('x1', HiddenType::class)
->add('y1', HiddenType::class)
->add('x2', HiddenType::class)
->add('y2', HiddenType::class)
->add('w', HiddenType::class)
->add('h', HiddenType::class)
->getForm();
// Récupération des data du formulaire
$form->handleRequest($request);
$toReport = false;
// Sur validation on généère la miniature croppée
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$toReport = true;
dump($data);
$this->imageService->cropImage($image, $thumb, $data['x1'], $data['y1'], $data['w'], $data['h'], 150, 150);
}
return $this->render('upload\crop02.html.twig', [
'useheader' => false,
'usemenu' => false,
'usesidebar' => false,
'reportThumb' => $reportThumb,
'image' => $path.'/'.$file,
'thumb' => $path.'/thumb_'.$file,
'form' => $form,
'toReport' => $toReport,
]);
}
}

View File

@ -2,11 +2,13 @@
namespace App\Controller;
use App\Entity\Company;
use App\Entity\User;
use App\Form\UserType;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
@ -69,7 +71,6 @@ class UserController extends AbstractController
return $this->redirectToRoute('app_admin_user');
}
$hashedPassword = $user->getPassword();
$user->setPassword('');
$form = $this->createForm(UserType::class, $user, ['mode' => 'update']);
$form->handleRequest($request);
@ -82,8 +83,6 @@ class UserController extends AbstractController
);
}
$user->setPassword($hashedPassword);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('app_admin_user');
@ -101,14 +100,87 @@ class UserController extends AbstractController
}
#[Route('/admin/user/delete/{id}', name: 'app_admin_user_delete')]
public function delete(int $id): Response
public function delete(int $id, EntityManagerInterface $em): Response
{
$user = $em->getRepository(User::class)->find($id);
if (!$user) {
return $this->redirectToRoute('app_admin_user');
}
// Tentative de suppression
try {
$em->remove($user);
$em->flush();
} catch (\Exception $e) {
$this->addflash('error', $e->getMessage());
return $this->redirectToRoute('app_admin_user_update', ['id' => $id]);
}
return $this->redirectToRoute('app_admin_user');
}
#[Route('/user', name: 'app_user_profil')]
public function profil(): Response
public function profil(Request $request, UserPasswordHasherInterface $passwordHasher, EntityManagerInterface $em): Response
{
return $this->redirectToRoute('app_home');
$user = $em->getRepository(User::class)->find($this->getUser());
if (!$user) {
return $this->redirectToRoute('app_home');
}
$hashedPassword = $user->getPassword();
$form = $this->createForm(UserType::class, $user, ['mode' => 'profil']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData();
if ($user->getPassword()) {
$hashedPassword = $passwordHasher->hashPassword(
$user,
$user->getPassword()
);
}
$user->setPassword($hashedPassword);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('app_home');
}
return $this->render('user/edit.html.twig', [
'usemenu' => true,
'usesidebar' => false,
'title' => 'Profil = '.$user->getUsername(),
'routecancel' => 'app_home',
'routedelete' => '',
'mode' => 'profil',
'form' => $form,
]);
}
#[Route('/admin/user/selectcompany', name: 'app_user_selectcompany')]
public function selectcompany(Request $request, EntityManagerInterface $em): JsonResponse
{
$id = $request->get('id');
$company = $em->getRepository(Company::class)->find($id);
if (!$company) {
return new JsonResponse(['status' => 'KO', 'message' => 'ID non fourni'], Response::HTTP_NOT_FOUND);
}
$user = $this->getUser();
if (!$user instanceof User) {
throw new \LogicException('L\'utilisateur actuel n\'est pas une instance de App\Entity\User.');
}
$companys = $user->getCompanys();
if (!$companys->contains($company)) {
return new JsonResponse(['status' => 'KO', 'message' => 'Compangnie non autorisée'], Response::HTTP_FORBIDDEN);
}
$user->setCompany($company);
$em->flush();
return new JsonResponse(['status' => 'OK', 'message' => 'Compangnie selectionnée'], Response::HTTP_OK);
}
}

View File

@ -7,10 +7,11 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: AccountingRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_ACCOUNTING', fields: ['num01', 'num02'])]
#[UniqueEntity(fields: ['num01', 'num02'], message: 'Ce numéro de compte est déjà utilisé.')]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_ACCOUNTING', fields: ['company', 'num01', 'num02'])]
#[UniqueEntity(fields: ['company', 'num01', 'num02'], message: 'Ce numéro de compte est déjà utilisé.')]
class Accounting
{
#[ORM\Id]
@ -18,10 +19,18 @@ class Accounting
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[ORM\Column(length: 3)]
#[Assert\Regex(
pattern: '/^[0-9]{3}$/',
message: 'La valeur doit être un nombre de trois chiffres (ex: 001, 098, 540).'
)]
private ?string $num01 = null;
#[ORM\Column(length: 255)]
#[ORM\Column(length: 10)]
#[Assert\Regex(
pattern: '/^[0-9]{3}$/',
message: 'La valeur doit être un nombre de trois chiffres (ex: 001, 098, 540).'
)]
private ?string $num02 = null;
#[ORM\Column(length: 255)]
@ -67,7 +76,7 @@ class Accounting
public function setNum01(string $num01): static
{
$this->num01 = $num01;
$this->num01 = str_pad($num01, 3, '0', STR_PAD_LEFT);
return $this;
}
@ -79,7 +88,7 @@ class Accounting
public function setNum02(string $num02): static
{
$this->num02 = $num02;
$this->num02 = str_pad($num02, 3, '0', STR_PAD_LEFT);
return $this;
}

View File

@ -8,6 +8,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: CompanyRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_COMPANY', fields: ['title'])]
@ -22,12 +23,16 @@ class Company
#[ORM\Column(length: 255, unique: true)]
private ?string $title = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $adress = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $logo = null;
#[ORM\Column(length: 255, nullable: true)]
#[Assert\Email(message: 'Veuillez entrer un email valide.')]
private ?string $email = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $adress = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $bankname = null;
@ -87,6 +92,30 @@ class Company
return $this;
}
public function getLogo(): ?string
{
return $this->logo ? $this->logo : 'medias/logo/logo.png';
}
public function setLogo(?string $logo): static
{
$this->logo = $logo;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): static
{
$this->email = $email;
return $this;
}
public function getAdress(): ?string
{
return $this->adress;
@ -99,18 +128,6 @@ class Company
return $this;
}
public function getLogo(): ?string
{
return $this->logo;
}
public function setLogo(?string $logo): static
{
$this->logo = $logo;
return $this;
}
public function getBankname(): ?string
{
return $this->bankname;

View File

@ -46,6 +46,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\ManyToMany(targetEntity: Company::class, inversedBy: 'users')]
private Collection $companys;
#[ORM\ManyToOne()]
#[ORM\JoinColumn(nullable: true)]
private ?Company $company = null;
public function __construct()
{
$this->companys = new ArrayCollection();
@ -173,4 +177,20 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
public function getCompany(): ?Company
{
if (!$this->companys) {
return null;
}
return $this->company;
}
public function setCompany(?Company $company): static
{
$this->company = $company;
return $this;
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\EventListener;
use App\Entity\User;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RouterInterface;
final class SessionListener
{
private Security $security;
private RouterInterface $router;
public function __construct(Security $security, RouterInterface $router)
{
$this->security = $security;
$this->router = $router;
}
#[AsEventListener(event: KernelEvents::REQUEST)]
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
$session = $request->getSession();
$user = $this->security->getUser();
if ($user instanceof User && $user) {
// Intialisation de la compagnie en cours
if (!$user->getCompany()) {
if ($user->getCompanys()) {
$user->setCompany($user->getCompanys()[0]);
}
}
$session->set('company', $user->getCompany());
$session->set('companys', $user->getCompanys());
if (!$user->getCompany()) {
$event->setResponse(new RedirectResponse($this->router->generate('app_user_nocompany', [])));
}
}
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\EventListener;
use Oneup\UploaderBundle\Event\PostPersistEvent;
use Oneup\UploaderBundle\Event\ValidationEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\KernelInterface;
final class UploadListener
{
private string $projectDir;
public function __construct(KernelInterface $kernel)
{
// Utiliser le projectDir pour construire le chemin
$this->projectDir = $kernel->getProjectDir();
}
#[AsEventListener(event: 'oneup_uploader.validation')]
public function onOneupUploaderValidation(ValidationEvent $event): void
{
// On s'assure que le repertoire de destination existe bien
$fs = new Filesystem();
$fs->mkdir($this->projectDir.'/public/uploads');
$fs->mkdir($this->projectDir.'/public/uploads/'.$event->getType());
}
#[AsEventListener(event: 'oneup_uploader.post_persist')]
public function onOneupUploaderPostPersit(PostPersistEvent $event): void
{
$file = $event->getFile();
$type = $event->getType();
$filename = $file->getFilename();
$response = $event->getResponse();
$response['file'] = $filename;
$response['path'] = 'uploads/'.$type;
$response['filepath'] = 'uploads/'.$type.'/'.$filename;
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace App\Form;
use App\Entity\Accounting;
use App\Form\DataTransformer\ThreeDigitTransformer;
use App\Form\Type\ThreeDigitType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AccountingType extends AbstractType
{
private ThreeDigitTransformer $threeDigitTransformer;
public function __construct(ThreeDigitTransformer $threeDigitTransformer)
{
$this->threeDigitTransformer = $threeDigitTransformer;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => 'btn btn-success no-print'],
])
->add('num01', ThreeDigitType::class, [
'label' => 'Numéro de Compte 01',
])
->add('num02', ThreeDigitType::class, [
'label' => 'Numéro de Compte 01',
])
->add('title', TextType::class, [
'label' => 'Titre',
])
->add('category', ChoiceType::class, [
'label' => 'Catégorie',
'choices' => ['passif' => 'passif', 'actif' => 'actif', 'charge' => 'charge', 'produit' => 'produit'],
])
->add('icon', FontawsomeType::class, [
'label' => 'Icône',
'attr' => ['class' => 'select2'],
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Accounting::class,
'mode' => 'submit',
]);
}
}

91
src/Form/CompanyType.php Normal file
View File

@ -0,0 +1,91 @@
<?php
namespace App\Form;
use App\Entity\Company;
use App\Entity\User;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CompanyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => 'btn btn-success no-print'],
])
->add('title', TextType::class, [
'label' => 'Nom',
])
->add('email', EmailType::class, [
'label' => 'Email',
'required' => false,
])
->add('logo', HiddenType::class)
->add('adress', TextType::class, [
'label' => 'Adresse',
'required' => false,
])
->add('bankname', TextType::class, [
'required' => false,
])
->add('bankcode', TextType::class, [
'required' => false,
])
->add('bankguichet', TextType::class, [
'required' => false,
])
->add('banknum', TextType::class, [
'required' => false,
])
->add('bankkey', TextType::class, [
'required' => false,
])
->add('banklocality', TextType::class, [
'required' => false,
])
->add('bankiban', TextType::class, [
'required' => false,
])
->add('bankbic', TextType::class, [
'required' => false,
])
->add('users', EntityType::class, [
'label' => 'Utilisateurs',
'class' => User::class,
'choice_label' => 'username',
'multiple' => true,
'attr' => ['class' => 'select2'],
'required' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Company::class,
'mode' => 'submit',
]);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
class ThreeDigitTransformer implements DataTransformerInterface
{
public function transform($value): ?string
{
return null !== $value ? str_pad($value, 3, '0', STR_PAD_LEFT) : null;
}
public function reverseTransform($value): ?int
{
return str_pad($value, 3, '0', STR_PAD_LEFT);
}
}

View File

@ -0,0 +1,999 @@
<?php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FontawsomeType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'choices' => $this->getFontAwesomeIcons(),
]);
}
public function getParent(): string
{
return ChoiceType::class;
}
private function getFontAwesomeIcons(): array
{
$icons = [
'ad',
'address-book',
'address-card',
'adjust',
'air-freshener',
'align-center',
'align-justify',
'align-left',
'align-right',
'allergies',
'ambulance',
'american-sign-language-interpreting',
'anchor',
'angle-double-down',
'angle-double-left',
'angle-double-right',
'angle-double-up',
'angle-down',
'angle-left',
'angle-right',
'angle-up',
'angry',
'ankh',
'apple-alt',
'archive',
'archway',
'arrow-alt-circle-down',
'arrow-alt-circle-left',
'arrow-alt-circle-right',
'arrow-alt-circle-up',
'arrow-circle-down',
'arrow-circle-left',
'arrow-circle-right',
'arrow-circle-up',
'arrow-down',
'arrow-left',
'arrow-right',
'arrow-up',
'arrows-alt',
'arrows-alt-h',
'arrows-alt-v',
'assistive-listening-systems',
'asterisk',
'at',
'atlas',
'atom',
'audio-description',
'award',
'baby',
'baby-carriage',
'backspace',
'backward',
'bacon',
'bahai',
'balance-scale',
'balance-scale-left',
'balance-scale-right',
'ban',
'band-aid',
'barcode',
'bars',
'baseball-ball',
'basketball-ball',
'bath',
'battery-empty',
'battery-full',
'battery-half',
'battery-quarter',
'battery-three-quarters',
'bed',
'beer',
'bell',
'bell-slash',
'bezier-curve',
'bible',
'bicycle',
'biking',
'binoculars',
'biohazard',
'birthday-cake',
'blender',
'blender-phone',
'blind',
'blog',
'bold',
'bolt',
'bomb',
'bone',
'bong',
'book',
'book-dead',
'book-medical',
'book-open',
'book-reader',
'bookmark',
'border-all',
'border-none',
'border-style',
'bowling-ball',
'box',
'box-open',
'boxes',
'braille',
'brain',
'bread-slice',
'briefcase',
'briefcase-medical',
'broadcast-tower',
'broom',
'brush',
'bug',
'building',
'bullhorn',
'bullseye',
'burn',
'bus',
'bus-alt',
'business-time',
'calculator',
'calendar',
'calendar-alt',
'calendar-check',
'calendar-day',
'calendar-minus',
'calendar-plus',
'calendar-times',
'calendar-week',
'camera',
'camera-retro',
'campground',
'candy-cane',
'cannabis',
'capsules',
'car',
'car-alt',
'car-battery',
'car-crash',
'car-side',
'caravan',
'caret-down',
'caret-left',
'caret-right',
'caret-square-down',
'caret-square-left',
'caret-square-right',
'caret-square-up',
'caret-up',
'carrot',
'cart-arrow-down',
'cart-plus',
'cash-register',
'cat',
'certificate',
'chair',
'chalkboard',
'chalkboard-teacher',
'charging-station',
'chart-area',
'chart-bar',
'chart-line',
'chart-pie',
'check',
'check-circle',
'check-double',
'check-square',
'cheese',
'chess',
'chess-bishop',
'chess-board',
'chess-king',
'chess-knight',
'chess-pawn',
'chess-queen',
'chess-rook',
'chevron-circle-down',
'chevron-circle-left',
'chevron-circle-right',
'chevron-circle-up',
'chevron-down',
'chevron-left',
'chevron-right',
'chevron-up',
'child',
'church',
'circle',
'circle-notch',
'city',
'clinic-medical',
'clipboard',
'clipboard-check',
'clipboard-list',
'clock',
'clone',
'closed-captioning',
'cloud',
'cloud-download-alt',
'cloud-meatball',
'cloud-moon',
'cloud-moon-rain',
'cloud-rain',
'cloud-showers-heavy',
'cloud-sun',
'cloud-sun-rain',
'cloud-upload-alt',
'cocktail',
'code',
'code-branch',
'coffee',
'cog',
'cogs',
'coins',
'columns',
'comment',
'comment-alt',
'comment-dollar',
'comment-dots',
'comment-medical',
'comment-slash',
'comments',
'comments-dollar',
'compact-disc',
'compass',
'compress',
'compress-alt',
'compress-arrows-alt',
'concierge-bell',
'cookie',
'cookie-bite',
'copy',
'copyright',
'couch',
'credit-card',
'crop',
'crop-alt',
'cross',
'crosshairs',
'crow',
'crown',
'crutch',
'cube',
'cubes',
'cut',
'database',
'deaf',
'democrat',
'desktop',
'dharmachakra',
'diagnoses',
'dice',
'dice-d20',
'dice-d6',
'dice-five',
'dice-four',
'dice-one',
'dice-six',
'dice-three',
'dice-two',
'digital-tachograph',
'directions',
'divide',
'dizzy',
'dna',
'dog',
'dollar-sign',
'dolly',
'dolly-flatbed',
'donate',
'door-closed',
'door-open',
'dot-circle',
'dove',
'download',
'drafting-compass',
'dragon',
'draw-polygon',
'drum',
'drum-steelpan',
'drumstick-bite',
'dumbbell',
'dumpster',
'dumpster-fire',
'dungeon',
'edit',
'egg',
'eject',
'ellipsis-h',
'ellipsis-v',
'envelope',
'envelope-open',
'envelope-open-text',
'envelope-square',
'equals',
'eraser',
'ethernet',
'euro-sign',
'exchange-alt',
'exclamation',
'exclamation-circle',
'exclamation-triangle',
'expand',
'expand-alt',
'expand-arrows-alt',
'external-link-alt',
'external-link-square-alt',
'eye',
'eye-dropper',
'eye-slash',
'fan',
'fast-backward',
'fast-forward',
'fax',
'feather',
'feather-alt',
'female',
'fighter-jet',
'file',
'file-alt',
'file-archive',
'file-audio',
'file-code',
'file-contract',
'file-csv',
'file-download',
'file-excel',
'file-export',
'file-image',
'file-import',
'file-invoice',
'file-invoice-dollar',
'file-medical',
'file-medical-alt',
'file-pdf',
'file-powerpoint',
'file-prescription',
'file-signature',
'file-upload',
'file-video',
'file-word',
'fill',
'fill-drip',
'film',
'filter',
'fingerprint',
'fire',
'fire-alt',
'fire-extinguisher',
'first-aid',
'fish',
'fist-raised',
'flag',
'flag-checkered',
'flag-usa',
'flask',
'flushed',
'folder',
'folder-minus',
'folder-open',
'folder-plus',
'font',
'football-ball',
'forward',
'frog',
'frown',
'frown-open',
'funnel-dollar',
'futbol',
'gamepad',
'gas-pump',
'gavel',
'gem',
'genderless',
'ghost',
'gift',
'gifts',
'glass-cheers',
'glass-martini',
'glass-martini-alt',
'glass-whiskey',
'glasses',
'globe',
'globe-africa',
'globe-americas',
'globe-asia',
'globe-europe',
'golf-ball',
'gopuram',
'graduation-cap',
'greater-than',
'greater-than-equal',
'grimace',
'grin',
'grin-alt',
'grin-beam',
'grin-beam-sweat',
'grin-hearts',
'grin-squint',
'grin-squint-tears',
'grin-stars',
'grin-tears',
'grin-tongue',
'grin-tongue-squint',
'grin-tongue-wink',
'grin-wink',
'grip-horizontal',
'grip-lines',
'grip-lines-vertical',
'grip-vertical',
'guitar',
'h-square',
'hamburger',
'hammer',
'hamsa',
'hand-holding',
'hand-holding-heart',
'hand-holding-usd',
'hand-lizard',
'hand-middle-finger',
'hand-paper',
'hand-peace',
'hand-point-down',
'hand-point-left',
'hand-point-right',
'hand-point-up',
'hand-pointer',
'hand-rock',
'hand-scissors',
'hand-spock',
'hands',
'hands-helping',
'handshake',
'hanukiah',
'hard-hat',
'hashtag',
'hat-cowboy',
'hat-cowboy-side',
'hat-wizard',
'hdd',
'heading',
'headphones',
'headphones-alt',
'headset',
'heart',
'heart-broken',
'heartbeat',
'helicopter',
'highlighter',
'hiking',
'hippo',
'history',
'hockey-puck',
'holly-berry',
'home',
'horse',
'horse-head',
'hospital',
'hospital-alt',
'hospital-symbol',
'hot-tub',
'hotdog',
'hotel',
'hourglass',
'hourglass-end',
'hourglass-half',
'hourglass-start',
'house-damage',
'hryvnia',
'i-cursor',
'ice-cream',
'icicles',
'icons',
'id-badge',
'id-card',
'id-card-alt',
'igloo',
'image',
'images',
'inbox',
'indent',
'industry',
'infinity',
'info',
'info-circle',
'italic',
'jedi',
'joint',
'journal-whills',
'kaaba',
'key',
'keyboard',
'khanda',
'kiss',
'kiss-beam',
'kiss-wink-heart',
'kiwi-bird',
'landmark',
'language',
'laptop',
'laptop-code',
'laptop-medical',
'laugh',
'laugh-beam',
'laugh-squint',
'laugh-wink',
'layer-group',
'leaf',
'lemon',
'less-than',
'less-than-equal',
'level-down-alt',
'level-up-alt',
'life-ring',
'lightbulb',
'link',
'lira-sign',
'list',
'list-alt',
'list-ol',
'list-ul',
'location-arrow',
'lock',
'lock-open',
'long-arrow-alt-down',
'long-arrow-alt-left',
'long-arrow-alt-right',
'long-arrow-alt-up',
'low-vision',
'luggage-cart',
'magic',
'magnet',
'mail-bulk',
'male',
'map',
'map-marked',
'map-marked-alt',
'map-marker',
'map-marker-alt',
'map-pin',
'map-signs',
'marker',
'mars',
'mars-double',
'mars-stroke',
'mars-stroke-h',
'mars-stroke-v',
'mask',
'medal',
'medkit',
'meh',
'meh-blank',
'meh-rolling-eyes',
'memory',
'menorah',
'mercury',
'meteor',
'microchip',
'microphone',
'microphone-alt',
'microphone-alt-slash',
'microphone-slash',
'microscope',
'minus',
'minus-circle',
'minus-square',
'mitten',
'mobile',
'mobile-alt',
'money-bill',
'money-bill-alt',
'money-bill-wave',
'money-bill-wave-alt',
'money-check',
'money-check-alt',
'monument',
'moon',
'mortar-pestle',
'mosque',
'motorcycle',
'mountain',
'mouse',
'mouse-pointer',
'mug-hot',
'music',
'network-wired',
'neuter',
'newspaper',
'not-equal',
'notes-medical',
'object-group',
'object-ungroup',
'oil-can',
'om',
'otter',
'outdent',
'pager',
'paint-brush',
'paint-roller',
'palette',
'pallet',
'paper-plane',
'paperclip',
'parachute-box',
'paragraph',
'parking',
'passport',
'pastafarianism',
'paste',
'pause',
'pause-circle',
'paw',
'peace',
'pen',
'pen-alt',
'pen-fancy',
'pen-nib',
'pen-square',
'pencil-alt',
'pencil-ruler',
'people-carry',
'pepper-hot',
'percent',
'percentage',
'person-booth',
'phone',
'phone-alt',
'phone-slash',
'phone-square',
'phone-square-alt',
'phone-volume',
'photo-video',
'piggy-bank',
'pills',
'pizza-slice',
'place-of-worship',
'plane',
'plane-arrival',
'plane-departure',
'play',
'play-circle',
'plug',
'plus',
'plus-circle',
'plus-square',
'podcast',
'poll',
'poll-h',
'poo',
'poo-storm',
'poop',
'portrait',
'pound-sign',
'power-off',
'pray',
'praying-hands',
'prescription',
'prescription-bottle',
'prescription-bottle-alt',
'print',
'procedures',
'project-diagram',
'puzzle-piece',
'qrcode',
'question',
'question-circle',
'quidditch',
'quote-left',
'quote-right',
'quran',
'radiation',
'radiation-alt',
'rainbow',
'random',
'receipt',
'record-vinyl',
'recycle',
'redo',
'redo-alt',
'registered',
'remove-format',
'reply',
'reply-all',
'republican',
'restroom',
'retweet',
'ribbon',
'ring',
'road',
'robot',
'rocket',
'route',
'rss',
'rss-square',
'ruble-sign',
'ruler',
'ruler-combined',
'ruler-horizontal',
'ruler-vertical',
'running',
'rupee-sign',
'sad-cry',
'sad-tear',
'satellite',
'satellite-dish',
'save',
'school',
'screwdriver',
'scroll',
'sd-card',
'search',
'search-dollar',
'search-location',
'search-minus',
'search-plus',
'seedling',
'server',
'shapes',
'share',
'share-alt',
'share-alt-square',
'share-square',
'shekel-sign',
'shield-alt',
'ship',
'shipping-fast',
'shoe-prints',
'shopping-bag',
'shopping-basket',
'shopping-cart',
'shower',
'shuttle-van',
'sign',
'sign-in-alt',
'sign-language',
'sign-out-alt',
'signal',
'signature',
'sim-card',
'sitemap',
'skating',
'skiing',
'skiing-nordic',
'skull',
'skull-crossbones',
'slash',
'sleigh',
'sliders-h',
'smile',
'smile-beam',
'smile-wink',
'smog',
'smoking',
'smoking-ban',
'sms',
'snowboarding',
'snowflake',
'snowman',
'snowplow',
'socks',
'solar-panel',
'sort',
'sort-alpha-down',
'sort-alpha-down-alt',
'sort-alpha-up',
'sort-alpha-up-alt',
'sort-amount-down',
'sort-amount-down-alt',
'sort-amount-up',
'sort-amount-up-alt',
'sort-down',
'sort-numeric-down',
'sort-numeric-down-alt',
'sort-numeric-up',
'sort-numeric-up-alt',
'sort-up',
'spa',
'space-shuttle',
'spell-check',
'spider',
'spinner',
'splotch',
'spray-can',
'square',
'square-full',
'square-root-alt',
'stamp',
'star',
'star-and-crescent',
'star-half',
'star-half-alt',
'star-of-david',
'star-of-life',
'step-backward',
'step-forward',
'stethoscope',
'sticky-note',
'stop',
'stop-circle',
'stopwatch',
'store',
'store-alt',
'stream',
'street-view',
'strikethrough',
'stroopwafel',
'subscript',
'subway',
'suitcase',
'suitcase-rolling',
'sun',
'superscript',
'surprise',
'swatchbook',
'swimmer',
'swimming-pool',
'synagogue',
'sync',
'sync-alt',
'syringe',
'table',
'table-tennis',
'tablet',
'tablet-alt',
'tablets',
'tachometer-alt',
'tag',
'tags',
'tape',
'tasks',
'taxi',
'teeth',
'teeth-open',
'temperature-high',
'temperature-low',
'tenge',
'terminal',
'text-height',
'text-width',
'th',
'th-large',
'th-list',
'theater-masks',
'thermometer',
'thermometer-empty',
'thermometer-full',
'thermometer-half',
'thermometer-quarter',
'thermometer-three-quarters',
'thumbs-down',
'thumbs-up',
'thumbtack',
'ticket-alt',
'times',
'times-circle',
'tint',
'tint-slash',
'tired',
'toggle-off',
'toggle-on',
'toilet',
'toilet-paper',
'toolbox',
'tools',
'tooth',
'torah',
'torii-gate',
'tractor',
'trademark',
'traffic-light',
'trailer',
'train',
'tram',
'transgender',
'transgender-alt',
'trash',
'trash-alt',
'trash-restore',
'trash-restore-alt',
'tree',
'trophy',
'truck',
'truck-loading',
'truck-monster',
'truck-moving',
'truck-pickup',
'tshirt',
'tty',
'tv',
'umbrella',
'umbrella-beach',
'underline',
'undo',
'undo-alt',
'universal-access',
'university',
'unlink',
'unlock',
'unlock-alt',
'upload',
'user',
'user-alt',
'user-alt-slash',
'user-astronaut',
'user-check',
'user-circle',
'user-clock',
'user-cog',
'user-edit',
'user-friends',
'user-graduate',
'user-injured',
'user-lock',
'user-md',
'user-minus',
'user-ninja',
'user-nurse',
'user-plus',
'user-secret',
'user-shield',
'user-slash',
'user-tag',
'user-tie',
'user-times',
'users',
'users-cog',
'utensil-spoon',
'utensils',
'vector-square',
'venus',
'venus-double',
'venus-mars',
'vial',
'vials',
'video',
'video-slash',
'vihara',
'voicemail',
'volleyball-ball',
'volume-down',
'volume-mute',
'volume-off',
'volume-up',
'vote-yea',
'vr-cardboard',
'walking',
'wallet',
'warehouse',
'water',
'wave-square',
'weight',
'weight-hanging',
'wheelchair',
'wifi',
'wind',
'window-close',
'window-maximize',
'window-minimize',
'window-restore',
'wine-bottle',
'wine-glass',
'wine-glass-alt',
'won-sign',
'wrench',
'x-ray',
'yen-sign',
'yin-yang', ];
$tbicons = [];
foreach ($icons as $value) {
$tbicons[$value] = 'fas fa-'.$value;
}
// Liste d'exemples d'icônes Font Awesome
return $tbicons;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Form\Type;
use App\Form\DataTransformer\ThreeDigitTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ThreeDigitType extends AbstractType
{
private ThreeDigitTransformer $transformer;
public function __construct(ThreeDigitTransformer $transformer)
{
$this->transformer = $transformer;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->addModelTransformer($this->transformer);
}
public function configureOptions(OptionsResolver $resolver): void
{
}
public function getParent(): string
{
return TextType::class;
}
}

View File

@ -8,6 +8,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -20,43 +21,45 @@ class UserType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => 'btn btn-success no-print'],
])
->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => 'btn btn-success no-print'],
])
->add('username', TextType::class, [
'label' => 'Login',
])
->add('username', TextType::class, [
'label' => 'Login',
])
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'required' => ('submit' == $options['mode'] ? true : false),
'options' => ['always_empty' => true],
'first_options' => ['label' => 'Mot de Passe', 'attr' => ['class' => 'form-control', 'style' => 'margin-bottom:15px', 'autocomplete' => 'new-password']],
'second_options' => ['label' => 'Confirmer Mot de Passe', 'attr' => ['class' => 'form-control', 'style' => 'margin-bottom:15px']],
])
->add('avatar', HiddenType::class)
->add('email', EmailType::class, [
'label' => 'Email',
]);
if ('profil' != $options['mode']) {
$builder
->add('roles', ChoiceType::class, [
'choices' => ['ROLE_ADMIN' => 'ROLE_ADMIN', 'ROLE_USER' => 'ROLE_USER'],
'multiple' => true,
'expanded' => true,
])
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'required' => ('submit' == $options['mode'] ? true : false),
'options' => ['always_empty' => true],
'first_options' => ['label' => 'Mot de Passe', 'attr' => ['class' => 'form-control', 'style' => 'margin-bottom:15px', 'autocomplete' => 'new-password']],
'second_options' => ['label' => 'Confirmer Mot de Passe', 'attr' => ['class' => 'form-control', 'style' => 'margin-bottom:15px']],
])
->add('avatar')
->add('email', EmailType::class, [
'label' => 'Email',
])
->add('companys', EntityType::class, [
'label' => 'Companie',
'label' => 'Compagnies',
'class' => Company::class,
'choice_label' => 'title',
'multiple' => true,
'attr' => ['class' => 'select2'],
])
;
]);
}
}
public function configureOptions(OptionsResolver $resolver): void

View File

@ -0,0 +1,133 @@
<?php
namespace App\Service;
class ImageService
{
// Hauteur d'une image
public function getHeight(string $image): int
{
$size = getimagesize($image);
$height = $size[1];
return $height;
}
// Largeur d'une imgage
public function getWidth(string $image): int
{
$size = getimagesize($image);
$width = $size[0];
return $width;
}
public function resizeImage(string $image, int $maxWidth, int $maxHeight): void
{
list($width, $height, $imageType) = getimagesize($image);
$imageType = image_type_to_mime_type($imageType);
// Définir le pourcentage de réduction de l'image
$scale = $maxHeight / $height;
if (($width * $scale) > $maxWidth) {
$scale = $maxWidth / $width;
}
// Création de l'image redimentionnée
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth, $newImageHeight);
switch ($imageType) {
case 'image/gif':
$source = imagecreatefromgif($image);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
$source = imagecreatefromjpeg($image);
break;
case 'image/png':
case 'image/x-png':
$source = imagecreatefrompng($image);
break;
case 'image/webp':
$source = imagecreatefromwebp($image);
break;
}
imagecopyresampled($newImage, $source, 0, 0, 0, 0, $newImageWidth, $newImageHeight, $width, $height);
switch ($imageType) {
case 'image/gif':
imagegif($newImage, $image);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
imagejpeg($newImage, $image, 90);
break;
case 'image/png':
case 'image/x-png':
imagepng($newImage, $image);
break;
case 'image/webp':
imagewebp($newImage, $image, 90);
}
}
public function cropImage(string $image, string $thumb, int $x, int $y, int $cropWidth, int $cropHeight, int $maxWidth, int $maxHeight): void
{
list($width, $height, $imageType) = getimagesize($image);
$imageType = image_type_to_mime_type($imageType);
// Définir le pourcentage de réduction de l'image
$scale = $maxHeight / $cropHeight;
if (($cropWidth * $scale) > $maxWidth) {
$scale = $maxWidth / $cropWidth;
}
// Création de l'image redimentionnée
$newImageWidth = ceil($cropWidth * $scale);
$newImageHeight = ceil($cropHeight * $scale);
$newImage = imagecreatetruecolor($newImageWidth, $newImageHeight);
switch ($imageType) {
case 'image/gif':
$source = imagecreatefromgif($image);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
$source = imagecreatefromjpeg($image);
break;
case 'image/png':
case 'image/x-png':
$source = imagecreatefrompng($image);
break;
case 'image/webp':
$source = imagecreatefromwebp($image);
break;
}
imagecopyresampled($newImage, $source, 0, 0, $x, $y, $newImageWidth, $newImageHeight, $cropWidth, $cropHeight);
switch ($imageType) {
case 'image/gif':
imagegif($newImage, $thumb);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
imagejpeg($newImage, $thumb, 90);
break;
case 'image/png':
case 'image/x-png':
imagepng($newImage, $thumb);
break;
case 'image/webp':
imagewebp($newImage, $thumb, 90);
}
}
}