src/EventSubscriber/EasyAdminSubscriber.php line 57

  1. <?php
  2. # src/EventSubscriber/EasyAdminSubscriber.php
  3. namespace App\EventSubscriber;
  4. use App\Entity\ExportExcel;
  5. use App\Entity\FrontTheme;
  6. use App\Entity\Settings;
  7. use App\Entity\User;
  8. use Doctrine\Common\Collections\ArrayCollection;
  9. use Doctrine\Common\Collections\Collection;
  10. use Doctrine\Persistence\ManagerRegistry;
  11. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
  12. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityPersistedEvent;
  13. use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent;
  14. use RecursiveDirectoryIterator;
  15. use RecursiveIteratorIterator;
  16. use ReflectionClass;
  17. use ReflectionMethod;
  18. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  19. use Symfony\Component\Security\Core\Security;
  20. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  21. use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
  22. use Symfony\Component\Filesystem\Filesystem;
  23. use Symfony\Component\Filesystem\Path;
  24. use Symfony\Component\Finder\Finder;
  25. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  26. use Symfony\Component\Yaml\Yaml;
  27. use ZipArchive;
  28. use Symfony\Contracts\Translation\TranslatorInterface;
  29. class EasyAdminSubscriber implements EventSubscriberInterface
  30. {
  31.  
  32.     
  33.     public function __construct(
  34.         private readonly Security $security,
  35.         private readonly UserPasswordHasherInterface $passwordEncoder,
  36.         private readonly ManagerRegistry $doctrine,
  37.         private readonly TranslatorInterface $translatorInterface
  38.         
  39.         )
  40. {
  41.         
  42.     }
  43.     public static function getSubscribedEvents()
  44.     {
  45.         return [
  46.             BeforeEntityPersistedEvent::class => ['beforePersist'],
  47.             BeforeEntityUpdatedEvent::class => ['beforeUpdated'],
  48.             BeforeEntityDeletedEvent::class => ['beforeDelete']
  49.         ];
  50.     }
  51.     public function beforePersist(BeforeEntityPersistedEvent $event)
  52.     {
  53.         $entity $event->getEntityInstance();
  54.         if($entity instanceof FrontTheme){
  55.             
  56.             $filesystem = new Filesystem();
  57.             $finder = new Finder();
  58.             
  59.             $path __DIR__."/../../public/uploads/".$entity->getName();
  60.             if(!$filesystem->exists($path) )
  61.             {
  62.                 $filesystem->mkdir($path,0777);
  63.                 $filesystem->mkdir($path."/pages",0777);
  64.                 $filesystem->mkdir($path."/shop",0777);
  65.                 
  66.             }
  67.             $pathFrontBundle __DIR__."/../IlaveU/FrontBundle";
  68.             
  69.             $themePath $pathFrontBundle."/Themes";
  70.             $filesystem->mirror($themePath."/Default",$themePath."/".ucfirst($entity->getName()));
  71.             //$filesystem->mkdir(__DIR__."/../../public/themes/".strtolower($entity->getName()),0777);
  72.             $filesystem->symlink($themePath."/".$entity->getName()."/assets"__DIR__."/../../public/themes/".strtolower($entity->getName()));
  73.             
  74.             
  75.             
  76.             //Step 1 : Copy Controllers
  77.             $finder->in($themePath."/".ucfirst($entity->getName())."/Controller");
  78.             $finder->files()->contains("Default");
  79.             
  80.             foreach ($finder as $file) {
  81.                 
  82.                 $file_contents file_get_contents($file->getPathname());
  83.                 $file_contents str_replace("Default\Controller"ucfirst($entity->getName())."\Controller"$file_contents);
  84.                 $file_contents str_replace("Default\Form"ucfirst($entity->getName())."\Form"$file_contents);
  85.                 
  86.                 file_put_contents($file->getPathname(), $file_contents);
  87.             }
  88.             
  89.             
  90.             
  91.             //Step 2 : Copy Forms
  92.             
  93.             $finder->in($themePath."/".ucfirst($entity->getName())."/Form");
  94.             $finder->files()->contains("Default");
  95.             //dd($finder->hasResults());
  96.             foreach ($finder as $file) {
  97.                 
  98.                 $file_contents file_get_contents($file->getPathname());
  99.                 $file_contents str_replace("Default\Form"ucfirst($entity->getName())."\Form"$file_contents);
  100.                 file_put_contents($file->getPathname(), $file_contents);
  101.             }
  102.             //Step 3 : Copy assets
  103.             
  104.             //$assetsPath = $pathFrontBundle."/Resources/public/assets";
  105.             //$filesystem->mirror($assetsPath."/default",$assetsPath."/".strtolower($entity->getName())); 
  106.                       
  107.             //Step 4 : Copy Templates
  108.             
  109.             $finder->in($themePath."/".ucfirst($entity->getName())."/templates");
  110.             
  111.             $finder->files()->contains("default");
  112.             //dd($finder->hasResults());
  113.             foreach ($finder as $file) {
  114.                 
  115.                 $file_contents file_get_contents($file->getPathname());
  116.                 $file_contents str_replace("default/"strtolower($entity->getName())."/"$file_contents);
  117.                 file_put_contents($file->getPathname(), $file_contents);
  118.             }
  119.             
  120.             
  121.         }
  122.         if($entity instanceof Settings){
  123.             if($entity->getFrontTheme()){
  124.                 $entity->setAssetFolderName(strtolower($entity->getFrontTheme()->getName()));
  125.             }
  126.             
  127.             $filesystem = new Filesystem();
  128.             
  129.             $path __DIR__."/../../public/uploads/".$entity->getAssetFolderName();
  130.             if(!$filesystem->exists($path) )
  131.             {
  132.                 $filesystem->mkdir($path,0777);
  133.                 $filesystem->mkdir($path."/pages",0777);
  134.                 $filesystem->mkdir($path."/shop",0777);
  135.                 
  136.             }
  137.             $pathFrontBundleRoutes __DIR__."/../IlaveU/FrontBundle/Resources/config/routes.yaml";
  138.             if($filesystem->exists($pathFrontBundleRoutes)){
  139.                 $configArray Yaml::parseFile($pathFrontBundleRoutes);
  140.                 $configArray["controllers"]["resource"] = "../../Controller/".ucfirst($entity->getAssetFolderName());
  141.                 
  142.                 $yamlConfig Yaml::dump($configArray);
  143.                 file_put_contents($pathFrontBundleRoutes$yamlConfig);
  144.             }
  145.             
  146.             
  147.         } 
  148.     
  149.         
  150.         if ($entity instanceof ExportExcel) {
  151.             $entityNameSpace $entity->getEntityNameSpace();
  152.             
  153.             $directFields $this->doctrine->getManager()->getClassMetadata($entityNameSpace)->getColumnNames();
  154.             $associationFields $this->doctrine->getManager()->getClassMetadata($entityNameSpace)->getAssociationMappings();
  155.             
  156.             
  157.             $entityRepository $this->doctrine->getRepository($entityNameSpace);
  158.             $repositoryMethods $this->getAllRepositoryMethods($entityRepository);
  159.             
  160.             $reflectionClass $this->doctrine->getManager()->getClassMetadata($entityNameSpace)->reflClass->getMethods();// All methods detailled
  161.             
  162.             //-------------
  163.             //dd($reflectionClass[0]->name);
  164.             $fields = [];
  165.             $translatedFields = [];
  166.             foreach($reflectionClass as $singleRefClass){
  167.                 if(count($entity->getFields()) > ){
  168.                     if($entity->isExcludeFields()){
  169.                         if(in_array($singleRefClass->name,$entity->getFields())){
  170.                             continue;
  171.                         }
  172.                     }else{
  173.                         if(!in_array($singleRefClass->name,$entity->getFields())){
  174.                             continue;
  175.                         }
  176.                     }
  177.                     
  178.                 }
  179.                 if (substr($singleRefClass->name03) === "get") {
  180.                     $fields[]=$singleRefClass->name;
  181.                 } else {
  182.                     continue;
  183.                 }
  184.             }
  185.             foreach($repositoryMethods as $singleMethod){
  186.                     $fields[]=$singleMethod;
  187.             }
  188.             
  189.             
  190.             //$selectedFieldsToExport = ["name","categoryProduct","subCategoryProduct","price"];
  191.             $selectedFieldsToExport = [];
  192.             $selectedFieldsToExport array_merge($selectedFieldsToExport,$fields);
  193.             //$selectedFieldsToExport = array_merge($selectedFieldsToExport,$reflectionClass);
  194.            
  195.             if(count($entity->getFindBy())>|| $entity->getStartingAt() || $entity->getEndingAt()){
  196.                 $queryBuilder $this->doctrine->getManager()->createQueryBuilder();
  197.                 
  198.                 $queryBuilder
  199.                     ->select('e')
  200.                     ->from($entityNameSpace'e')
  201.                     //->join('e.relatedEntity', 'r')
  202.                     // ->andWhere('JSON_CONTAINS(e.metaData, :metadataAPE) = 1  OR JSON_CONTAINS(e.metaData, :metadataNAF) = 1')
  203.                     // ->setParameter("metadataAPE",'{"key": "CodeAPE"}')
  204.                     // ->setParameter("metadataNAF",'{"key": "CodeNAF"}')
  205.                     ;
  206.                     
  207.                 foreach($entity->getFindBy() as $key => $value){
  208.                     $queryBuilder   
  209.                     ->andWhere('e.'.$key.' '.$value);
  210.                 }
  211.                 if($entity->getStartingAt()){
  212.                     $queryBuilder->andWhere('e.createdAt >= :startingAt')->setParameter('startingAt'$entity->getStartingAt());
  213.                 }
  214.                 if($entity->getEndingAt()){
  215.                     $queryBuilder->andWhere('e.createdAt <= :endingAt')->setParameter('endingAt'$entity->getEndingAt());
  216.                 }
  217.                 
  218.                 if(count($entity->getOrderBy())>0){
  219.                     foreach($entity->getOrderBy() as $key => $value){
  220.                         if(gettype($key)=="integer"){
  221.                             $queryBuilder->orderBy("e.".$value);
  222.                         }else{
  223.                             $queryBuilder->orderBy("e.".$key,$value);
  224.                         }
  225.                         
  226.                     }
  227.                     
  228.                 }
  229.                 //$queryBuilder->setMaxResults(500);
  230.                 
  231.                 $entityFetchAll $queryBuilder->getQuery()->getResult();
  232.                 
  233.                 
  234.                 
  235.                 
  236.                 
  237.                 
  238.                     
  239.             }else{
  240.                 $queryBuilder $this->doctrine->getManager()->createQueryBuilder();
  241.                 
  242.                     $queryBuilder
  243.                         ->select('e')
  244.                         ->from($entityNameSpace'e');
  245.                         //->join('e.relatedEntity', 'r')
  246.                         //$queryBuilder->setMaxResults(500);
  247.                     $entityFetchAll $queryBuilder->getQuery()->getResult();
  248.             }
  249.             
  250.             
  251.             
  252.             $arrayToExport = [];
  253.             $correctedFieldsName =[];
  254.             foreach($fields as $field){
  255.                 if($field == "getMetaData"){
  256.                     continue;
  257.                 }
  258.                 
  259.                 $name $this->getAbsoluteNameMethod($field);
  260.                 $correctedFieldsName[]= $this->translatorInterface->trans($name,[],"ilaveu-admin");
  261.             }
  262.             foreach($entity->getMetaDataFields() as $singleField){
  263.                 $correctedFieldsName[]= $this->translatorInterface->trans($singleField,[],"ilaveu-admin");
  264.             }
  265.             
  266.             
  267.             
  268.             $arrayToExport[]=$correctedFieldsName;
  269.             
  270.             foreach($entityFetchAll as $singleEntityInstance){
  271.                 
  272.                 $singleRow =[];
  273.                 $singleMetaDataValue = [];
  274.                 foreach($fields as $singleField){
  275.                     $value=null;
  276.                     $valueSub=null;
  277.                     $valueParent=null;
  278.                     
  279.                     
  280.                    
  281.                     
  282.                     
  283.                         if(method_exists($singleEntityInstance,$singleField)){
  284.                             
  285.                             
  286.                             
  287.                             $value $singleEntityInstance->{$singleField}();
  288.                             
  289.                                 if($value instanceof Collection){
  290.                                     $value implode("\n"$value->toArray());
  291.                                     //dd($value);
  292.                                 }elseif(is_array($value)){
  293.                                     
  294.                                     if($singleField == "getMetaData"){
  295.                                         
  296.                                         
  297.                                         foreach($entity->getMetaDataFields() as $singleField){
  298.                                             $singleMetaDataValue[] = $this->getMetaDataValue($value,$singleField);
  299.                                             continue;
  300.                                         }
  301.                                         continue;
  302.                                     
  303.                                     foreach($value as $k=>$v){
  304.                                         if(in_array($k,$entity->getMetaDataFields())){
  305.                                                 
  306.                                                 $singleMetaDataValue[]=$v["value"];
  307.                                                 
  308.                                         }else
  309.                                         dd("None");
  310.                                             
  311.                                             
  312.                                             
  313.                                             
  314.                                         }
  315.                                         
  316.                                         continue;
  317.                                     }
  318.                                     
  319.                                     
  320.                                     $value $this->implode_multidimensional($value,"\n");
  321.                                     
  322.                                 }elseif(gettype($value) == "string"){
  323.                                     $value $this->translatorInterface->trans($value);
  324.                                 }
  325.                             
  326.     
  327.                         }elseif(method_exists($entityRepository,$singleField)){
  328.                             $value $entityRepository->{$singleField}($singleEntityInstance->getId());
  329.                             
  330.                         
  331.                             if(is_array($value)){
  332.                                 
  333.                                 // find the index of the value 'orange'
  334.                                 $field $this->getAbsoluteNameMethod($singleField);
  335.                                
  336.                                 $translatedField $this->translatorInterface->trans($field);
  337.                                 $index array_search($translatedField$arrayToExport[0]);
  338.                                 // if the value exists in the array, remove it
  339.                                 if ($index !== false) {
  340.                                     unset($arrayToExport[0][$index]);
  341.                                 }
  342.                                 // re-index the array
  343.                                 //$arrayToExport = array_values($arrayToExport[0]);
  344.                                // dd($value);
  345.                                 
  346.                                 foreach($value as $singleData){
  347.                                     $translatedKey $this->translatorInterface->trans($singleData["key"]);
  348.                                     if(!in_array($translatedKey,$arrayToExport[0])){
  349.                                         
  350.                                         $arrayToExport[0][] = $this->translatorInterface->trans($translatedKey);
  351.                                     }
  352.                                     
  353.                                     $singleRow[]=$singleData["value"];
  354.                                 }
  355.                                 
  356.                                 continue;
  357.                             }else{
  358.                                 $value $this->translatorInterface->trans($value);
  359.                             }
  360.                         }
  361.                         $singleRow[]=$value;
  362.                     
  363.                     
  364.                 }
  365.                 
  366.                 
  367.                 
  368.                 
  369.                 foreach($singleMetaDataValue  as $singleMetaDataVal){
  370.                     //dd($singleMetaDataVal);
  371.                     if(is_array($singleMetaDataVal)){
  372.                         
  373.                         $singleRow[] = $this->implode_multidimensional($singleMetaDataVal,", ");
  374.                         continue;
  375.                     }
  376.                     $singleRow[] = $singleMetaDataVal;
  377.                 }
  378.                 $arrayToExport[]=$singleRow;
  379.                 //dd($arrayToExport);
  380.             }
  381.             //dd($arrayToExport);
  382.             
  383.             
  384.             
  385.             
  386.             $mySpreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
  387.             $mySpreadsheet->removeSheetByIndex(0);
  388.             $worksheet1 = new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet($mySpreadsheet"List Produits");
  389.             $mySpreadsheet->addSheet($worksheet10);
  390.             $worksheet1->fromArray($arrayToExport,null,"A1");
  391.             // Set the auto filter to cover all the data
  392.             $lastColumn $worksheet1->getHighestColumn();
  393.             $lastRow $worksheet1->getHighestDataRow();
  394.             $range "A1:$lastColumn$lastRow";
  395.             $worksheet1->setAutoFilter($range);
  396.             foreach ($worksheet1->getColumnIterator() as $column)
  397.                 {
  398.                     $worksheet1->getColumnDimension($column->getColumnIndex())->setAutoSize(true);
  399.                     
  400.                     
  401.                 }
  402.                 foreach ($worksheet1->getRowIterator() as $row) {
  403.                     foreach ($row->getCellIterator() as $cell) {
  404.                         $cell->getStyle()->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_TOP);
  405.                     }
  406.                 }
  407.                 $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($mySpreadsheet);
  408.                 
  409.                 $parts explode("\\"$entityNameSpace);
  410.                 $nameOfFile end($parts);
  411.                 $nameOfFile strtolower($nameOfFile)."-".$entity->getCreatedAt()->format("Y-m-d-H-i");
  412.                 //echo $lastWord; // output: CategoryProduct
  413.                 $settings $this->doctrine->getManager()->getRepository(Settings::class)->findOneBy(["code"=>"main"]);
  414.                 $assetFolderName $settings->getAssetFolderName();
  415.                 $assetFolderName strtolower($assetFolderName);
  416.                 $writer->save("uploads/".$assetFolderName."/exports/".$nameOfFile.".xlsx");
  417.                 
  418.                 $entity->setGeneratedFilePath("uploads/".$assetFolderName."/exports/".$nameOfFile.".xlsx");
  419.                 $entity->setEntityNameSpace($entityNameSpace);
  420.         
  421.             
  422.         }
  423.                 if ($entity instanceof User) {
  424.                     
  425.                    $entity->setPassword(
  426.                    $this->passwordEncoder->hashPassword(
  427.                             $entity,
  428.                             $entity->getPassword()
  429.                 ));
  430.                 
  431.             
  432.             
  433.             
  434.                 
  435.         }
  436.     }
  437.     public function beforeUpdated(BeforeEntityUpdatedEvent $event)
  438.     {
  439.         $entity $event->getEntityInstance();
  440.         
  441.         if($entity instanceof Settings){
  442.             $filesystem = new Filesystem();
  443.             $pathFrontBundle __DIR__."/../IlaveU/FrontBundle";
  444.             $themePath $pathFrontBundle."/Themes";
  445.             if($entity->getFrontTheme()){
  446.                 $entity->setAssetFolderName($entity->getFrontTheme()->getName());
  447.                 if(!$filesystem->exists(__DIR__."/../../public/themes/".strtolower($entity->getFrontTheme()->getName()))){
  448.                     $filesystem->symlink($themePath."/".$entity->getFrontTheme()->getName()."/assets"__DIR__."/../../public/themes/".strtolower($entity->getFrontTheme()->getName()));
  449.                 }
  450.                
  451.             }
  452.             
  453.             
  454.             $path __DIR__."/../../public/uploads/".$entity->getAssetFolderName();
  455.             if(!$filesystem->exists($path) )
  456.             {
  457.                 $filesystem->mkdir($path,0777);
  458.                 $filesystem->mkdir($path."/pages",0777);
  459.                 $filesystem->mkdir($path."/shop",0777);
  460.                 
  461.             }
  462.             
  463.             $pathFrontBundleRoutes __DIR__."/../IlaveU/FrontBundle/Resources/config/routes.yaml";
  464.             if($filesystem->exists($pathFrontBundleRoutes)){
  465.                 $configArray Yaml::parseFile($pathFrontBundleRoutes);
  466.                 $configArray["controllers"]["resource"] = "../../Themes/".ucfirst($entity->getAssetFolderName())."/Controller";
  467.                 
  468.                 $yamlConfig Yaml::dump($configArray);
  469.                 file_put_contents($pathFrontBundleRoutes$yamlConfig);
  470.             }
  471.             
  472.         }
  473.       
  474.    
  475.      
  476.     }
  477.     public function beforeDelete(BeforeEntityDeletedEvent $event){
  478.         $entity $event->getEntityInstance();
  479.         if($entity instanceof FrontTheme){
  480.             //$entity->getSettings()->setFrontTheme(null);
  481.             $filesystem = new Filesystem();
  482.             //dd(__DIR__."/../../");
  483.             $pathFrontBundle __DIR__."/../IlaveU/FrontBundle";
  484.             
  485.             $themePath $pathFrontBundle."/Themes";
  486.             if($filesystem->exists($themePath."/".ucfirst($entity->getName()) ) ){
  487.             
  488.             $this->zipDirectory($themePath."/".ucfirst($entity->getName()),__DIR__."/../../public/archive-themes/".strtolower($entity->getName()).".zip" );
  489.             
  490.             $filesystem->remove($themePath."/".ucfirst($entity->getName()));
  491.             
  492.                 
  493.                 
  494.             
  495.                
  496.             }
  497.             
  498.             //$filesystem->remove($pathFrontBundle."/Resources/public/assets/".strtolower($entity->getName()));
  499.             $settings $this->doctrine->getManager()->getRepository(Settings::class)->findOneBy(["code"=>"main"]);
  500.             $currentTheme $settings->getAssetFolderName();
  501.             $entity->removeSetting($settings);
  502.             $settings->setAssetFolderName("Default");
  503.             $this->doctrine->getManager()->persist($settings);
  504.             if(strtolower($entity->getName()) == strtolower($currentTheme) ){
  505.                 $pathFrontBundleRoutes __DIR__."/../IlaveU/FrontBundle/Resources/config/routes.yaml";
  506.                 if($filesystem->exists($pathFrontBundleRoutes)){
  507.                     $configArray Yaml::parseFile($pathFrontBundleRoutes);
  508.     
  509.                     $configArray["controllers"]["resource"] = "../../Themes/Default/Controller";
  510.                     
  511.     
  512.                     $yamlConfig Yaml::dump($configArray);
  513.     
  514.                     file_put_contents($pathFrontBundleRoutes$yamlConfig);
  515.                 }
  516.             }
  517.             
  518.         }
  519.        
  520.     }
  521.     public function  exportFile($records) {
  522.         $heading false;
  523.             if(!empty($records))
  524.               foreach($records as $row) {
  525.                 if(!$heading) {
  526.                   // display field/column names as a first row
  527.                   echo implode("\t"array_keys($row)) . "\n";
  528.                   $heading true;
  529.                 }
  530.                 echo implode("\t"array_values($row)) . "\n";
  531.             }
  532.         
  533.     }
  534.     public static function zipDirectory($directory$zipName)
  535. {
  536.     // Get real path for our folder
  537. $rootPath realpath($directory);
  538. // Initialize archive object
  539. $zip = new ZipArchive();
  540. $zip->open($zipNameZipArchive::CREATE ZipArchive::OVERWRITE);
  541. // Initialize empty "delete list"
  542. $filesToDelete = array();
  543. // Create recursive directory iterator
  544. /** @var SplFileInfo[] $files */
  545. $files = new RecursiveIteratorIterator(
  546.     new RecursiveDirectoryIterator($rootPath),
  547.     RecursiveIteratorIterator::LEAVES_ONLY
  548. );
  549. foreach ($files as $name => $file)
  550. {
  551.     // Skip directories (they would be added automatically)
  552.     if (!$file->isDir())
  553.     {
  554.         // Get real and relative path for current file
  555.         $filePath $file->getRealPath();
  556.         $relativePath substr($filePathstrlen($rootPath) + 1);
  557.         // Add current file to archive
  558.         $zip->addFile($filePath$relativePath);
  559.         // Add current file to "delete list"
  560.         // delete it later cause ZipArchive create archive only after calling close function and ZipArchive lock files until archive created)
  561.         if ($file->getFilename() != 'important.txt')
  562.         {
  563.             $filesToDelete[] = $filePath;
  564.         }
  565.     }
  566. }
  567. // Zip archive will be created only after closing object
  568. $zip->close();
  569. return $zip;
  570. }
  571. function getAbsoluteNameMethod($input) {
  572.     // Remove the "get" prefix from the input string
  573.   $input preg_replace('/^get/'''$input);
  574.   
  575.   // Replace all capital letters with a space followed by the letter
  576.   $output preg_replace('/([A-Z])/'' $1'$input);
  577.   
  578.   // Remove any leading or trailing spaces
  579.   $output trim($output);
  580.   
  581.   // Convert the first character to uppercase
  582.   $output ucfirst($output);
  583.   
  584.   // Return the final result
  585.   return $output;
  586.   }
  587.   public function getAllRepositoryMethods($repository)
  588. {
  589.     $reflectionClass = new ReflectionClass(get_class($repository));
  590.     $methods $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC);
  591.     $findMethods = [];
  592.     foreach ($methods as $method) {
  593.         $methodName $method->getName();
  594.         if (strpos($methodName'export') === 0) {
  595.             $findMethods[] = $methodName;
  596.         }
  597.     }
  598.     return $findMethods;
  599. }
  600. function is_multidimensional(array $array) {
  601.     foreach ($array as $element) {
  602.         if (is_array($element)) {
  603.             return true;
  604.         }
  605.     }
  606.     return false;
  607. }
  608. function implode_multidimensional(array $array$glue ', ') {
  609.     $result = [];
  610.     
  611.     foreach ($array as $key => $element) {
  612.         if (is_array($element)) {
  613.             $element $this->implode_multidimensional($element$glue);
  614.         }
  615.         //$result[] = "{$key}:{$element}";
  616.         if(!in_array("{$element}",$result)){
  617.             $result[] = "{$element}";
  618.         }
  619.         
  620.         
  621.     }
  622.     
  623.     return implode($glue$result);
  624. }
  625. public function getMetaDataValue($jsonData$searchKey)
  626.     {
  627.         
  628.         $dataArray = (array)$jsonData;
  629.         
  630.         
  631.         foreach ($dataArray as $item) {
  632.             if (isset($item['key']) && $item['key'] === $searchKey) {
  633.                 return $item['value'];
  634.             }
  635.         }
  636.         return null;
  637.     }
  638. }