Your project should not use deprecated PHP features 2
- Read doc
- Productivity
- Major
More information: https://insight.symfony.com/what-we-analyse/php.use_deprecated_function
- return true;
- }
- $finfo = finfo_open(FILEINFO_MIME_TYPE);
- $mimeType = finfo_file($finfo, $filePath);
- finfo_close($finfo);
- // Define allowed MIME types based on configured extensions
- $allowedMimeTypes = [
- // Images
- 'image/jpeg' => ['jpg', 'jpeg'],
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
- }
- $response = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
- if ($response === false) {
- return ['error' => ['message' => 'Stripe API request failed (curl).']];
- }
Your project uses non-strict array lookups
- Read doc
- Reliability
- Major
More information: https://insight.symfony.com/what-we-analyse/php.strict_array_lookup
- // Check if detected MIME type matches expected extension
- foreach ($allowedMimeTypes as $mime => $extensions) {
- if ($mimeType === $mime) {
- $fileExtension = $this->getExtension();
- return in_array($fileExtension, $extensions);
- }
- }
- // If MIME type not in whitelist, reject
- return false;
Your project should not use insecure random number functions
- Read doc
- Security
- Major
More information: https://insight.symfony.com/what-we-analyse/php.use_insecure_random_function
- // Fallback: use multiple sources of entropy
- // This should never happen on PHP 7.0+ but provides safety
- $fallback = hash('sha256',
- uniqid('antispam_', true) .
- microtime(true) .
- mt_rand() .
- (function_exists('random_bytes') ? bin2hex(random_bytes(16)) : '')
- );
- trigger_error(
- 'Failed to generate cryptographically secure secret, using fallback. Error: ' . $e->getMessage(),
Your project should use dedicated PHP string functions 63
- Read doc
- Productivity
- Info
More information: https://insight.symfony.com/what-we-analyse/php.use_string_function
- if (strpos($error, 'Hybrid result missing') !== false) {
- 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.";
- }
- // Pattern: "Empty response"
- if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
- 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.";
- }
- }
- // Default fallback message
- // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
- if (!$hasSources) {
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- if (!$isLLMFallback) {
- private function generateUserFriendlyErrorMessage(array $errors): string
- {
- // Check for common error patterns and generate appropriate messages
- foreach ($errors as $error) {
- // Pattern: "Semantic result missing sources and data"
- if (strpos($error, 'Semantic result missing sources and data') !== false) {
- 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.";
- }
- // Pattern: "Analytics result missing data"
- if (strpos($error, 'Analytics result missing data') !== false) {
- if (!$hasSources) {
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- if (!$isLLMFallback) {
- $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
- if (strpos($error, 'Analytics result missing data') !== false) {
- 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.";
- }
- // Pattern: "Hybrid result missing"
- if (strpos($error, 'Hybrid result missing') !== false) {
- 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.";
- }
- // Pattern: "Empty response"
- if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
- // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
- if (!$hasSources) {
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- if (!$isLLMFallback) {
- $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
- $dataStatus = isset($finalResult['data']) ? 'empty' : 'not set';
- if (strpos($error, 'Semantic result missing sources and data') !== false) {
- 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.";
- }
- // Pattern: "Analytics result missing data"
- if (strpos($error, 'Analytics result missing data') !== false) {
- 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.";
- }
- // Pattern: "Hybrid result missing"
- if (strpos($error, 'Hybrid result missing') !== false) {
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
- // Check if they're operating on similar subjects
- $similarity = $this->calculateSimilarity($obj1, $obj2);
- 'optimize' => ['optimize', 'improve', 'enhance', 'tune']
- ];
- foreach ($operationPatterns as $operation => $keywords) {
- foreach ($keywords as $keyword) {
- if (strpos($text, $keyword) !== false) {
- $operations[] = $operation;
- break;
- }
- }
- }
- ['grow', 'shrink']
- ];
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- 'database', 'table', 'index', 'query', 'cache', 'memory',
- 'file', 'log', 'configuration', 'setting', 'registry'
- ];
- foreach ($resourceKeywords as $keyword) {
- if (strpos($text, $keyword) !== false) {
- $resources[] = $keyword;
- }
- }
- return array_unique($resources);
- ];
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
- // Check if they're operating on similar subjects
- if (strpos($errorLower, 'syntax') !== false) {
- return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
- }
- if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
- return "You may not have permission to access the required data. Contact your administrator.";
- }
- if (strpos($errorLower, 'timeout') !== false) {
- return "The query took too long. Try a shorter time range or simpler aggregation.";
- if (strpos($errorLower, 'table') !== false) {
- return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
- }
- if (strpos($errorLower, 'syntax') !== false) {
- return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
- }
- if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
- return "You may not have permission to access the required data. Contact your administrator.";
- private function determineSuggestedActionForSqlError(string $errorMessage, string $temporalPeriod): string
- {
- $errorLower = strtolower($errorMessage);
- // Check for common error patterns
- if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
- return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
- }
- if (strpos($errorLower, 'table') !== false) {
- return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
- // Check for common error patterns
- if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
- return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
- }
- if (strpos($errorLower, 'table') !== false) {
- return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
- }
- if (strpos($errorLower, 'syntax') !== false) {
- return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
- if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
- return "You may not have permission to access the required data. Contact your administrator.";
- }
- if (strpos($errorLower, 'timeout') !== false) {
- return "The query took too long. Try a shorter time range or simpler aggregation.";
- }
- // Default suggestion
- return "Try rephrasing your query or using a different temporal period. If the problem persists, contact support.";
- // Format: ['table' => 'column']
- $table = $key;
- $column = $value;
- } else {
- // Format: ['table.column']
- if (strpos($value, '.') !== false) {
- list($table, $column) = explode('.', $value, 2);
- } else {
- // Cannot validate without table context
- if ($this->debug) {
- error_log("SchemaValidator: Column '{$value}' has no table context");
- // Display mode badges
- $badges = [];
- foreach ($modesUsed as $mode) {
- $badge = '';
- if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
- $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
- } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
- } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
- } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
- } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
- $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
- } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
- $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
- }
- if (!empty($badge)) {
- $badges[] = "<span class='badge badge-primary' style='margin-right: 10px; padding: 8px 12px; font-size: 0.9em;'>{$badge}</span>";
- if (isset($metadata['engines_used']) && is_array($metadata['engines_used'])) {
- $modesUsed = $metadata['engines_used'];
- $isHybrid = count($modesUsed) > 1;
- } elseif (isset($metadata['mode_type'])) {
- $modesUsed = [$metadata['mode_type']];
- $isHybrid = (strpos($metadata['mode_type'], 'hybrid') !== false);
- }
- // Display hybrid label if applicable
- if ($isHybrid) {
- $output .= "<strong>" . $this->language->getDef('text_rag_hybrid_search') . "</strong><br>";
- foreach ($modesUsed as $mode) {
- $badge = '';
- if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
- $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
- } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
- } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
- } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
- $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
- $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
- } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
- } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
- } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
- $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
- } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
- $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
- }
- if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
- $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
- } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
- } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
- $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
- } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
- $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
- } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
- $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
- return "year {$matches[2]}";
- }
- // Check for relative time patterns
- foreach (self::RELATIVE_TIME_PATTERNS as $pattern => $range) {
- if (strpos($query, $pattern) !== false) {
- return $range;
- }
- }
- return null;
- public static function extractBaseMetric(string $query): ?string
- {
- $query = strtolower($query);
- foreach (self::FINANCIAL_METRICS as $pattern => $metric) {
- if (strpos($query, $pattern) !== false) {
- return $metric;
- }
- }
- return null;
- $lowerQuery = strtolower($query);
- $needsContext = false;
- foreach ($contextualKeywords as $keyword) {
- if (strpos($lowerQuery, $keyword) !== false) {
- $needsContext = true;
- break;
- }
- }
- 'as an ai',
- 'i\'m an ai'
- ];
- foreach ($genericPhrases as $phrase) {
- if (strpos($response, $phrase) !== false) {
- $validationErrors[] = "Response contains generic LLM phrase indicating lack of knowledge";
- return false;
- }
- }
- // Check if source type is valid (case-insensitive, partial match)
- $sourceType = strtolower($sourceAttr['source_type']);
- $isValidSource = false;
- foreach ($validSourceTypes as $validType) {
- if (strpos($sourceType, strtolower($validType)) !== false) {
- $isValidSource = true;
- break;
- }
- }
- ];
- // If extension has defined magic bytes, validate them
- if (isset($magicBytes[$extension])) {
- foreach ($magicBytes[$extension] as $magic) {
- if (strpos($bytes, $magic) === 0) {
- return true;
- }
- }
- return false;
- }
- // Simple contradiction check
- $s1Lower = strtolower($statement1);
- $s2Lower = strtolower($statement2);
- // Check for negation patterns
- if (strpos($s1Lower, 'not') !== false && strpos($s2Lower, 'not') === false) {
- return true;
- }
- return false;
- }
- }
- // Check for relative time patterns
- $relativePatterns = self::getRelativeTimePatterns();
- foreach ($relativePatterns as $pattern => $range) {
- if (strpos($query, $pattern) !== false) {
- return $range;
- }
- }
- // Check for date range patterns (e.g., "from January to March")
- $tableName = $metadata['source_table'];
- // Remove prefix and _embedding suffix
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- $tableName = str_replace('_embedding', '', $tableName);
- $tableName = str_replace('_', ' ', $tableName);
- $docName = ucwords($tableName);
- */
- private function categorizeError(string $errorMessage): string
- {
- $message = strtolower($errorMessage);
- if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
- return 'database';
- }
- if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
- return 'timeout';
- }
- return 'timeout';
- }
- if (strpos($message, 'memory') !== false) {
- return 'memory';
- }
- if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
- return 'validation';
- }
- if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
- return 'classification';
- }
- return 'memory';
- }
- if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
- return 'validation';
- }
- if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
- return 'classification';
- }
- if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
- return 'api';
- }
- return 'database';
- }
- if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
- return 'timeout';
- }
- if (strpos($message, 'memory') !== false) {
- return 'memory';
- }
- if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
- return 'validation';
- }
- return 'validation';
- }
- if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
- return 'classification';
- }
- if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
- return 'api';
- }
- return 'unknown';
- }
- $message = strtolower($errorMessage);
- if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
- return 'database';
- }
- if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
- return 'timeout';
- }
- if (strpos($message, 'memory') !== false) {
- return 'memory';
- }
- $text = strtolower("$reason $comment");
- foreach ($keywords as $type => $words) {
- foreach ($words as $word) {
- if (strpos($text, $word) !== false) {
- return $type;
- }
- }
- }
- return $rawResult['text_response'];
- }
- }
- // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
- if (!empty($finalResponse) && strpos($finalResponse, 'Résultat:') === false) {
- return $finalResponse;
- }
- return '';
- }
- }
- }
- // Priority 4: Check if rawResult has 'text_response' field (but not if it's the JSON fallback)
- if (isset($rawResult['text_response']) && !empty($rawResult['text_response'])) {
- if (strpos($rawResult['text_response'], 'Résultat:') === false) {
- return $rawResult['text_response'];
- }
- }
- // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
- // If it's an array, search for the response
- if (is_array($executionResult)) {
- if (isset($executionResult['text_response']) && !empty($executionResult['text_response'])) {
- // Check if text_response is NOT the JSON fallback
- if (strpos($executionResult['text_response'], 'Résultat:') === false) {
- return $executionResult['text_response'];
- }
- }
- if (isset($executionResult['response']) && !empty($executionResult['response'])) {
- // 🔍 DEBUG: Log prompt loading verification
- if ($this->debug) {
- error_log("[INFO : ANALYSE] [UnifiedQueryAnalyzer] Prompt Loading Verification:");
- error_log(" Prompt length: " . strlen($prompt) . " characters");
- error_log(" Prompt preview (first 200 chars): " . substr($prompt, 0, 200) . "...");
- error_log(" Query in prompt: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
- }
- // Single GPT call for everything
- // Use Gpt::getGptResponse() instead of non-existent complete() method
- if ($this->debug) {
- error_log("UnifiedQueryAnalyzer: Built prompt from language file sections");
- error_log("UnifiedQueryAnalyzer: Query to analyze: {$query}");
- error_log("UnifiedQueryAnalyzer: Total prompt length: " . strlen($prompt) . " characters");
- error_log("UnifiedQueryAnalyzer: Prompt contains query: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
- }
- return $prompt;
- }
- return "year {$matches[2]}";
- }
- // Check for relative time patterns
- foreach (self::RELATIVE_TIME_PATTERNS as $pattern => $range) {
- if (strpos($query, $pattern) !== false) {
- return $range;
- }
- }
- return null;
- public static function extractBaseMetric(string $query): ?string
- {
- $query = strtolower($query);
- foreach (self::FINANCIAL_METRICS as $pattern => $metric) {
- if (strpos($query, $pattern) !== false) {
- return $metric;
- }
- }
- return null;
- * @return string Escaped value
- */
- private function escapeCsvValue(string $value): string
- {
- // Escape quotes and wrap in quotes if contains comma, quote, or newline
- if (strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
- return '"' . str_replace('"', '""', $value) . '"';
- }
- return $value;
- }
- {
- $query = strtolower($query);
- $detected = [];
- foreach (SuperlativePatterns::$superlativeKeywords as $pattern) {
- if (strpos($query, $pattern) !== false) {
- $detected[] = $pattern;
- }
- }
- return $detected;
- public static function hasSuperlativePattern(string $query): bool
- {
- $query = strtolower($query);
- foreach (SuperlativePatterns::$superlativeKeywords as $pattern) {
- if (strpos($query, $pattern) !== false) {
- return true;
- }
- }
- return false;
- // Fallback to source_table if no name found
- if ($docName === null && isset($metadata['source_table'])) {
- $tableName = $metadata['source_table'];
- // Remove prefix and _embedding suffix
- $prefix = defined('CLICSHOPPING_DB_TABLE_PREFIX') ? CLICSHOPPING_DB_TABLE_PREFIX : 'clic_';
- if (strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- $tableName = str_replace('_embedding', '', $tableName);
- $tableName = str_replace('_', ' ', $tableName);
- $docName = ucwords($tableName);
- return $entityType;
- }
- // Remove table prefix if present
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- // Remove '_embedding' suffix if present
- $tableName = str_replace('_embedding', '', $tableName);
- }
- $keywords[] = $entityType;
- $keywords[] = str_replace('_', ' ', $entityType);
- if (substr($entityType, -3) === 'ies') {
- $keywords[] = substr($entityType, 0, -3) . 'y';
- } elseif (substr($entityType, -1) === 's') {
- $keywords[] = substr($entityType, 0, -1);
- } else {
- $keywords[] = $entityType . 's';
- * @return bool
- */
- private function hasKeyword(string $text, array $keywords): bool
- {
- foreach ($keywords as $keyword) {
- if (strpos($text, $keyword) !== false) {
- return true;
- }
- }
- return false;
- }
- $keywords[] = $entityType;
- $keywords[] = str_replace('_', ' ', $entityType);
- if (substr($entityType, -3) === 'ies') {
- $keywords[] = substr($entityType, 0, -3) . 'y';
- } elseif (substr($entityType, -1) === 's') {
- $keywords[] = substr($entityType, 0, -1);
- } else {
- $keywords[] = $entityType . 's';
- }
- }
- // Propose permission level always requires approval for write actions
- if ($permissionLevel === self::PERMISSION_PROPOSE) {
- $writeActions = ['create', 'update', 'delete', 'modify', 'propose'];
- foreach ($writeActions as $writeAction) {
- if (strpos($action, $writeAction) !== false) {
- return true;
- }
- }
- }
- $table = $matches[1];
- }
- // Ajouter le préfixe si nécessaire
- $prefix = CLICSHOPPING::getConfig('db_prefix');
- if (!empty($prefix) && strpos($table, $prefix) !== 0) {
- $table = $prefix . $table;
- }
- return trim($table, '`"\'');
- }
- {
- $query = strtolower($query);
- $metrics = self::getMetricsPatterns();
- foreach ($metrics as $pattern => $metric) {
- if (strpos($query, $pattern) !== false) {
- return $metric;
- }
- }
- return null;
- * @param string $sql The SQL query
- * @return bool True if comments found
- */
- private function hasComments(string $sql): bool
- {
- return preg_match('/--/', $sql) || preg_match('/\/\*/', $sql);
- }
- /**
- * Check if query contains UNION statement.
- *
- if (isset($metadata['source_table']) && !empty($metadata['source_table'])) {
- $tableName = $metadata['source_table'];
- // Remove prefix and _embedding suffix
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- $tableName = str_replace('_embedding', '', $tableName);
- // Convert to readable format (e.g., "pages_manager_description" -> "Pages Manager Description")
- public function __construct(EmbeddingGeneratorInterface $embeddingGenerator, string $tableName = 'rag_embeddings')
- {
- $this->embeddingGenerator = $embeddingGenerator;
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
- $this->tableName = $tableName;
- } else {
- $this->tableName = $prefix . $tableName;
- }
Your project uses legacy callable syntax instead of first-class callable syntax 3
- Read doc
- Productivity
- Info
More information: https://insight.symfony.com/what-we-analyse/php.use_first_class_callable_syntax
- // Escape foreign key name for SQL injection protection
- $escaped_fk_name = self::prepareIdentifier($name);
- // Escape column names in foreign key definition
- $escaped_cols = array_map([self::class, 'prepareIdentifier'], $fields['col']);
- $escaped_ref_cols = array_map([self::class, 'prepareIdentifier'], $fields['ref_col']);
- // Escape reference table name
- $escaped_ref_table = self::prepareIdentifier($fields['ref_table']);
- $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) . ')';
- foreach ($schema['foreign'] as $name => $fields) {
- // Escape foreign key name for SQL injection protection
- $escaped_fk_name = self::prepareIdentifier($name);
- // Escape column names in foreign key definition
- $escaped_cols = array_map([self::class, 'prepareIdentifier'], $fields['col']);
- $escaped_ref_cols = array_map([self::class, 'prepareIdentifier'], $fields['ref_col']);
- // Escape reference table name
- $escaped_ref_table = self::prepareIdentifier($fields['ref_table']);
- // Build a mapping of table names (without prefix) to entity types
- $tableToEntityType = [];
- foreach ($allTables as $fullTableName) {
- $entityType = $registry->getEntityTypeForTable($fullTableName);
- // Remove prefix and _embedding suffix to get base table name
- $tableName = str_replace([$prefix, '_embedding'], '', $fullTableName);
- $tableToEntityType[$tableName] = $entityType;
- }
- // Pattern 1: FROM {table_name}
- if (preg_match('/FROM\s+(?:\w+\.)?(\w+)/i', $query, $matches)) {