+
diff --git a/app/Core/App.php b/app/Core/App.php
index 8311b3b..cd6381c 100644
--- a/app/Core/App.php
+++ b/app/Core/App.php
@@ -47,7 +47,7 @@ final class App
*
* @var string
*/
- public const VERSION = '0.2.0-alpha';
+ public const VERSION = '0.2.1-alpha';
/**
* Set the base path of the application
diff --git a/app/Core/Cache/AbstractCacheDriver.php b/app/Core/Cache/AbstractCacheDriver.php
index 4f3418e..367e5bd 100644
--- a/app/Core/Cache/AbstractCacheDriver.php
+++ b/app/Core/Cache/AbstractCacheDriver.php
@@ -73,17 +73,17 @@ public function set(string $key, $value, $ttl = null): bool
{
$item = $this->cache->getItem($key);
- // Если кэша с таким ключом нет, устанавливаем новое значение
- if (!$item->isHit()) {
- $item->set($value);
- $item->expiresAfter($ttl);
- return $this->cache->save($item);
+ $item->set($value);
+ $item->expiresAfter($ttl);
+ $result = $this->cache->save($item);
+
+ if (!$result) {
+ logs()->error("ERROR SAVE CACHE - $key");
}
- return false;
+ return $result;
}
-
/**
* Удаляет значение из кэша по ключу
*
diff --git a/app/Core/Database/Entities/User.php b/app/Core/Database/Entities/User.php
index a4175f8..7bb2884 100644
--- a/app/Core/Database/Entities/User.php
+++ b/app/Core/Database/Entities/User.php
@@ -89,7 +89,7 @@ class User
public $created_at;
/**
- * @Column(type="timestamp", default="CURRENT_TIMESTAMP")
+ * @Column(type="timestamp", nullable=true)
*/
public $last_logged;
diff --git a/app/Core/Http/Controllers/Profile/ProfileRedirectController.php b/app/Core/Http/Controllers/Profile/ProfileRedirectController.php
index 961e885..bf093bd 100644
--- a/app/Core/Http/Controllers/Profile/ProfileRedirectController.php
+++ b/app/Core/Http/Controllers/Profile/ProfileRedirectController.php
@@ -12,9 +12,9 @@ public function search(FluteRequest $request, $value)
{
$redirectUrl = $request->input('else-redirect', null);
- $user = rep(UserSocialNetwork::class)->findOne([
+ $user = rep(UserSocialNetwork::class)->select()->where([
'value' => $value
- ]);
+ ])->load('user')->fetchOne();
if (!empty($redirectUrl) && empty($user))
return redirect($redirectUrl);
diff --git a/app/Core/Services/EventNotifications.php b/app/Core/Services/EventNotifications.php
index 31b5b98..7e88e4c 100644
--- a/app/Core/Services/EventNotifications.php
+++ b/app/Core/Services/EventNotifications.php
@@ -3,7 +3,6 @@
namespace Flute\Core\Services;
use Flute\Core\Database\Entities\EventNotification;
-use Flute\Core\Database\Entities\Notification;
class EventNotifications
{
@@ -15,38 +14,99 @@ public function listen()
$events = rep(EventNotification::class)->findAll();
foreach ($events as $event) {
- events()->addDeferredListener($event->event, function ($eventInstance) use ($event) {
- $notification = new Notification;
- $notification->content = $this->replaceContent($event->content, $eventInstance);
- $notification->url = $event->url;
- $notification->user = user()->getCurrentUser();
- $notification->icon = $event->icon;
- $notification->title = $event->title;
-
- notification()->create($notification);
- });
+ events()->addDeferredListener($event->event, [$this, 'handleEvent']);
}
}
- private function replaceContent(string $content, $event)
+ public static function handleEvent($eventInstance)
{
- $content = $this->replaceUserContent($content);
-
- return preg_replace_callback('/\{(.*?)\}/', function ($matches) use ($event) {
- $parts = explode('.', $matches[1]);
- if (count($parts) == 2 && method_exists($event, $parts[0])) {
- return $event->{$parts[0]}()->{$parts[1]};
- } elseif (count($parts) == 1 && method_exists($event, $parts[0])) {
- return $event->{$parts[0]}();
- } elseif (property_exists($event, $matches[1])) {
- return $event->{$matches[1]};
- } else {
- return $matches[0];
+ if ($eventInstance::NAME) {
+ $events = rep(EventNotification::class)->select()->where('event', $eventInstance::NAME)->fetchAll();
+
+ foreach ($events as $event) {
+ $table = db()->table('notifications');
+
+ $table->insertOne([
+ 'content' => self::replaceContent($event->content, $eventInstance),
+ 'icon' => $event->icon,
+ 'url' => $event->url,
+ 'title' => $event->title,
+ 'user_id' => user()->getCurrentUser()->id,
+ 'created_at' => new \DateTime()
+ ]);
}
+ }
+ }
+
+ private static function replaceContent(string $content, $eventInstance): string
+ {
+ $content = self::replaceUserContent($content);
+
+ return preg_replace_callback('/\{(.*?)\}/', function ($matches) use ($eventInstance) {
+ return self::evaluateExpression($matches[1], $eventInstance);
}, $content);
}
- private function replaceUserContent(string $content)
+ private static function evaluateExpression($expression, $eventInstance)
+ {
+ if (preg_match('/^(\w+)\((.*?)\)$/', $expression, $matches)) {
+ $func = $matches[1];
+ $args = self::parseArguments($matches[2]);
+ if (function_exists($func)) {
+ $result = call_user_func_array($func, $args);
+ return is_object($result) ? self::getNestedProperty($result, array_slice(explode('.', $expression), 1)) : $result;
+ }
+ }
+
+ $parts = explode('.', $expression);
+ return self::getNestedProperty($eventInstance, $parts);
+ }
+
+ private static function getNestedProperty($object, array $parts)
+ {
+ $current = $object;
+
+ foreach ($parts as $part) {
+ if (preg_match('/(\w+)\((.*?)\)$/', $part, $matches)) {
+ $func = $matches[1];
+ $args = self::parseArguments($matches[2]);
+ if (is_object($current) && method_exists($current, $func)) {
+ $current = call_user_func_array([$current, $func], $args);
+ } elseif (function_exists($func)) {
+ $current = call_user_func_array($func, $args);
+ } else {
+ return '{' . implode('.', $parts) . '}';
+ }
+ } elseif (is_object($current)) {
+ if (method_exists($current, $part)) {
+ $current = $current->{$part}();
+ } elseif (property_exists($current, $part)) {
+ $current = $current->{$part};
+ } else {
+ return '{' . implode('.', $parts) . '}';
+ }
+ } else {
+ return '{' . implode('.', $parts) . '}';
+ }
+ }
+
+ return $current;
+ }
+
+ private static function parseArguments($argsString)
+ {
+ $args = [];
+ if (!empty($argsString)) {
+ $parts = explode(',', $argsString);
+ foreach ($parts as $part) {
+ $part = trim($part, " \t\n\r\0\x0B'\"");
+ $args[] = $part;
+ }
+ }
+ return $args;
+ }
+
+ private static function replaceUserContent(string $content)
{
return str_replace(['{name}', '{login}', '{email}', '{balance}'], [
user()->getCurrentUser()->name,
diff --git a/app/Core/Support/FluteEventDispatcher.php b/app/Core/Support/FluteEventDispatcher.php
index acbbb8e..89205cd 100644
--- a/app/Core/Support/FluteEventDispatcher.php
+++ b/app/Core/Support/FluteEventDispatcher.php
@@ -1,8 +1,8 @@
getListenerId($listener);
+ // if ($listener instanceof \Closure) {
+ // $listener = new SerializableClosure($listener);
+ // }
+
if (!isset($this->deferredListeners[$eventName])) {
$this->deferredListeners[$eventName] = [];
}
+ if (isset($this->deferredListeners[$eventName][$listenerId]))
+ return;
+
$this->deferredListeners[$eventName][$listenerId] = ['listener' => $listener, 'priority' => $priority];
- if (is_callable($listener))
+ if (is_callable($listener)) {
$this->addListener($eventName, $listener, $priority);
+ $this->saveDeferredListenersToCache();
+ }
}
public function removeDeferredListener($eventName, $listener)
@@ -41,7 +50,7 @@ public function removeDeferredListener($eventName, $listener)
unset($this->deferredListeners[$eventName]);
}
- cache()->set($this->deferredListenersKey, $this->deferredListeners);
+ $this->saveDeferredListenersToCache();
}
$this->removeListener($eventName, $listener);
@@ -56,13 +65,20 @@ private function initializeDeferredListeners()
{
$deferredListeners = cache()->get($this->deferredListenersKey, []);
- if (!is_array($deferredListeners))
+ if (!is_array($deferredListeners)) {
$deferredListeners = [];
+ }
foreach ($deferredListeners as $eventName => $listeners) {
foreach ($listeners as $listenerData) {
- if (is_callable($listenerData['listener']))
- $this->addListener($eventName, $listenerData['listener'], $listenerData['priority']);
+ $listener = $listenerData['listener'];
+ if ($listener instanceof SerializableClosure) {
+ $listener = $listener->getClosure();
+ }
+
+ if (is_callable($listener)) {
+ $this->addListener($eventName, $listener, $listenerData['priority']);
+ }
}
}
@@ -71,14 +87,34 @@ private function initializeDeferredListeners()
private function getListenerId($listener)
{
- if (is_object($listener)) {
- return spl_object_hash($listener);
+ if ($listener instanceof \Closure) {
+ return $this->getClosureId($listener);
+ }
+
+ if ($listener instanceof SerializableClosure) {
+ return $this->getClosureId($listener->getClosure());
}
if (is_array($listener)) {
+ if (is_object($listener[0])) {
+ return spl_object_hash($listener[0]) . '::' . $listener[1];
+ }
+
return $listener[0] . '::' . $listener[1];
}
+ if (is_object($listener)) {
+ return $this->getClosureId($listener);
+ }
+
return $listener;
}
+
+ private function getClosureId($closure)
+ {
+ $reflection = new ReflectionClosure($closure);
+ $code = $reflection->getCode();
+
+ return md5($code);
+ }
}
diff --git a/bootstrap/app.php b/bootstrap/app.php
index b9db75f..5a8f6fc 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -2,6 +2,14 @@
declare(strict_types=1);
+if (version_compare(PHP_VERSION, '7.4.0', '<')) {
+ exit('Flute requires PHP version 7.4 or higher.');
+}
+
+if (!file_exists(BASE_PATH . 'vendor/autoload.php')) {
+ exit('Folder "vendor" wasn\'t found. Please, check your files again');
+}
+
use Flute\Core\App;
use Flute\Core\ServiceProviders\AdminServiceProvider;
use Flute\Core\ServiceProviders\AuthServiceProvider;
@@ -41,10 +49,6 @@
use Flute\Core\ServiceProviders\WidgetServiceProvider;
use Flute\Core\ServiceProviders\EmailServiceProvider;
-if (!file_exists(BASE_PATH . 'vendor/autoload.php')) {
- exit('Folder "vendor" wasn\'t found. Please, check your files again');
-}
-
/**
* Include the composer autoloader
*/