Your project should not use deprecated PHP features 2

More information: https://insight.symfony.com/what-we-analyse/php.use_deprecated_function

  1. return true;
  2. }
  3. $finfo = finfo_open(FILEINFO_MIME_TYPE);
  4. $mimeType = finfo_file($finfo, $filePath);
  5. finfo_close($finfo);
    finfo_close() has been deprecated in PHP 8.5 and will be removed from PHP in the next major version.
    Last edited by clicshopping
  6. // Define allowed MIME types based on configured extensions
  7. $allowedMimeTypes = [
  8. // Images
  9. 'image/jpeg' => ['jpg', 'jpeg'],
  1. curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
  2. }
  3. $response = curl_exec($ch);
  4. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  5. curl_close($ch);
    curl_close() has been deprecated in PHP 8.5 and will be removed from PHP in the next major version.
    Last edited by clicshopping
  6. if ($response === false) {
  7. return ['error' => ['message' => 'Stripe API request failed (curl).']];
  8. }

Your project should not use insecure random number functions

More information: https://insight.symfony.com/what-we-analyse/php.use_insecure_random_function

  1. // Fallback: use multiple sources of entropy
  2. // This should never happen on PHP 7.0+ but provides safety
  3. $fallback = hash('sha256',
  4. uniqid('antispam_', true) .
  5. microtime(true) .
  6. mt_rand() .
    The function mt_rand() is not cryptographically secure. Use random_int() or random_bytes() instead.
    Last edited by clicshopping
  7. (function_exists('random_bytes') ? bin2hex(random_bytes(16)) : '')
  8. );
  9. trigger_error(
  10. 'Failed to generate cryptographically secure secret, using fallback. Error: ' . $e->getMessage(),

Your project should use dedicated PHP string functions 55

More information: https://insight.symfony.com/what-we-analyse/php.use_string_function

  1. ['grow', 'shrink']
  2. ];
  3. // Check if goals contain contradictory terms
  4. foreach ($contradictions as $pair) {
  5. $has1in1 = strpos($goal1, $pair[0]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $has2in1 = strpos($goal1, $pair[1]) !== false;
  7. $has1in2 = strpos($goal2, $pair[0]) !== false;
  8. $has2in2 = strpos($goal2, $pair[1]) !== false;
  9. // If obj1 has first term and obj2 has second term (or vice versa)
  1. ];
  2. // Check if goals contain contradictory terms
  3. foreach ($contradictions as $pair) {
  4. $has1in1 = strpos($goal1, $pair[0]) !== false;
  5. $has2in1 = strpos($goal1, $pair[1]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $has1in2 = strpos($goal2, $pair[0]) !== false;
  7. $has2in2 = strpos($goal2, $pair[1]) !== false;
  8. // If obj1 has first term and obj2 has second term (or vice versa)
  9. if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
  1. // Check if goals contain contradictory terms
  2. foreach ($contradictions as $pair) {
  3. $has1in1 = strpos($goal1, $pair[0]) !== false;
  4. $has2in1 = strpos($goal1, $pair[1]) !== false;
  5. $has1in2 = strpos($goal2, $pair[0]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $has2in2 = strpos($goal2, $pair[1]) !== false;
  7. // If obj1 has first term and obj2 has second term (or vice versa)
  8. if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
  9. // Check if they're operating on similar subjects
  1. // Check if goals contain contradictory terms
  2. foreach ($contradictions as $pair) {
  3. $has1in1 = strpos($goal1, $pair[0]) !== false;
  4. $has2in1 = strpos($goal1, $pair[1]) !== false;
  5. $has1in2 = strpos($goal2, $pair[0]) !== false;
  6. $has2in2 = strpos($goal2, $pair[1]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. // If obj1 has first term and obj2 has second term (or vice versa)
  8. if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
  9. // Check if they're operating on similar subjects
  10. $similarity = $this->calculateSimilarity($obj1, $obj2);
  1. 'database', 'table', 'index', 'query', 'cache', 'memory',
  2. 'file', 'log', 'configuration', 'setting', 'registry'
  3. ];
  4. foreach ($resourceKeywords as $keyword) {
  5. if (strpos($text, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $resources[] = $keyword;
  7. }
  8. }
  9. return array_unique($resources);
  1. 'optimize' => ['optimize', 'improve', 'enhance', 'tune']
  2. ];
  3. foreach ($operationPatterns as $operation => $keywords) {
  4. foreach ($keywords as $keyword) {
  5. if (strpos($text, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $operations[] = $operation;
  7. break;
  8. }
  9. }
  10. }
  1. if (isset($metadata['engines_used']) && is_array($metadata['engines_used'])) {
  2. $modesUsed = $metadata['engines_used'];
  3. $isHybrid = count($modesUsed) > 1;
  4. } elseif (isset($metadata['mode_type'])) {
  5. $modesUsed = [$metadata['mode_type']];
  6. $isHybrid = (strpos($metadata['mode_type'], 'hybrid') !== false);
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. }
  8. // Display hybrid label if applicable
  9. if ($isHybrid) {
  10. $output .= "<strong>" . $this->language->getDef('text_rag_hybrid_search') . "</strong><br>";
  1. // Display mode badges
  2. $badges = [];
  3. foreach ($modesUsed as $mode) {
  4. $badge = '';
  5. if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  7. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
  8. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  9. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  10. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  1. foreach ($modesUsed as $mode) {
  2. $badge = '';
  3. if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
  4. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  5. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  7. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  8. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  9. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
  10. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  1. if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
  2. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  3. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
  4. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  5. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  7. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
  8. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  9. } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
  10. $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
  1. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  2. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
  3. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  4. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  5. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  6. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  8. } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
  9. $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
  10. }
  1. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  2. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  3. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  4. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
  5. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  6. } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
  8. }
  9. if (!empty($badge)) {
  10. $badges[] = "<span class='badge badge-primary' style='margin-right: 10px; padding: 8px 12px; font-size: 0.9em;'>{$badge}</span>";
  1. ];
  2. // If extension has defined magic bytes, validate them
  3. if (isset($magicBytes[$extension])) {
  4. foreach ($magicBytes[$extension] as $magic) {
  5. if (strpos($bytes, $magic) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Last edited by clicshopping
  6. return true;
  7. }
  8. }
  9. return false;
  10. }
  1. // Simple contradiction check
  2. $s1Lower = strtolower($statement1);
  3. $s2Lower = strtolower($statement2);
  4. // Check for negation patterns
  5. if (strpos($s1Lower, 'not') !== false && strpos($s2Lower, 'not') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return true;
  7. }
  8. return false;
  9. }
  1. * @return string Escaped value
  2. */
  3. private function escapeCsvValue(string $value): string
  4. {
  5. // Escape quotes and wrap in quotes if contains comma, quote, or newline
  6. if (strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return '"' . str_replace('"', '""', $value) . '"';
  8. }
  9. return $value;
  10. }
  1. // Propose permission level always requires approval for write actions
  2. if ($permissionLevel === self::PERMISSION_PROPOSE) {
  3. $writeActions = ['create', 'update', 'delete', 'modify', 'propose'];
  4. foreach ($writeActions as $writeAction) {
  5. if (strpos($action, $writeAction) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return true;
  7. }
  8. }
  9. }
  1. $text = strtolower("$reason $comment");
  2. foreach ($keywords as $type => $words) {
  3. foreach ($words as $word) {
  4. if (strpos($text, $word) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  5. return $type;
  6. }
  7. }
  8. }
  1. // 🔍 DEBUG: Log prompt loading verification
  2. if ($this->debug) {
  3. error_log("[INFO : ANALYSE] [UnifiedQueryAnalyzer] Prompt Loading Verification:");
  4. error_log(" Prompt length: " . strlen($prompt) . " characters");
  5. error_log(" Prompt preview (first 200 chars): " . substr($prompt, 0, 200) . "...");
  6. error_log(" Query in prompt: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. }
  8. // Single GPT call for everything
  9. // Use Gpt::getGptResponse() instead of non-existent complete() method
  1. if ($this->debug) {
  2. error_log("UnifiedQueryAnalyzer: Built prompt from language file sections");
  3. error_log("UnifiedQueryAnalyzer: Query to analyze: {$query}");
  4. error_log("UnifiedQueryAnalyzer: Total prompt length: " . strlen($prompt) . " characters");
  5. error_log("UnifiedQueryAnalyzer: Prompt contains query: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. }
  7. return $prompt;
  8. }
  1. */
  2. private function categorizeError(string $errorMessage): string
  3. {
  4. $message = strtolower($errorMessage);
  5. if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return 'database';
  7. }
  8. if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
  9. return 'timeout';
  10. }
  1. $message = strtolower($errorMessage);
  2. if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
  3. return 'database';
  4. }
  5. if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return 'timeout';
  7. }
  8. if (strpos($message, 'memory') !== false) {
  9. return 'memory';
  10. }
  1. return 'database';
  2. }
  3. if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
  4. return 'timeout';
  5. }
  6. if (strpos($message, 'memory') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return 'memory';
  8. }
  9. if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
  10. return 'validation';
  11. }
  1. return 'timeout';
  2. }
  3. if (strpos($message, 'memory') !== false) {
  4. return 'memory';
  5. }
  6. if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return 'validation';
  8. }
  9. if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
  10. return 'classification';
  11. }
  1. return 'memory';
  2. }
  3. if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
  4. return 'validation';
  5. }
  6. if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return 'classification';
  8. }
  9. if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
  10. return 'api';
  11. }
  1. return 'validation';
  2. }
  3. if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
  4. return 'classification';
  5. }
  6. if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return 'api';
  8. }
  9. return 'unknown';
  10. }
  1. // If it's an array, search for the response
  2. if (is_array($executionResult)) {
  3. if (isset($executionResult['text_response']) && !empty($executionResult['text_response'])) {
  4. // Check if text_response is NOT the JSON fallback
  5. if (strpos($executionResult['text_response'], 'Résultat:') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return $executionResult['text_response'];
  7. }
  8. }
  9. if (isset($executionResult['response']) && !empty($executionResult['response'])) {
  1. }
  2. }
  3. // Priority 4: Check if rawResult has 'text_response' field (but not if it's the JSON fallback)
  4. if (isset($rawResult['text_response']) && !empty($rawResult['text_response'])) {
  5. if (strpos($rawResult['text_response'], 'Résultat:') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return $rawResult['text_response'];
  7. }
  8. }
  9. // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
  1. return $rawResult['text_response'];
  2. }
  3. }
  4. // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
  5. if (!empty($finalResponse) && strpos($finalResponse, 'Résultat:') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return $finalResponse;
  7. }
  8. return '';
  9. }
  1. // Check if source type is valid (case-insensitive, partial match)
  2. $sourceType = strtolower($sourceAttr['source_type']);
  3. $isValidSource = false;
  4. foreach ($validSourceTypes as $validType) {
  5. if (strpos($sourceType, strtolower($validType)) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $isValidSource = true;
  7. break;
  8. }
  9. }
  1. 'as an ai',
  2. 'i\'m an ai'
  3. ];
  4. foreach ($genericPhrases as $phrase) {
  5. if (strpos($response, $phrase) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. $validationErrors[] = "Response contains generic LLM phrase indicating lack of knowledge";
  7. return false;
  8. }
  9. }
  1. $table = $matches[1];
  2. }
  3. // Ajouter le préfixe si nécessaire
  4. $prefix = CLICSHOPPING::getConfig('db_prefix');
  5. if (!empty($prefix) && strpos($table, $prefix) !== 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Last edited by clicshopping
  6. $table = $prefix . $table;
  7. }
  8. return trim($table, '`"\'');
  9. }
  1. private function determineSuggestedActionForSqlError(string $errorMessage, string $temporalPeriod): string
  2. {
  3. $errorLower = strtolower($errorMessage);
  4. // Check for common error patterns
  5. if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
  7. }
  8. if (strpos($errorLower, 'table') !== false) {
  9. return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
  1. // Check for common error patterns
  2. if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
  3. return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
  4. }
  5. if (strpos($errorLower, 'table') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
  7. }
  8. if (strpos($errorLower, 'syntax') !== false) {
  9. return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
  1. if (strpos($errorLower, 'table') !== false) {
  2. return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
  3. }
  4. if (strpos($errorLower, 'syntax') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  5. return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
  6. }
  7. if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
  8. return "You may not have permission to access the required data. Contact your administrator.";
  1. if (strpos($errorLower, 'syntax') !== false) {
  2. return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
  3. }
  4. if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  5. return "You may not have permission to access the required data. Contact your administrator.";
  6. }
  7. if (strpos($errorLower, 'timeout') !== false) {
  8. return "The query took too long. Try a shorter time range or simpler aggregation.";
  1. if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
  2. return "You may not have permission to access the required data. Contact your administrator.";
  3. }
  4. if (strpos($errorLower, 'timeout') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  5. return "The query took too long. Try a shorter time range or simpler aggregation.";
  6. }
  7. // Default suggestion
  8. return "Try rephrasing your query or using a different temporal period. If the problem persists, contact support.";
  1. // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
  2. if (!$hasSources) {
  3. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  4. $isLLMFallback = $hasTextResponse && (
  5. strpos($sourceType, 'llm') !== false ||
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. strpos($sourceType, 'general knowledge') !== false ||
  7. strpos($sourceType, 'conversation') !== false ||
  8. strpos($sourceType, 'memory') !== false
  9. );
  1. // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
  2. if (!$hasSources) {
  3. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  4. $isLLMFallback = $hasTextResponse && (
  5. strpos($sourceType, 'llm') !== false ||
  6. strpos($sourceType, 'general knowledge') !== false ||
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. strpos($sourceType, 'conversation') !== false ||
  8. strpos($sourceType, 'memory') !== false
  9. );
  10. if (!$isLLMFallback) {
  1. if (!$hasSources) {
  2. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  3. $isLLMFallback = $hasTextResponse && (
  4. strpos($sourceType, 'llm') !== false ||
  5. strpos($sourceType, 'general knowledge') !== false ||
  6. strpos($sourceType, 'conversation') !== false ||
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. strpos($sourceType, 'memory') !== false
  8. );
  9. if (!$isLLMFallback) {
  10. $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
  1. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  2. $isLLMFallback = $hasTextResponse && (
  3. strpos($sourceType, 'llm') !== false ||
  4. strpos($sourceType, 'general knowledge') !== false ||
  5. strpos($sourceType, 'conversation') !== false ||
  6. strpos($sourceType, 'memory') !== false
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. );
  8. if (!$isLLMFallback) {
  9. $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
  10. $dataStatus = isset($finalResult['data']) ? 'empty' : 'not set';
  1. private function generateUserFriendlyErrorMessage(array $errors): string
  2. {
  3. // Check for common error patterns and generate appropriate messages
  4. foreach ($errors as $error) {
  5. // Pattern: "Semantic result missing sources and data"
  6. if (strpos($error, 'Semantic result missing sources and data') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return "I couldn't find any information about that in the database. The requested content (like terms and conditions) may not be available yet. Please try asking about something else or contact support to add this content.";
  8. }
  9. // Pattern: "Analytics result missing data"
  10. if (strpos($error, 'Analytics result missing data') !== false) {
  1. if (strpos($error, 'Semantic result missing sources and data') !== false) {
  2. return "I couldn't find any information about that in the database. The requested content (like terms and conditions) may not be available yet. Please try asking about something else or contact support to add this content.";
  3. }
  4. // Pattern: "Analytics result missing data"
  5. if (strpos($error, 'Analytics result missing data') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return "I couldn't retrieve the requested data. This might be because there are no records matching your query, or the data hasn't been entered yet. Please try a different query or check if the data exists.";
  7. }
  8. // Pattern: "Hybrid result missing"
  9. if (strpos($error, 'Hybrid result missing') !== false) {
  1. if (strpos($error, 'Analytics result missing data') !== false) {
  2. return "I couldn't retrieve the requested data. This might be because there are no records matching your query, or the data hasn't been entered yet. Please try a different query or check if the data exists.";
  3. }
  4. // Pattern: "Hybrid result missing"
  5. if (strpos($error, 'Hybrid result missing') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return "I couldn't complete your request because some of the required information is missing. Please try breaking your question into smaller parts or asking about something else.";
  7. }
  8. // Pattern: "Empty response"
  9. if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
  1. if (strpos($error, 'Hybrid result missing') !== false) {
  2. return "I couldn't complete your request because some of the required information is missing. Please try breaking your question into smaller parts or asking about something else.";
  3. }
  4. // Pattern: "Empty response"
  5. if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return "I couldn't find any results for your query. The information you're looking for might not be available in the system yet. Please try rephrasing your question or asking about something else.";
  7. }
  8. }
  9. // Default fallback message
  1. // Fallback to source_table if no name found
  2. if ($docName === null && isset($metadata['source_table'])) {
  3. $tableName = $metadata['source_table'];
  4. // Remove prefix and _embedding suffix
  5. $prefix = defined('CLICSHOPPING_DB_TABLE_PREFIX') ? CLICSHOPPING_DB_TABLE_PREFIX : 'clic_';
  6. if (strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Last edited by clicshopping
  7. $tableName = substr($tableName, strlen($prefix));
  8. }
  9. $tableName = str_replace('_embedding', '', $tableName);
  10. $tableName = str_replace('_', ' ', $tableName);
  11. $docName = ucwords($tableName);
  1. return $entityType;
  2. }
  3. // Remove table prefix if present
  4. $prefix = CLICSHOPPING::getConfig('db_table_prefix');
  5. if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Last edited by clicshopping
  6. $tableName = substr($tableName, strlen($prefix));
  7. }
  8. // Remove '_embedding' suffix if present
  9. $tableName = str_replace('_embedding', '', $tableName);
  1. }
  2. $keywords[] = $entityType;
  3. $keywords[] = str_replace('_', ' ', $entityType);
  4. if (substr($entityType, -3) === 'ies') {
    Consider replacing substr() with str_ends_with() for improved readability.
    Last edited by clicshopping
  5. $keywords[] = substr($entityType, 0, -3) . 'y';
  6. } elseif (substr($entityType, -1) === 's') {
  7. $keywords[] = substr($entityType, 0, -1);
  8. } else {
  9. $keywords[] = $entityType . 's';
  1. $keywords[] = $entityType;
  2. $keywords[] = str_replace('_', ' ', $entityType);
  3. if (substr($entityType, -3) === 'ies') {
  4. $keywords[] = substr($entityType, 0, -3) . 'y';
  5. } elseif (substr($entityType, -1) === 's') {
    Consider replacing substr() with str_ends_with() for improved readability.
    Last edited by clicshopping
  6. $keywords[] = substr($entityType, 0, -1);
  7. } else {
  8. $keywords[] = $entityType . 's';
  9. }
  10. }
  1. * @return bool
  2. */
  3. private function hasKeyword(string $text, array $keywords): bool
  4. {
  5. foreach ($keywords as $keyword) {
  6. if (strpos($text, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. return true;
  8. }
  9. }
  10. return false;
  11. }
  1. // Simple keyword matching (replaces deleted PatternAnalysisPattern)
  2. $patternKeywords = ['pattern', 'trend', 'style', 'dominant', 'recurring', 'common'];
  3. $queryLower = strtolower($queryToAnalyze);
  4. foreach ($patternKeywords as $keyword) {
  5. if (strpos($queryLower, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. if ($this->debug) {
  7. $this->logDebug("Pattern analysis keyword detected: $keyword");
  8. }
  9. return true;
  10. }
  1. // Format: ['table' => 'column']
  2. $table = $key;
  3. $column = $value;
  4. } else {
  5. // Format: ['table.column']
  6. if (strpos($value, '.') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  7. list($table, $column) = explode('.', $value, 2);
  8. } else {
  9. // Cannot validate without table context
  10. if ($this->debug) {
  11. error_log("SchemaValidator: Column '{$value}' has no table context");
  1. * @param string $sql The SQL query
  2. * @return bool True if comments found
  3. */
  4. private function hasComments(string $sql): bool
  5. {
  6. return preg_match('/--/', $sql) || preg_match('/\/\*/', $sql);
    Consider replacing preg_match() with str_contains() for improved readability.
    Last edited by clicshopping
  7. }
  8. /**
  9. * Check if query contains UNION statement.
  10. *
  1. public static function extractBaseMetric(string $query): ?string
  2. {
  3. $query = strtolower($query);
  4. foreach (self::FINANCIAL_METRICS as $pattern => $metric) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return $metric;
  7. }
  8. }
  9. return null;
  1. return "year {$matches[2]}";
  2. }
  3. // Check for relative time patterns
  4. foreach (self::RELATIVE_TIME_PATTERNS as $pattern => $range) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  6. return $range;
  7. }
  8. }
  9. return null;
  1. $lowerQuery = strtolower($query);
  2. $needsContext = false;
  3. foreach ($contextualKeywords as $keyword) {
  4. if (strpos($lowerQuery, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by clicshopping
  5. $needsContext = true;
  6. break;
  7. }
  8. }

Your project uses legacy callable syntax instead of first-class callable syntax 3

More information: https://insight.symfony.com/what-we-analyse/php.use_first_class_callable_syntax

  1. foreach ($schema['foreign'] as $name => $fields) {
  2. // Escape foreign key name for SQL injection protection
  3. $escaped_fk_name = self::prepareIdentifier($name);
  4. // Escape column names in foreign key definition
  5. $escaped_cols = array_map([self::class, 'prepareIdentifier'], $fields['col']);
    Use the first-class callable syntax ($this->method(...))
    Time to fix: about 15 minutes
    Read doc Open Issue Permalink Copy Prompt
    Last edited by clicshopping
  6. $escaped_ref_cols = array_map([self::class, 'prepareIdentifier'], $fields['ref_col']);
  7. // Escape reference table name
  8. $escaped_ref_table = self::prepareIdentifier($fields['ref_table']);
  1. // Escape foreign key name for SQL injection protection
  2. $escaped_fk_name = self::prepareIdentifier($name);
  3. // Escape column names in foreign key definition
  4. $escaped_cols = array_map([self::class, 'prepareIdentifier'], $fields['col']);
  5. $escaped_ref_cols = array_map([self::class, 'prepareIdentifier'], $fields['ref_col']);
    Use the first-class callable syntax ($this->method(...))
    Time to fix: about 15 minutes
    Read doc Open Issue Permalink Copy Prompt
    Last edited by clicshopping
  6. // Escape reference table name
  7. $escaped_ref_table = self::prepareIdentifier($fields['ref_table']);
  8. $row = ' FOREIGN KEY ' . $escaped_fk_name . ' (' . implode(', ', $escaped_cols) . ') REFERENCES ' . (isset($prefix) && (!isset($fields['prefix']) || ($fields['prefix'] != 'false')) ? $prefix : '') . $escaped_ref_table . '(' . implode(', ', $escaped_ref_cols) . ')';
  1. // Build a mapping of table names (without prefix) to entity types
  2. $tableToEntityType = [];
  3. foreach ($allTables as $fullTableName) {
  4. $entityType = $registry->getEntityTypeForTable($fullTableName);
  5. // Remove prefix and _embedding suffix to get base table name
  6. $tableName = str_replace([$prefix, '_embedding'], '', $fullTableName);
    Use the first-class callable syntax ($this->method(...))
    Time to fix: about 15 minutes
    Read doc Open Issue Permalink Copy Prompt
    Last edited by clicshopping
  7. $tableToEntityType[$tableName] = $entityType;
  8. }
  9. // Pattern 1: FROM {table_name}
  10. if (preg_match('/FROM\s+(?:\w+\.)?(\w+)/i', $query, $matches)) {