passiveMode = true; if($this->effects === null) $this->effects = []; } public function getId(): int { return $this->zone_id ?? 0; } public function hasId(): bool { return isset($this->zone_id) && $this->zone_id > 0; } private function setId(int $id): void { if($id < 1) throw new ZoneInvalidIdException; $this->zone_id = $id; } public function getUserId(): int { return $this->user_id ?? 0; } public function setUserId(int $userId): void { $this->user_id = $userId; } private $userObj = null; public function getUser(): User { if($this->userObj === null) $this->userObj = User::byId($this->getUserId()); return $this->userObj; } public function getName(): string { return $this->zone_name; } public function setName(string $name): void { if(!self::validName($name)) throw new ZoneInvalidNameException; $this->zone_name = $name; } public function getUrl(): string { return 'https://' . sprintf(Config::get('domain.zone'), $this->getName()); } public function getUrlForPreview(): string { return $this->getUrl() . '?preview=1'; } public function getScreenshotPath(): string { return YTKNS_SCREENSHOTS . '/' . $this->getName() . '.jpg'; } public function getScreenshotUrl(): string { return 'https://' . Config::get('domain.main') . '/ss/' . $this->getName() . '.jpg'; } public function takeScreenshot(): void { $path = escapeshellarg($this->getScreenshotPath()); $url = escapeshellarg($this->getUrlForPreview()); system(sprintf('/usr/bin/firefox --window-size=800,600 --screenshot %s %s', $path, $url)); //system(sprintf('/usr/bin/convert %1$s 200x150 %1$s', $path)); } public function removeScreenshot(): void { $path = $this->getScreenshotPath(); if(is_file($path)) unlink($path); } public function getTitle(): string { return $this->zone_title; } public function setTitle(string $title): void { if(strlen($title) > 255) throw new ZoneInvalidTitleException; $this->zone_title = $title; } public function getViews(): int { return $this->zone_views ?? 0; } public function incrementViews(): void { $updateViews = DB::prepare(' UPDATE `ytkns_zones` SET `zone_views` = `zone_views` + 1 WHERE `zone_id` = :zone '); $updateViews->bindValue('zone', $this->getId()); if($updateViews->execute()) $this->zone_views = $this->getViews() + 1; } public function getEffects(): array { if(!is_array($this->effects)) $this->effects = $this->hasId() ? ZoneEffect::byZone($this) : []; return $this->effects; } public function getPageBuilder(bool $quiet = false): PageBuilder { $pageBuilder = new PageBuilder($this->getTitle()); $effects = $this->getEffects(); foreach($effects as $effect) $effect->applyEffect($pageBuilder, $quiet); return $pageBuilder; } public function addEffect(PageEffectInterface $effect): void { if(is_array($this->effects)) $this->effects[] = $effect; if(!$this->passiveMode) $this->addEffectDatabase($effect); } private function addEffectDatabase(PageEffectInterface $effect): void { if(!$this->hasId()) return; $insert = DB::prepare(' REPLACE INTO `ytkns_zones_effects` ( `zone_id`, `effect_name`, `effect_params` ) VALUES ( :zone, :name, :params ) '); $insert->bindValue('zone', $this->getId()); $insert->bindValue('name', substr(get_class($effect), 14, -6)); $insert->bindValue('params', json_encode($effect->getEffectParams())); $insert->execute(); } public function removeEffects(): void { $this->effects = []; if(!$this->passiveMode) $this->removeEffectsDatabase(); } private function removeEffectsDatabase(): void { if(!$this->hasId()) return; $removeEffects = DB::prepare(' DELETE FROM `ytkns_zones_effects` WHERE `zone_id` = :zone '); $removeEffects->bindValue('zone', $this->getId()); $removeEffects->execute(); } public static function byId(string $id): self { $getZone = DB::prepare(' SELECT `zone_id`, `user_id`, `zone_name`, `zone_title`, `zone_views`, UNIX_TIMESTAMP(`zone_created`) AS `zone_created`, UNIX_TIMESTAMP(`zone_updated`) AS `zone_updated` FROM `ytkns_zones` WHERE `zone_id` = :zone '); $getZone->bindValue('zone', $id); $zone = $getZone->execute() ? $getZone->fetchObject(self::class) : false; if(!$zone) throw new ZoneNotFoundException; return $zone; } public static function byName(string $name): self { $getZone = DB::prepare(' SELECT `zone_id`, `user_id`, `zone_name`, `zone_title`, `zone_views`, UNIX_TIMESTAMP(`zone_created`) AS `zone_created`, UNIX_TIMESTAMP(`zone_updated`) AS `zone_updated` FROM `ytkns_zones` WHERE `zone_name` = :name '); $getZone->bindValue('name', $name); $zone = $getZone->execute() ? $getZone->fetchObject(self::class) : false; if(!$zone) throw new ZoneNotFoundException; return $zone; } public static function byUser(User $user, ?string $orderBy = null, bool $ascending = true, int $take = 0, int $offset = 0): array { $getZonesQuery = ' SELECT `zone_id`, `user_id`, `zone_name`, `zone_title`, `zone_views`, UNIX_TIMESTAMP(`zone_created`) AS `zone_created`, UNIX_TIMESTAMP(`zone_updated`) AS `zone_updated` FROM `ytkns_zones` WHERE `user_id` = :user '; if($orderBy !== null) $getZonesQuery .= sprintf('ORDER BY `%s` %s', $orderBy, $ascending ? 'ASC' : 'DESC'); if($take > 0) $getZonesQuery .= sprintf(' LIMIT %d OFFSET %d', $take, $offset); $getZones = DB::prepare($getZonesQuery); $getZones->bindValue('user', $user->getId()); $getZones->execute(); $zones = []; while($zone = $getZones->fetchObject(self::class)) $zones[] = $zone; return $zones; } public static function all(?string $orderBy = null, bool $ascending = true, int $take = 0, int $offset = 0): array { $getZonesQuery = ' SELECT `zone_id`, `user_id`, `zone_name`, `zone_title`, `zone_views`, UNIX_TIMESTAMP(`zone_created`) AS `zone_created`, UNIX_TIMESTAMP(`zone_updated`) AS `zone_updated` FROM `ytkns_zones` '; if($orderBy !== null) $getZonesQuery .= sprintf(' ORDER BY `%s` %s', $orderBy, $ascending ? 'ASC' : 'DESC'); if($take > 0) $getZonesQuery .= sprintf(' LIMIT %d OFFSET %d', $take, $offset); $getZones = DB::prepare($getZonesQuery); $getZones->execute(); $zones = []; while($zone = $getZones->fetchObject(self::class)) $zones[] = $zone; return $zones; } public static function count(): int { $getZoneCount = DB::prepare(' SELECT COUNT(`zone_id`) FROM `ytkns_zones` '); return (int)($getZoneCount->execute() ? $getZoneCount->fetchColumn() : 0); } public static function create(User $user, string $name, string $title): self { $create = DB::prepare(' INSERT INTO `ytkns_zones` ( `user_id`, `zone_name`, `zone_title` ) VALUES ( :user, LOWER(:name), :title ) '); $create->bindValue('user', $user->getId()); $create->bindValue('name', $name); $create->bindValue('title', $title); $create->execute(); try { return self::byName($name); } catch(ZoneNotFoundException $ex) { throw new ZoneCreationFailedException; } } public function update(array $save = ['user_id', 'zone_name', 'zone_title']): void { if(!$this->hasId()) return; $set = [ '`zone_updated` = NOW()', ]; foreach($save as $param) $set[] = sprintf('`%1$s` = :%1$s', $param); $update = DB::prepare(sprintf('UPDATE `ytkns_zones` SET %s WHERE `zone_id` = :zone', implode(', ', $set))); if(in_array('user_id', $save)) $update->bindValue('user_id', $this->getUserId()); if(in_array('zone_name', $save)) $update->bindValue('zone_name', $this->getName()); if(in_array('zone_title', $save)) $update->bindValue('zone_title', $this->getTitle()); $update->bindValue('zone', $this->getId()); $update->execute(); if($this->passiveMode) { $effects = $this->getEffects(); $this->removeEffectsDatabase(); foreach($this->getEffects() as $effectInfo) $this->addEffectDatabase($effectInfo); } } public static function exists(string $name): bool { $check = DB::prepare(' SELECT COUNT(`zone_name`) > 0 FROM `ytkns_zones` WHERE `zone_name` = :name '); $check->bindValue('name', $name); return $check->execute() ? (bool)$check->fetchColumn() : true; } public function delete(): void { $delete = DB::prepare(' DELETE FROM `ytkns_zones` WHERE `zone_id` = :zone '); $delete->bindValue('zone', $this->getId()); $delete->execute(); } public static function validName(string $name): bool { return preg_match('#^([A-Za-z0-9]{1,50})$#', $name); } public function toJson(bool $asString = false) { $zoneInfo = [ 'id' => $this->getId(), 'name' => $this->getName(), 'title' => $this->getTitle(), 'effects' => [], ]; foreach($this->getEffects() as $effect) $zoneInfo['effects'][] = $effect->toJson(); if($asString) $zoneInfo = json_encode($zoneInfo); return $zoneInfo; } public function queueTask(string $task, ...$params): void { ZoneTask::enqueue($this, $task, $params); } }