File: /home/xedaptot/ai.naniguide.com/app/Model/Form.php
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Library\Traits\HasUid;
use Validator;
use App\Model\Template;
use App\Library\Contracts\TemplateSubjectInterface;
use App\Library\GeneralTagResolver;
use App\Library\HtmlHandler\TransformTag;
use App\Services\TemplateService;
use League\Pipeline\PipelineBuilder;
/**
* @property \App\Model\MailList|null $mailList
* @property \App\Model\Template|null $template
* @property \App\Model\Customer|null $customer
*/
class Form extends Model implements TemplateSubjectInterface
{
use HasFactory;
use HasUid;
public const STATUS_DRAFT = 'draft';
public const STATUS_PUBLISHED = 'published';
protected $fillable = [
'mail_list_id', 'name'
];
public function mailList()
{
return $this->belongsTo('App\Model\MailList');
}
public function template()
{
return $this->belongsTo('App\Model\Template');
}
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function hasTemplate(): bool
{
return !is_null($this->template_id) && $this->template()->exists();
}
public function getThumbUrl(): string
{
return $this->template
? $this->template->getThumbUrl()
: url('images/placeholder.jpg');
}
public function setTemplate($template, string $name): void
{
TemplateService::for($this)->setTemplate($template, $name);
}
public function removeTemplate(): void
{
TemplateService::for($this)->removeTemplate();
}
public function setTemplateContent($content, $json): void
{
$this->template->updateContent($json, $content);
}
public function getTemplateContent(): string
{
return $this->template->content;
}
public static function newDefault($customer)
{
$form = new self();
$form->name = trans('messages.form.untitled');
$form->status = self::STATUS_DRAFT;
$form->customer_id = $customer->id;
return $form;
}
public function createFromArray($params)
{
$this->fill($params);
$validator = Validator::make($params, [
'name' => 'required',
'template_uid' => 'required',
'mail_list_uid' => 'required',
]);
if ($validator->fails()) {
return $validator;
}
$this->mail_list_id = \App\Model\MailList::findByUid($params['mail_list_uid'])->id;
$selectedTemplate = Template::findByUid($params['template_uid']);
$this->changeTemplate($selectedTemplate); // also save
return $validator;
}
public function changeTemplate($selectedTemplate)
{
$this->setTemplate($selectedTemplate, trans('messages.form.template_name', ['name' => $this->name]));
}
public function scopeFilter($query, $params)
{
// list
if (!empty($params['mail_list_uid'])) {
$query = $query->where('mail_list_id', '=', \App\Model\MailList::findByUid($params['mail_list_uid'])->id);
}
// website
if (!empty($params['website_uid'])) {
if ($params['website_uid'] === 'none') {
$query = $query->notConnectedToWebsite();
} else {
$website = \App\Model\Website::findByUid($params['website_uid']);
if ($website) {
$query = $query->byWebsite($website);
}
}
}
}
public function scopeSearch($query, $keyword)
{
// Keyword
if (!empty($keyword)) {
$query = $query->where('name', 'like', '%'.trim($keyword).'%');
}
}
public function updateMetadata($data)
{
$metadata = (object) array_merge((array) $this->getMetadata(), $data);
$this['metadata'] = json_encode($metadata);
$this->save();
}
public function getMetadata($name = null)
{
if (!$this['metadata']) {
return json_decode('{}', true);
}
$data = json_decode($this['metadata'], true);
if ($name != null) {
if (isset($data[$name])) {
return $data[$name];
} else {
return null;
}
} else {
return $data;
}
}
public function saveSettingsFromArray($params)
{
if (!empty($params['mail_list_uid'])) {
$list = \App\Model\MailList::findByUid($params['mail_list_uid']);
if ($list) {
$this->mail_list_id = $list->id;
}
}
if (!empty($params['name'])) {
$this->name = $params['name'];
}
$this->updateMetadata([
'overlay_opacity' => $params['overlay_opacity'] ?? null,
'display' => $params['display'] ?? null,
'wait_time' => $params['wait_time'] ?? null,
'element_id' => $params['element_id'] ?? null,
]);
}
public function connect($site)
{
$this->updateMetadata([
'website_uid' => $site->uid,
]);
}
public function getWebsite()
{
return $this->getMetadata('website_uid') ? \App\Model\Website::findByUid($this->getMetadata('website_uid')) : null;
}
public function disconnect()
{
$this->updateMetadata([
'website_uid' => null,
]);
}
public static function scopeByWebsite($query, $website)
{
$query = $query->where('metadata', 'like', '%'.$website->uid.'%');
}
public function scopeNotConnectedToWebsite($query)
{
$query->where(function ($q) {
$q->whereNull('metadata')
->orWhere('metadata', 'not like', '%website_uid%')
->orWhere('metadata', 'like', '%"website_uid":null%');
});
}
public function getBuilderTags()
{
$result = [];
$tags = [
['name' => 'LIST_NAME', 'required' => false],
['name' => 'CURRENT_YEAR', 'required' => false],
['name' => 'CURRENT_MONTH', 'required' => false],
['name' => 'CURRENT_DAY', 'required' => false],
];
foreach ($tags as $tag) {
$result[] = [
'type' => 'label',
'text' => '{'.$tag['name'].'}',
'tag' => '{'.$tag['name'].'}',
'required' => true,
];
}
return $result;
}
public function renderedContent($content = null)
{
if (!$content) {
$content = $this->template->content;
}
return (new PipelineBuilder())
->add(new TransformTag(new GeneralTagResolver(), $this->mailList))
->build()
->process($content);
}
public function publish()
{
$this->status = self::STATUS_PUBLISHED;
$this->save();
}
public function unpublish()
{
$this->status = self::STATUS_DRAFT;
$this->save();
}
public static function scopePublished($query)
{
$query = $query->where('status', '=', self::STATUS_PUBLISHED);
}
public function isPublished()
{
return $this->status == self::STATUS_PUBLISHED;
}
public function isStageExcluded(string $name): bool
{
// Temporarily
return false;
}
/**
* Reserved input name used by every TermsOfServiceElement instance.
*
* Re-exported from `TermsAcceptanceService` (the canonical owner of
* compliance domain logic) so legacy callers + tests that already
* referenced `Form::TERMS_RESERVED_NAME` continue to work without
* changes. The validation walker, pre-flight gate, and any future
* compliance widgets live in the service layer — see
* `app/Services/Forms/TermsAcceptanceService.php`.
*/
public const TERMS_RESERVED_NAME = \App\Services\Forms\TermsAcceptanceService::RESERVED_INPUT_NAME;
}