src/StartPlatz/Bundle/MentorsBundle/Controller/PublicController.php line 406

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace App\StartPlatz\Bundle\MentorsBundle\Controller;
  3. use App\StartPlatz\Bundle\MentorsBundle\Service\MentorService;
  4. use App\StartPlatz\Bundle\MentorsBundle\Service\WordPressMenuService;
  5. use Doctrine\ORM\EntityManagerInterface;
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\Routing\Annotation\Route;
  10. /**
  11.  * PublicController
  12.  *
  13.  * Handles public-facing mentor and expert pages
  14.  */
  15. class PublicController extends AbstractController
  16. {
  17.     private MentorService $mentorService;
  18.     private WordPressMenuService $menuService;
  19.     private EntityManagerInterface $entityManager;
  20.     public function __construct(
  21.         MentorService $mentorService,
  22.         WordPressMenuService $menuService,
  23.         EntityManagerInterface $entityManager
  24.     ) {
  25.         $this->mentorService $mentorService;
  26.         $this->menuService $menuService;
  27.         $this->entityManager $entityManager;
  28.     }
  29.     /**
  30.      * STARTPLATZ Mentors page
  31.      */
  32.     #[Route('/mentors/startplatz'name'mentors_startplatz')]
  33.     #[Route('/en/mentors/startplatz'name'mentors_startplatz_en')]
  34.     public function startplatzMentorsAction(Request $request): Response
  35.     {
  36.         $locale $request->getLocale();
  37.         $isEnglish str_contains($request->getPathInfo(), '/en/');
  38.         // Get all mentors (no pagination for section-based display)
  39.         $allMentors $this->mentorService->getMentorsByCategory(
  40.             MentorService::CATEGORY_STARTPLATZ,
  41.             []
  42.         );
  43.         // Define categories in the order they should appear (matching original page)
  44.         $categoryOrder = [
  45.             'apps-it' => 'Apps und IT',
  46.             'marketing' => 'Marketing',
  47.             'finanzierung' => 'Finanzierung',
  48.             'gruendung-fuehrung' => 'Gründung und Führung',
  49.             'recht' => 'Recht',
  50.             'design' => 'Design',
  51.             'wirtschaftspruefung-steuerberatung' => 'Wirtschaftsprüfung und Steuerberatung',
  52.             'versicherung' => 'Versicherung'
  53.         ];
  54.         // Group mentors by category
  55.         $mentorsByCategory = [];
  56.         // Initialize all categories even if empty
  57.         foreach ($categoryOrder as $categoryKey => $categoryLabel) {
  58.             $mentorsByCategory[$categoryKey] = [
  59.                 'label' => $categoryLabel,
  60.                 'mentors' => []
  61.             ];
  62.         }
  63.         // Process each mentor
  64.         foreach ($allMentors as $mentorProfile) {
  65.             $member $mentorProfile->getMember();
  66.             $metadata $mentorProfile->getMetadata() ?? [];
  67.             // Get mentor's categories from metadata ONLY
  68.             // If no categories defined, assign to default category
  69.             $mentorCategories $metadata['categories'] ?? ['gruendung-fuehrung'];
  70.             if (!is_array($mentorCategories)) {
  71.                 $mentorCategories = [$mentorCategories];
  72.             }
  73.             // Prepare mentor data
  74.             $mentorData = [
  75.                 'id' => $member->getId(),
  76.                 'name' => trim($member->getFirstName() . ' ' $member->getLastName()),
  77.                 'firstName' => $member->getFirstName(),
  78.                 'lastName' => $member->getLastName(),
  79.                 'email' => $member->getEmail(),
  80.                 'title' => $member->getJobTitle() ?? '',
  81.                 'academicTitle' => $member->getTitle() ?? '',
  82.                 'company' => $mentorProfile->getFirma() ?? $member->getCompany() ?? '',
  83.                 'description' => $mentorProfile->getProfileDe() ?? $member->getDescription() ?? '',
  84.                 'image' => $member->getImageLink() ?? 'https://res.cloudinary.com/startplatz/image/upload/v1637360496/Wordpress/Sprechstunden/Sprechstunden_Platzhalter.jpg',
  85.                 'skills' => [],
  86.                 'slug' => strtolower(str_replace(' ''-'trim($member->getFirstName() . '-' $member->getLastName())))
  87.             ];
  88.             // Add to appropriate categories (or to first category if none specified)
  89.             if (empty($mentorCategories)) {
  90.                 // If no category specified, add to first category
  91.                 $firstKey array_key_first($categoryOrder);
  92.                 $mentorsByCategory[$firstKey]['mentors'][] = $mentorData;
  93.             } else {
  94.                 // Add to all specified categories
  95.                 foreach ($mentorCategories as $category) {
  96.                     if (isset($mentorsByCategory[$category])) {
  97.                         $mentorsByCategory[$category]['mentors'][] = $mentorData;
  98.                     }
  99.                 }
  100.             }
  101.         }
  102.         // Remove empty categories if needed (optional)
  103.         // $mentorsByCategory = array_filter($mentorsByCategory, function($category) {
  104.         //     return !empty($category['mentors']);
  105.         // });
  106.         return $this->render('@StartPlatzMentors/Public/startplatz-mentors.html.twig', [
  107.             'mentorsByCategory' => $mentorsByCategory,
  108.             'isEnglish' => $isEnglish
  109.         ]);
  110.     }
  111.     /**
  112.      * Categorize mentor by their skills
  113.      */
  114.     private function categorizeMentorBySkills(array $skills): array
  115.     {
  116.         // Define category keywords (German and English)
  117.         $categoryKeywords = [
  118.             'tech-development' => [
  119.                 'entwicklung''development''programming''software''code''coding',
  120.                 'python''javascript''java''php''backend''frontend''fullstack',
  121.                 'devops''cloud''aws''docker''kubernetes''api''database''sql',
  122.                 'machine learning''ai''ki''artificial intelligence''deep learning',
  123.                 'neural''tensorflow''pytorch''data science''algorithm''tech''it',
  124.                 'mobile''app''web''security''blockchain''crypto''iot''embedded',
  125.                 'github''gitlab''git''bitbucket''technologie''technology',
  126.                 'react''angular''vue''node''typescript''swift''kotlin',
  127.                 'android''ios''flutter''xamarin''unity''unreal',
  128.                 'azure''gcp''serverless''microservices''ci/cd''jenkins',
  129.                 'mysql''postgresql''mongodb''redis''elasticsearch''ingenieurwesen'
  130.             ],
  131.             'business-strategy' => [
  132.                 'strategy''strategie''business''geschäft''model''skalierung',
  133.                 'scaling''growth''wachstum''management''führung''leadership',
  134.                 'operations''prozesse''transformation''innovation''planung',
  135.                 'roadmap''vision''mission''okr''kpi''agile''scrum''lean',
  136.                 'startup''gründung''entrepreneurship''ceo''coo''executive',
  137.                 'consulting''beratung''change''digital transformation'
  138.             ],
  139.             'sales-marketing' => [
  140.                 'sales''vertrieb''marketing''growth''hacking''b2b''b2c',
  141.                 'seo''sea''sem''social media''content''brand''marke''pr',
  142.                 'communication''kommunikation''crm''lead''conversion''funnel',
  143.                 'customer''acquisition''retention''email''advertising''werbung',
  144.                 'campaign''analytics''performance''influencer''storytelling',
  145.                 'copywriting''demand''generation''outbound''inbound'
  146.             ],
  147.             'finance-legal' => [
  148.                 'finance''finanzen''funding''investment''investor''vc',
  149.                 'venture''capital''förderung''grant''pitch''valuation',
  150.                 'legal''recht''anwalt''lawyer''compliance''dsgvo''gdpr',
  151.                 'vertrag''contract''ip''patent''steuer''tax''accounting',
  152.                 'buchführung''controlling''budget''cashflow''revenue''profit',
  153.                 'seed''series''exit''ipo''due diligence''term sheet'
  154.             ],
  155.             'product-design' => [
  156.                 'product''produkt''design''ux''ui''user experience''usability',
  157.                 'customer''development''mvp''prototype''iteration''lean startup',
  158.                 'feedback''research''testing''interface''interaction',
  159.                 'creative''kreativ''brand''visual''figma''sketch''adobe',
  160.                 'wireframe''mockup''persona''journey''map''sprint',
  161.                 'discovery''validation''feature''roadmap''backlog'
  162.             ]
  163.         ];
  164.         if (empty($skills)) {
  165.             return ['business-strategy']; // Default category
  166.         }
  167.         // Convert skills to lowercase for matching
  168.         $skillsLower array_map('strtolower'$skills);
  169.         $categoryScores = [];
  170.         foreach ($categoryKeywords as $category => $keywords) {
  171.             $score 0;
  172.             $matches = [];
  173.             foreach ($skillsLower as $skill) {
  174.                 // Remove hashtag if present
  175.                 $skill ltrim(trim($skill), '#');
  176.                 // Split hyphenated words for better matching
  177.                 $skillParts preg_split('/[-\s]+/'$skill);
  178.                 foreach ($keywords as $keyword) {
  179.                     // Exact match: 3 points
  180.                     if ($skill === $keyword) {
  181.                         $score += 3;
  182.                         $matches[] = $skill;
  183.                         break; // Don't count same skill multiple times
  184.                     }
  185.                     // Check parts of hyphenated words
  186.                     foreach ($skillParts as $part) {
  187.                         if ($part === $keyword) {
  188.                             $score += 2// Give 2 points for exact part match
  189.                             $matches[] = $skill;
  190.                             break 2// Break both loops
  191.                         }
  192.                     }
  193.                     // Partial match: 1 point - but only for whole word matches
  194.                     // Use word boundaries to avoid false positives like "it" in "exit"
  195.                     if (preg_match('/\b' preg_quote($keyword'/') . '\b/i'$skill)) {
  196.                         $score += 1;
  197.                         $matches[] = $skill;
  198.                         break;
  199.                     }
  200.                 }
  201.             }
  202.             // Only consider categories with score >= 2
  203.             if ($score >= 2) {
  204.                 $categoryScores[$category] = [
  205.                     'score' => $score,
  206.                     'matches' => array_unique($matches)
  207.                 ];
  208.             }
  209.         }
  210.         // If no categories matched, return default
  211.         if (empty($categoryScores)) {
  212.             return ['business-strategy'];
  213.         }
  214.         // Sort by score and return top 3 categories
  215.         arsort($categoryScores);
  216.         return array_slice(array_keys($categoryScores), 03);
  217.     }
  218.     /**
  219.      * AI Accelerator Mentors page
  220.      */
  221.     #[Route('/accelerator/mentors'name'accelerator_mentors')]
  222.     #[Route('/en/accelerator/mentors'name'accelerator_mentors_en')]
  223.     public function acceleratorMentorsAction(Request $request): Response
  224.     {
  225.         $isEnglish str_contains($request->getPathInfo(), '/en/');
  226.         // Get filters
  227.         $filters = [
  228.             'search' => $request->get('search'),
  229.             'expertise' => $request->get('expertise'),
  230.             'techStack' => $request->get('tech')
  231.         ];
  232.         // Get mentors
  233.         $allMentors $this->mentorService->getMentorsByCategory(
  234.             MentorService::CATEGORY_ACCELERATOR,
  235.             array_filter($filters)
  236.         );
  237.         // Prepare mentor data arrays
  238.         $mentorsData = [];
  239.         foreach ($allMentors as $mentorProfile) {
  240.             $member $mentorProfile->getMember();
  241.             $metadata $mentorProfile->getMetadata() ?? [];
  242.             // Prepare skills array from member
  243.             $skills = [];
  244.             $skillsString $member->getSkills();
  245.             if (!empty($skillsString)) {
  246.                 $skills preg_split('/[\s,]+/'$skillsString);
  247.                 $skills array_filter($skills, function($s) { return !empty(trim($s)); });
  248.             }
  249.             // Categorize mentor based on skills
  250.             $categories $this->categorizeMentorBySkills($skills);
  251.             // Prepare mentor data
  252.             $mentorData = [
  253.                 'id' => $member->getId(),
  254.                 'name' => trim($member->getFirstName() . ' ' $member->getLastName()),
  255.                 'firstName' => $member->getFirstName(),
  256.                 'lastName' => $member->getLastName(),
  257.                 'email' => $member->getEmail(),
  258.                 'title' => $member->getJobTitle() ?? $metadata['title'] ?? '',
  259.                 'academicTitle' => $member->getTitle() ?? '',
  260.                 'company' => $member->getCompany() ?? $metadata['company'] ?? '',
  261.                 'mentorFirma' => $mentorProfile->getFirma(),
  262.                 'description' => $member->getDescription() ?? $metadata['description'] ?? '',
  263.                 'profileImage' => $member->getImageLink() ?? $metadata['profileImage'] ?? null,
  264.                 'image' => $member->getImageLink() ?? $metadata['profileImage'] ?? null,
  265.                 'skills' => $skills,
  266.                 'categories' => $categories,
  267.                 'expertise' => $metadata['expertise'] ?? null,
  268.                 'linkedin' => $metadata['linkedin'] ?? null,
  269.                 'mentorProfile' => $mentorProfile->getProfileDe(),
  270.                 'jobTitle' => $member->getJobTitle(),
  271.                 'mentorMetadata' => $metadata,
  272.                 'github' => $metadata['github'] ?? null,
  273.                 'twitter' => $metadata['twitter'] ?? null
  274.             ];
  275.             $mentorsData[] = $mentorData;
  276.         }
  277.         // Get menu from WordPress
  278.         $menu $this->menuService->getAcceleratorMenu($isEnglish$request->getPathInfo());
  279.         return $this->render('@StartPlatzMentors/Public/accelerator-mentors.html.twig', [
  280.             'mentors' => $mentorsData,
  281.             'searchQuery' => $filters['search'] ?? '',
  282.             'currentExpertise' => $filters['expertise'] ?? null,
  283.             'currentTechStack' => $filters['techStack'] ?? null,
  284.             'isEnglish' => $isEnglish,
  285.             'pageTitle' => $isEnglish 'AI Accelerator Mentors' 'KI Accelerator Mentoren',
  286.             'pageDescription' => $isEnglish
  287.                 'Expert mentors for AI startups'
  288.                 'Experten-Mentoren für KI-Startups',
  289.             'menu' => $menu
  290.         ]);
  291.     }
  292.     /**
  293.      * Experts in Residence page
  294.      */
  295.     #[Route('/accelerator/experts-in-residence'name'experts_residence')]
  296.     #[Route('/en/accelerator/experts-in-residence'name'experts_residence_en')]
  297.     public function expertsResidenceAction(Request $request): Response
  298.     {
  299.         $isEnglish str_contains($request->getPathInfo(), '/en/');
  300.         // Get filters
  301.         $filters = [
  302.             'search' => $request->get('search'),
  303.             'specialization' => $request->get('specialization'),
  304.             'limit' => 20,
  305.             'offset' => ($request->get('page'1) - 1) * 20
  306.         ];
  307.         // Get experts
  308.         $allExperts $this->mentorService->getMentorsByCategory(
  309.             MentorService::CATEGORY_EXPERTS,
  310.             array_filter($filters)
  311.         );
  312.         // Prepare expert data arrays
  313.         $expertsData = [];
  314.         foreach ($allExperts as $mentorProfile) {
  315.             $member $mentorProfile->getMember();
  316.             $metadata $mentorProfile->getMetadata() ?? [];
  317.             // Prepare expert data
  318.             $expertData = [
  319.                 'id' => $member->getId(),
  320.                 'name' => trim($member->getFirstName() . ' ' $member->getLastName()),
  321.                 'firstName' => $member->getFirstName(),
  322.                 'lastName' => $member->getLastName(),
  323.                 'email' => $member->getEmail(),
  324.                 'profileImage' => $member->getImageLink(),
  325.                 'whoAmI' => $member->getDescription() ?: $mentorProfile->getProfileDe(),
  326.                 'skills' => $member->getSkills(),
  327.                 'linkedin' => $member->getLinkedin(),
  328.                 'twitter' => $member->getTwitter(),
  329.                 'expertMetadata' => $metadata,
  330.                 'title' => $member->getJobTitle() ?? $metadata['title'] ?? '',
  331.                 'academicTitle' => $member->getTitle() ?? '',
  332.                 'company' => $member->getCompany() ?? $metadata['companyAffiliation'] ?? '',
  333.                 'description' => $member->getDescription(),
  334.                 'image' => $member->getImageLink(),
  335.                 'specializations' => $metadata['expertiseAreas'] ?? $mentorProfile->getExpertiseAreas() ?? [],
  336.                 'currentProject' => $metadata['currentProject'] ?? null,
  337.                 'website' => $metadata['website'] ?? null
  338.             ];
  339.             $expertsData[] = $expertData;
  340.         }
  341.         // Determine language for template
  342.         $language $isEnglish 'en' 'de';
  343.         // Get menu from WordPress
  344.         $menu $this->menuService->getAcceleratorMenu($isEnglish$request->getPathInfo());
  345.         return $this->render('@StartPlatzMentors/Public/experts-residence.html.twig', [
  346.             'experts' => $expertsData,
  347.             'searchQuery' => $filters['search'] ?? '',
  348.             'currentSpecialization' => $filters['specialization'] ?? null,
  349.             'isEnglish' => $isEnglish,
  350.             'language' => $language,
  351.             'pageTitle' => 'Expert-in-Residence Program',
  352.             'pageDescription' => $isEnglish
  353.                 'Making local excellence in Artificial Intelligence visible and impactful'
  354.                 'Lokale Exzellenz in der Künstlichen Intelligenz sichtbar und wirksam machen',
  355.             'menu' => $menu
  356.         ]);
  357.     }
  358. }