profile = SpaceProfile::findOne(['contentcontainer_id' => $this->contentContainer->contentcontainer_id]); if ($this->profile) { $this->address = (string)$this->profile->address; $this->city = (string)$this->profile->city; $this->state = (string)$this->profile->state; $this->zip = (string)$this->profile->zip; $this->email = (string)$this->profile->email; $this->phone = (string)$this->profile->phone; $this->animals_we_accept = (string)$this->profile->animals_we_accept; $this->mission_statement = (string)$this->profile->mission_statement; $this->template_key = !empty($this->profile->template_key) ? (string)$this->profile->template_key : TemplateRegistry::TEMPLATE_RESCUE_CENTER; $this->header_html = $this->profile->header_html; $this->body_html = $this->profile->body_html; $this->footer_html = $this->profile->footer_html; } $this->rescue_name = $this->getSpaceName(); $this->description = $this->getSpaceDescription(); } public function rules() { $contactRules = ValidationStandards::contactRules([ 'email' => 'email', 'phone' => 'phone', 'state' => 'state', 'zip' => 'zip', ]); return array_merge([ [['address', 'city', 'state', 'zip', 'email', 'phone', 'animals_we_accept', 'mission_statement', 'template_key'], 'required'], [['animals_we_accept', 'description', 'mission_statement', 'header_html', 'body_html', 'footer_html'], 'string'], [['template_key'], 'in', 'range' => array_keys(TemplateRegistry::options())], [['rescue_name', 'email'], 'string', 'max' => 190], [['address'], 'string', 'max' => 255], [['city'], 'string', 'max' => 120], [['state'], 'string', 'max' => 2], [['zip'], 'string', 'max' => 10], [['phone'], 'string', 'max' => 32], [['template_key'], 'string', 'max' => 64], [['removeIcon', 'removeBackgroundImage'], 'boolean'], [['iconFile', 'backgroundImageFile'], 'file', 'skipOnEmpty' => true, 'extensions' => UploadStandards::imageExtensions(), 'checkExtensionByMimeType' => true, 'mimeTypes' => UploadStandards::imageMimeTypes(), 'maxSize' => UploadStandards::IMAGE_MAX_BYTES, ], ], $contactRules); } public function save(): bool { if (!$this->validate()) { return false; } $persistedDescription = $this->resolvePersistedDescription(); $profile = $this->profile ?: new SpaceProfile(); $profile->contentcontainer_id = $this->contentContainer->contentcontainer_id; $profile->rescue_name = $this->getSpaceName(); $profile->address = trim($this->address); $profile->city = trim($this->city); $profile->state = strtoupper(trim($this->state)); $profile->zip = trim($this->zip); $profile->email = trim($this->email); $profile->phone = trim($this->phone); $profile->animals_we_accept = trim($this->animals_we_accept); $profile->description = $persistedDescription; $profile->mission_statement = trim($this->mission_statement); $profile->slug = $this->generateUniqueSlug(); $profile->template_key = $this->template_key; $profile->header_html = ProfileHtmlSanitizer::sanitize($this->header_html); $profile->body_html = ProfileHtmlSanitizer::sanitize($this->body_html); $profile->footer_html = ProfileHtmlSanitizer::sanitize($this->footer_html); if ($this->removeIcon) { $this->deleteStoredFile($profile->icon_path); $profile->icon_path = null; } if ($this->removeBackgroundImage) { $this->deleteStoredFile($profile->background_image_path); $profile->background_image_path = null; } if ($this->iconFile instanceof UploadedFile) { $this->deleteStoredFile($profile->icon_path); $profile->icon_path = $this->storeImage($this->iconFile, 'icon'); } if ($this->backgroundImageFile instanceof UploadedFile) { $this->deleteStoredFile($profile->background_image_path); $profile->background_image_path = $this->storeImage($this->backgroundImageFile, 'background'); } if (!$profile->save()) { $this->addErrors($profile->getErrors()); return false; } $this->setDefaultHomePage(); $this->profile = $profile; return true; } public function getProfile(): ?SpaceProfile { return $this->profile; } public function getTemplateOptions(): array { return TemplateRegistry::options(); } private function storeImage(UploadedFile $file, string $prefix): ?string { $relativeDir = '/uploads/space-profiles/' . $this->contentContainer->contentcontainer_id; $absoluteDir = Yii::getAlias('@webroot') . $relativeDir; FileHelper::createDirectory($absoluteDir); $random = Yii::$app->security->generateRandomString(8); $fileName = $prefix . '-' . time() . '-' . $random . '.' . strtolower((string)$file->extension); $absolutePath = $absoluteDir . '/' . $fileName; if (!$file->saveAs($absolutePath)) { return null; } return $relativeDir . '/' . $fileName; } private function deleteStoredFile(?string $relativePath): void { if (empty($relativePath)) { return; } $absolutePath = Yii::getAlias('@webroot') . $relativePath; if (is_file($absolutePath)) { @unlink($absolutePath); } } private function buildBaseSlug(): string { $source = $this->getSpaceName(); $normalized = trim((string)$source); $ascii = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $normalized); if ($ascii !== false) { $normalized = $ascii; } $slug = strtolower($normalized); $slug = preg_replace('/[^a-z0-9]+/', '-', $slug) ?? ''; $slug = trim($slug, '-'); return $slug !== '' ? $slug : 'rescue'; } private function generateUniqueSlug(): string { $base = $this->buildBaseSlug(); $candidate = $base; $suffix = 1; while ($this->slugExists($candidate)) { $candidate = $base . '-' . $suffix; $suffix++; } return $candidate; } private function slugExists(string $slug): bool { $query = SpaceProfile::find()->where(['slug' => $slug]); if ($this->profile && !$this->profile->isNewRecord) { $query->andWhere(['!=', 'id', (int)$this->profile->id]); } return $query->exists(); } private function setDefaultHomePage(): void { if (!$this->contentContainer instanceof Space) { return; } $defaultUrl = $this->contentContainer->createUrl('/space_profiles/profile/view'); $settings = $this->contentContainer->getSettings(); $settings->set('indexUrl', $defaultUrl); $settings->set('indexGuestUrl', $defaultUrl); } private function getSpaceName(): string { if ($this->contentContainer instanceof Space) { return trim((string)$this->contentContainer->name); } return trim($this->rescue_name); } private function getSpaceDescription(): string { if ($this->contentContainer instanceof Space) { $about = trim((string)$this->contentContainer->about); if ($about !== '') { return $about; } return trim((string)$this->contentContainer->description); } return trim($this->description); } private function resolvePersistedDescription(): string { $description = $this->getSpaceDescription(); if ($description !== '') { return $description; } $mission = trim($this->mission_statement); if ($mission !== '') { return $mission; } $animals = trim($this->animals_we_accept); if ($animals !== '') { return $animals; } return $this->getSpaceName(); } }