= " . $filterValue['from'] . " AND $quotedColumn <= " . $filterValue['to']; } elseif (isset($filterValue['from'])) { $sql = " AND $quotedColumn >= " . $filterValue['from']; } elseif (isset($filterValue['to'])) { $sql = " AND $quotedColumn <= " . $filterValue['to']; } else if (isset($filterValue['exact'])) { $sql = " AND $quotedColumn = " . "'{$filterValue['exact']}'"; } else if (!empty($filterValue)) { $sql = " AND $quotedColumn IN ('" . implode("','", $filterValue) . "')"; } } else if ($filterValue === "0" || $filterValue === "1") { $sql .= " AND $quotedColumn = " . $filterValue; } else if ($filterValue === null) { $sql .= " AND $quotedColumn IS NULL"; } else if ($filterValue === '!NULL') { $sql .= " AND $quotedColumn IS NOT NULL"; } else if (!empty($filterValue)) { if ($exactMatch) { $sql .= " AND $quotedColumn = '" . $filterValue . "'"; } else if (strpos($columnName, "|") !== false) { $columns = explode("|", $columnName); // Loop through each search term (e.g., "john", "doe") foreach (explode(" ", $filterValue) as $item) { // Skip if the item is empty if (empty(trim($item))) { continue; } $escapedItem = addslashes($item); // Basic escaping // Build the list of OR conditions for the current item $orConditions = []; foreach ($columns as $column) { // e.g., "first_name LIKE '%john%'" $orConditions[] = "$column LIKE '%" . $escapedItem . "%'"; } // Combine the OR conditions into a single block and add to the query // e.g., "AND (first_name LIKE '%john%' OR last_name LIKE '%john%')" if (!empty($orConditions)) { $sql .= " AND (" . implode(" OR ", $orConditions) . ")"; } } } else if ($filterValue[0] === "%") { $sql .= " AND $quotedColumn LIKE '" . addslashes($filterValue) . "'"; } else if ($filterValue[strlen($filterValue) - 1] === "%") { $sql .= " AND $quotedColumn LIKE '" . addslashes($filterValue) . "'"; } else if ($filterValue[0] === "!") { $sql .= " AND $quotedColumn NOT LIKE '%" . addslashes(substr($filterValue, 1)) . "%'"; } else { $filterItems = explode(" ", $filterValue); foreach ($filterItems as $item) { $escapedItem = addslashes($item); // Basic escaping $sql .= " AND $quotedColumn LIKE '%" . $escapedItem . "%'"; } } } else if ($filterValue === 0) { $sql .= " AND $quotedColumn = 0"; } return $sql; } /** * Validates an array of data based on a set of predefined rules. * * @param array $data The data to validate. Keys represent field names, and values are the corresponding data. * @param array $checkArray An associative array defining validation rules for each field: * - key: The field name to validate. * - value: An associative array of validation rules for that field: * - required (bool, optional): Whether the field is required. Default: false. * - title (string, optional): The human-readable name of the field to use in error messages. * - required_length (int, optional): The minimum required length of the value. Default: 1. * - regex (string, optional): A regular expression pattern the value must match. * * @return array|true Returns `true` if validation passes for all fields. Otherwise, returns an associative array of errors * where keys are field names, and values are error messages. */ public static function validateArray(array $data, array $checkArray, bool $printErrors = true) { $errors = []; foreach ($checkArray as $key => $rules) { $value = $data[$key] ?? null; $title = $rules['title'] ?? $key; //TODO: fix this, skip arrays for now if (is_array($value)) { continue; } // Apply default values for missing rules $rules = array_merge(['required' => false, 'required_length' => 1, 'regex' => false,], $rules); // Required Check if ($rules['required'] && (is_null($value) || $value === '')) { $errors[$key] = "$title wird benötigt."; } // Length Check (only if value exists) if (!is_null($value) && strlen($value) < $rules['required_length']) { $errors[$key] = "$title muss mindestens $rules[required_length] Zeichen lang sein."; } // Regex Check (only if value exists and regex is provided) if (!is_null($value) && $rules['regex'] && !preg_match($rules['regex'], $value)) { $errors[$key] = "$title hat ein ungültiges Format."; } } if ($printErrors) { if (!empty($errors)) { header('Content-Type: application/json'); die(json_encode(['success' => false, 'errors' => $errors])); } } return empty($errors) ? true : $errors; } /** * Displays Vue component with the given header title. * * @param mfBaseController $controller The controller instance to generate $JSGlobals for. * @param string $pageName The name of the Vue component to render. * @param string $headerTitle The title to display in the header. * @param array $additionalGlobals Additional global variables to pass to the Vue component. */ public static function renderVue(mfBaseController $controller, string $pageName, string $headerTitle, array $additionalGlobals = []) { $JSGlobals = ["BASE_URL" => $controller::getUrl($pageName), "MF_URL" => $controller::getUrl(""), "DASHBOARD_URL" => $controller::getUrl("Dashboard"), "MF_APP_NAME" => MFAPPNAME_SLUG, "BASE_PATH" => $controller::getUrl(""), "PAGE_TITLE" => $headerTitle, "PATH" => [["text" => MFAPPNAME_SLUG, "href" => $controller::getUrl("Dashboard")], ["text" => $headerTitle, "href" => $controller::getUrl($pageName)]],]; $JSGlobals = array_merge($JSGlobals, $additionalGlobals); $controller->layout()->set("vueViewName", $pageName); $controller->layout()->set("JSGlobals", $JSGlobals); $controller->layout()->setTemplate("VueViews/Vue"); } /** * Converts an array of objects to a CSV file. * @param array $rows The array of objects to convert to CSV. * @return string The CSV file content. */ public static function arrayToCsv(array $rows): string { $output = fopen('php://temp', 'w'); // Add headers fputcsv($output, array_keys((array) $rows[0])); // Add rows foreach ($rows as $row) { fputcsv($output, (array) $row); } rewind($output); $csv = stream_get_contents($output); fclose($output); return $csv; } /** * Formats a number with the given number of decimals, decimal point, and thousands separator. * @param $number * @param int $decimals * @param string $decPoint * @param string $thousandsSep * @return float */ public static function formatNumber($number, int $decimals = 2, string $decPoint = ",", string $thousandsSep = "."): string { if(!is_numeric($number)) return ""; return number_format($number, $decimals, $decPoint, $thousandsSep); } public static function getPreorderCampaignFromUser($user, bool $returnObject = false): array { if ($user->isAdmin()) $campaigns = PreordercampaignModel::getAll(); else { $networkIDs = array_unique(array_merge( array_column($user->myNetworks(["netowner"]), 'id'), json_decode($user->getFlag("preorder_networks")->value() ?: '[]') )); $campaigns = PreordercampaignModel::search(['network_id' => $networkIDs]); } return $returnObject ? $campaigns : array_column($campaigns, 'id'); } public static function getPreorderCampaignNetworkOwners() { $sql = "SELECT a.id FROM Preordercampaign pc LEFT JOIN Network n ON pc.network_id = n.id LEFT JOIN Address a ON n.owner_id = a.id GROUP BY a.id ORDER BY a.company, a.lastname, a.firstname"; $results = FronkDB::singleton()->fetch_all_assoc(FronkDB::singleton()->query($sql)) ?? []; return array_map(fn($owner) => new Address($owner['id']), $results); } }