routeName = URL::current() === route('bots.create') ? 'Create Bot' : 'Edit Bot'; if ($this->bot) { $this->name = $this->bot->name; $this->class = $this->bot->class; $this->config = $this->bot->config ?? []; $this->schedule = $this->bot->schedule; $this->enabled = $this->bot->enabled; $this->cron_text = CronTranslator::translate($this->bot->schedule); $this->configSchema = $this->bot->class::configSchema(); } $basePath = $basePath ?? app_path('Bots'); $baseNamespace = $baseNamespace ?? 'App\\Bots'; foreach (File::allFiles($basePath) as $file) { // Convert file path → class name $relativePath = str_replace([$basePath . DIRECTORY_SEPARATOR, '.php'], '', $file->getPathname()); $relativeNamespace = str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath); $class = $baseNamespace . '\\' . $relativeNamespace; // Make sure class exists and implements BotContract if (class_exists($class) && in_array(BotContract::class, class_implements($class))) { $label = method_exists($class, 'label') ? $class::label() : class_basename($class); $this->classList[$class] = $label; } } } public function updatedClass($value) { $this->configSchema = $this->class::configSchema(); } protected function rules(): array { $schemaRules = []; foreach ($this->configSchema as $field => $meta) { $schemaRules["config.$field"] = $meta['rules'] ?? []; } return array_merge([ 'name' => [ 'required', 'string', 'max:255', Rule::unique('bots', 'name')->ignore($this->name, 'name'), ], 'class' => [ 'required', 'string', 'max:255', ], 'schedule' => [ 'required', 'string', 'max:255', function ($attribute, $value, $fail) { if (!CronExpression::isValidExpression($value)) { $fail('The ' . $attribute . ' is not a valid cron expression.'); } }, ], 'enabled' => ['boolean'], ], $schemaRules); } public function save(): void { $this->validate(); if (!class_exists($this->class)) { $this->addError('class', 'The specified class does not exist.'); return; } if (!in_array(\App\Bots\BotContract::class, class_implements($this->class))) { $this->addError('class', 'The specified class does not exist.'); return; } if ($this->routeName !== 'Create Bot') { $this->bot->update([ 'name' => $this->name, 'class' => $this->class, 'enabled' => $this->enabled, 'schedule' => $this->schedule, 'config' => $this->config, ]); flash()->success('Bot updated successfully.'); return; } else { \App\Models\Bot::create([ 'name' => $this->name, 'class' => $this->class, 'enabled' => $this->enabled, 'schedule' => $this->schedule, 'config' => $this->config, ]); } flash()->success('Bot created successfully.'); $this->reset(['name', 'class', 'enabled', 'schedule', 'config', 'configSchema']); } public function updatedSchedule($value) { try { $this->cron_text = CronTranslator::translate($value); $this->resetErrorBag('schedule'); } catch (CronParsingException $e) { $this->cron_text = ''; } } protected function validationAttributes(): array { $attributes = []; foreach ($this->configSchema as $field => $meta) { $attributes["config.$field"] = $meta['label']; } $attributes['name'] = 'Bot Name'; $attributes['schedule'] = 'Schedule'; $attributes['class'] = 'Bot Schema'; return $attributes; } public function prettify(string $field): void { if (isset($this->config[$field])) { if (json_validate($this->config[$field])) { $decoded = json_decode($this->config[$field], true); $this->config[$field] = json_encode($decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); $this->resetErrorBag("config.$field"); } else { $this->addError("config.$field", 'Invalid JSON format.'); } } } public function render() { return view('livewire.create-edit-bot'); } }