From d98c3422fc53ba603cb64b98249b7f6f498f7497 Mon Sep 17 00:00:00 2001 From: Alexander Pankratov Date: Sun, 30 Apr 2023 18:13:26 +0200 Subject: [PATCH 1/6] Feat: allow different serizalizers for dbProperties --- src/Db/DbPropertiesFactory.php | 62 ++++++++++--------- src/Db/DbType.php | 7 +-- src/Db/DriverArray.php | 30 ++++++++- src/Db/MemoryArray.php | 2 +- src/Db/MysqlArray.php | 1 - src/Db/PostgresArray.php | 10 +-- src/Db/RedisArray.php | 5 +- src/Db/SqlArray.php | 23 +------ src/MTProto.php | 12 ++-- src/MTProtoTools/MinDatabase.php | 2 +- src/MTProtoTools/ReferenceDatabase.php | 2 +- src/Serialization.php | 3 +- ...act.php => PersistentDatabaseAbstract.php} | 21 ++++++- src/Settings/Database/Redis.php | 2 +- src/Settings/Database/SerializerType.php | 11 ++++ src/Settings/Database/SqlAbstract.php | 2 +- 16 files changed, 115 insertions(+), 80 deletions(-) rename src/Settings/Database/{DatabaseAbstract.php => PersistentDatabaseAbstract.php} (85%) create mode 100644 src/Settings/Database/SerializerType.php diff --git a/src/Db/DbPropertiesFactory.php b/src/Db/DbPropertiesFactory.php index 7d5db7121..9d7bc9caf 100644 --- a/src/Db/DbPropertiesFactory.php +++ b/src/Db/DbPropertiesFactory.php @@ -4,11 +4,12 @@ declare(strict_types=1); namespace danog\MadelineProto\Db; -use danog\MadelineProto\Settings\Database\DatabaseAbstract as DatabaseDatabaseAbstract; use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\Database\Mysql; +use danog\MadelineProto\Settings\Database\PersistentDatabaseAbstract; use danog\MadelineProto\Settings\Database\Postgres; use danog\MadelineProto\Settings\Database\Redis; +use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\DatabaseAbstract; use InvalidArgumentException; @@ -18,12 +19,7 @@ use InvalidArgumentException; abstract class DbPropertiesFactory { /** - * Indicates a simple K-V array stored in a database backend. - * Values can be objects or other arrays, but when lots of nesting is required, it's best to split the array into multiple arrays. - */ - const TYPE_ARRAY = 'array'; - /** - * @param self::TYPE_*|array $propertyType + * @param SerializerType | array{serializer?: SerializerType, enableCache?: bool, cacheTtl?: int} $config * @return DbType * @internal * @uses \danog\MadelineProto\Db\MemoryArray @@ -31,41 +27,49 @@ abstract class DbPropertiesFactory * @uses \danog\MadelineProto\Db\PostgresArray * @uses \danog\MadelineProto\Db\RedisArray */ - public static function get(DatabaseAbstract $dbSettings, string $table, $propertyType, ?DbType $value = null) + public static function get(DatabaseAbstract $dbSettings, string $table, SerializerType|array $config, ?DbType $value = null) { - $config = $propertyType['config'] ?? []; - $propertyType = \is_array($propertyType) ? $propertyType['type'] : $propertyType; - $propertyType = \strtolower($propertyType); - $class = $dbSettings instanceof DatabaseDatabaseAbstract && (!($config['enableCache'] ?? true) || !$dbSettings->getCacheTtl()) - ? __NAMESPACE__.'\\NullCache' - : __NAMESPACE__; + $dbSettingsCopy = clone $dbSettings; + $class = __NAMESPACE__; + + if ($dbSettingsCopy instanceof PersistentDatabaseAbstract) { + if ($config instanceof SerializerType) { + $config = [ + 'serializer' => $config + ]; + } + + $config = array_merge([ + 'serializer' => $dbSettings->getSerializer(), + 'enableCache' => true, + 'cacheTtl' => $dbSettings->getCacheTtl(), + ], $config); + + $class = $dbSettings instanceof PersistentDatabaseAbstract && (!($config['enableCache'] ?? true) || !$config['cacheTtl']) + ? __NAMESPACE__ . '\\NullCache' + : __NAMESPACE__; + + $dbSettingsCopy->setSerializer($config['serializer']); + $dbSettingsCopy->setCacheTtl($config['cacheTtl']); + } switch (true) { case $dbSettings instanceof Memory: - $class .= '\\Memory'; + $class .= '\\MemoryArray'; break; case $dbSettings instanceof Mysql: - $class .= '\\Mysql'; + $class .= '\\MysqlArray'; break; case $dbSettings instanceof Postgres: - $class .= '\\Postgres'; + $class .= '\\PostgresArray'; break; case $dbSettings instanceof Redis: - $class .= '\\Redis'; + $class .= '\\RedisArray'; break; default: - throw new InvalidArgumentException('Unknown dbType: '.$dbSettings::class); + throw new InvalidArgumentException('Unknown dbType: ' . $dbSettings::class); } - /** @var DbType $class */ - switch (\strtolower($propertyType)) { - case self::TYPE_ARRAY: - $class .= 'Array'; - break; - default: - throw new InvalidArgumentException("Unknown $propertyType: {$propertyType}"); - } - - return $class::getInstance($table, $value, $dbSettings); + return $class::getInstance($table, $value, $dbSettingsCopy); } } diff --git a/src/Db/DbType.php b/src/Db/DbType.php index df91b01bf..eb6fa4aaf 100644 --- a/src/Db/DbType.php +++ b/src/Db/DbType.php @@ -4,12 +4,9 @@ declare(strict_types=1); namespace danog\MadelineProto\Db; -use danog\MadelineProto\Settings\Database\DatabaseAbstract; +use danog\MadelineProto\Settings\DatabaseAbstract; interface DbType { - /** - * @param DatabaseAbstract $settings - */ - public static function getInstance(string $table, DbType|array|null $previous, $settings): static; + public static function getInstance(string $table, DbType|array|null $previous, DatabaseAbstract $settings): static; } diff --git a/src/Db/DriverArray.php b/src/Db/DriverArray.php index 981d26156..f6685732c 100644 --- a/src/Db/DriverArray.php +++ b/src/Db/DriverArray.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace danog\MadelineProto\Db; use danog\MadelineProto\Logger; +use danog\MadelineProto\Settings\Database\PersistentDatabaseAbstract; use danog\MadelineProto\Settings\Database\Memory; +use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\SettingsAbstract; use IteratorAggregate; use ReflectionClass; @@ -27,6 +29,7 @@ use function Amp\Future\await; abstract class DriverArray implements DbArray, IteratorAggregate { protected string $table; + protected PersistentDatabaseAbstract $dbSettings; use ArrayCacheTrait; @@ -80,7 +83,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate $instance = new static(); $instance->setTable($table); - /** @psalm-suppress UndefinedPropertyAssignment */ $instance->dbSettings = $settings; $instance->setCacheTtl($settings->getCacheTtl()); @@ -213,4 +215,30 @@ abstract class DriverArray implements DbArray, IteratorAggregate } return \str_replace('NullCache\\', '', $instance::class); } + + /** + * Serialize retrieved value. + */ + protected function serialize(mixed $value): string + { + return match ($this->dbSettings->getSerializer()) { + SerializerType::SERIALIZE => \serialize($value), + SerializerType::IGBINARY => \igbinary_serialize($value), + SerializerType::JSON => json_encode($value, JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), + SerializerType::STRING => (string)$value, + }; + } + + /** + * Deserialize retrieved value. + */ + protected function unserialize(string $value): mixed + { + return match ($this->dbSettings->getSerializer()) { + SerializerType::SERIALIZE => \unserialize($value), + SerializerType::IGBINARY => \igbinary_unserialize($value), + SerializerType::JSON => json_decode($value, true, 256, JSON_THROW_ON_ERROR), + SerializerType::STRING => $value, + }; + } } diff --git a/src/Db/MemoryArray.php b/src/Db/MemoryArray.php index 7bf141440..0d005626c 100644 --- a/src/Db/MemoryArray.php +++ b/src/Db/MemoryArray.php @@ -28,7 +28,7 @@ final class MemoryArray extends ArrayIterator implements DbArray /** * @param Memory $settings */ - public static function getInstance(string $table, $previous, $settings): static + public static function getInstance(string $table, $previous, Memory $settings): static { if ($previous instanceof MemoryArray) { return $previous; diff --git a/src/Db/MysqlArray.php b/src/Db/MysqlArray.php index 7d896f67f..028a7e8f0 100644 --- a/src/Db/MysqlArray.php +++ b/src/Db/MysqlArray.php @@ -22,7 +22,6 @@ use PDO; */ class MysqlArray extends SqlArray { - protected DatabaseMysql $dbSettings; // Legacy protected array $settings; diff --git a/src/Db/PostgresArray.php b/src/Db/PostgresArray.php index b72ab65f0..96e6ce6a2 100644 --- a/src/Db/PostgresArray.php +++ b/src/Db/PostgresArray.php @@ -8,6 +8,7 @@ use Amp\Postgres\PostgresConfig; use danog\MadelineProto\Db\Driver\Postgres; use danog\MadelineProto\Exception; use danog\MadelineProto\Logger; +use danog\MadelineProto\Settings\Database\PersistentDatabaseAbstract; use danog\MadelineProto\Settings\Database\Postgres as DatabasePostgres; use PDO; @@ -21,7 +22,6 @@ use PDO; */ class PostgresArray extends SqlArray { - public DatabasePostgres $dbSettings; // Legacy protected array $settings; @@ -90,14 +90,14 @@ class PostgresArray extends SqlArray } } - protected function getValue(string $value): mixed + protected function unserialize(string $value): mixed { - return \unserialize(\hex2bin($value)); + return parent::unserialize(\hex2bin($value)); } - protected function setValue(mixed $value): string + protected function serialize(mixed $value): string { - return \bin2hex(\serialize($value)); + return \bin2hex(parent::serialize($value)); } /** diff --git a/src/Db/RedisArray.php b/src/Db/RedisArray.php index 55cf4c239..f19cc6931 100644 --- a/src/Db/RedisArray.php +++ b/src/Db/RedisArray.php @@ -21,7 +21,6 @@ use danog\MadelineProto\Settings\Database\Redis as DatabaseRedis; */ class RedisArray extends DriverArray { - protected DatabaseRedis $dbSettings; private RedisRedis $db; // Legacy @@ -86,7 +85,7 @@ class RedisArray extends DriverArray $this->setCache($index, $value); - $this->db->set($this->rKey($index), \serialize($value)); + $this->db->set($this->rKey($index), $this->serialize($value)); $this->setCache($index, $value); } @@ -99,7 +98,7 @@ class RedisArray extends DriverArray $value = $this->db->get($this->rKey($offset)); - if ($value !== null && $value = \unserialize($value)) { + if ($value !== null && $value = $this->unserialize($value)) { $this->setCache($offset, $value); } diff --git a/src/Db/SqlArray.php b/src/Db/SqlArray.php index 42dce6979..91b391434 100644 --- a/src/Db/SqlArray.php +++ b/src/Db/SqlArray.php @@ -8,8 +8,6 @@ use Amp\Sql\Pool; use Amp\Sql\Result; use PDO; -use function serialize; - /** * Generic SQL database backend. * @@ -59,21 +57,6 @@ abstract class SqlArray extends DriverArray return $this; } - /** - * Deserialize retrieved value. - */ - protected function getValue(string $value): mixed - { - return \unserialize($value); - } - - /** - * Serialize retrieved value. - */ - protected function setValue(mixed $value): string - { - return \serialize($value); - } /** * Get iterator. @@ -83,7 +66,7 @@ abstract class SqlArray extends DriverArray public function getIterator(): \Traversable { foreach ($this->execute($this->queries[self::SQL_ITERATE]) as ['key' => $key, 'value' => $value]) { - yield $key => $this->getValue($value); + yield $key => $this->unserialize($value); } } @@ -103,7 +86,7 @@ abstract class SqlArray extends DriverArray return null; } - $value = $this->getValue($row['value']); + $value = $this->unserialize($row['value']); $this->setCache($key, $value); return $value; @@ -122,7 +105,7 @@ abstract class SqlArray extends DriverArray $this->queries[self::SQL_SET], [ 'index' => $key, - 'value' => $this->setValue($value), + 'value' => $this->serialize($value), ], ); $this->setCache($key, $value); diff --git a/src/MTProto.php b/src/MTProto.php index e8484c544..e68689266 100644 --- a/src/MTProto.php +++ b/src/MTProto.php @@ -48,7 +48,6 @@ use danog\MadelineProto\MTProtoTools\UpdatesState; use danog\MadelineProto\SecretChats\MessageHandler; use danog\MadelineProto\SecretChats\ResponseHandler; use danog\MadelineProto\SecretChats\SeqNoHandler; -use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\TLSchema; use danog\MadelineProto\TL\Conversion\BotAPI; use danog\MadelineProto\TL\Conversion\BotAPIFiles; @@ -502,13 +501,12 @@ final class MTProto implements TLCallback, LoggerGetter * @see DbPropertiesFactory */ protected static array $dbProperties = [ - 'chats' => 'array', - 'full_chats' => 'array', - 'sponsoredMessages' => 'array', - 'channelParticipants' => 'array', - 'usernames' => 'array', + 'chats' => [], + 'full_chats' => [], + 'sponsoredMessages' => [], + 'channelParticipants' => [], + 'usernames' => [], 'session' => [ - 'type' => 'array', 'config' => ['enableCache' => false], ], ]; diff --git a/src/MTProtoTools/MinDatabase.php b/src/MTProtoTools/MinDatabase.php index a50e2f196..cea40e39d 100644 --- a/src/MTProtoTools/MinDatabase.php +++ b/src/MTProtoTools/MinDatabase.php @@ -68,7 +68,7 @@ final class MinDatabase implements TLCallback * @see DbPropertiesFactory */ protected static array $dbProperties = [ - 'db' => 'array', + 'db' => [], ]; public function __construct(MTProto $API) diff --git a/src/MTProtoTools/ReferenceDatabase.php b/src/MTProtoTools/ReferenceDatabase.php index 0c57fda6c..0cc27a9e3 100644 --- a/src/MTProtoTools/ReferenceDatabase.php +++ b/src/MTProtoTools/ReferenceDatabase.php @@ -87,7 +87,7 @@ final class ReferenceDatabase implements TLCallback * @see DbPropertiesFactory */ protected static array $dbProperties = [ - 'db' => 'array', + 'db' => [], ]; public function __construct(private MTProto $API) diff --git a/src/Serialization.php b/src/Serialization.php index 75cf5e75a..574a2451f 100644 --- a/src/Serialization.php +++ b/src/Serialization.php @@ -30,6 +30,7 @@ use Amp\TimeoutException; use danog\MadelineProto\Db\DbPropertiesFactory; use danog\MadelineProto\Db\DriverArray; use danog\MadelineProto\Ipc\Server; +use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\DatabaseAbstract; use Revolt\EventLoop; use Throwable; @@ -216,7 +217,7 @@ abstract class Serialization $unserialized = DbPropertiesFactory::get( $settings, $tableName, - DbPropertiesFactory::TYPE_ARRAY, + SerializerType::SERIALIZE, $unserialized, ); } else { diff --git a/src/Settings/Database/DatabaseAbstract.php b/src/Settings/Database/PersistentDatabaseAbstract.php similarity index 85% rename from src/Settings/Database/DatabaseAbstract.php rename to src/Settings/Database/PersistentDatabaseAbstract.php index a36c6f2b9..ee847df2a 100644 --- a/src/Settings/Database/DatabaseAbstract.php +++ b/src/Settings/Database/PersistentDatabaseAbstract.php @@ -6,12 +6,10 @@ namespace danog\MadelineProto\Settings\Database; use danog\MadelineProto\Settings\DatabaseAbstract as SettingsDatabaseAbstract; -use function time; - /** * Base class for database backends. */ -abstract class DatabaseAbstract extends SettingsDatabaseAbstract +abstract class PersistentDatabaseAbstract extends SettingsDatabaseAbstract { /** * For how long to keep records in memory after last read, for cached backends. @@ -22,12 +20,18 @@ abstract class DatabaseAbstract extends SettingsDatabaseAbstract */ protected string $password = ''; + /** + * Which serializer strategy use by default + */ + protected SerializerType $serializer = SerializerType::SERIALIZE; + public function mergeArray(array $settings): void { foreach (self::toCamel([ 'database', 'password', 'cache_ttl', + 'serializer', ]) as $object => $array) { if (isset($settings[$array])) { $this->{$object}($settings[$array]); @@ -106,4 +110,15 @@ abstract class DatabaseAbstract extends SettingsDatabaseAbstract * Set database URI. */ abstract public function setUri(string $uri): self; + + + public function getSerializer(): SerializerType + { + return $this->serializer; + } + + public function setSerializer(SerializerType $serializer): void + { + $this->serializer = $serializer; + } } diff --git a/src/Settings/Database/Redis.php b/src/Settings/Database/Redis.php index 628cc8704..2e5e31d96 100644 --- a/src/Settings/Database/Redis.php +++ b/src/Settings/Database/Redis.php @@ -7,7 +7,7 @@ namespace danog\MadelineProto\Settings\Database; /** * Redis backend settings. */ -final class Redis extends DatabaseAbstract +final class Redis extends PersistentDatabaseAbstract { /** * Database number. diff --git a/src/Settings/Database/SerializerType.php b/src/Settings/Database/SerializerType.php new file mode 100644 index 000000000..e422397df --- /dev/null +++ b/src/Settings/Database/SerializerType.php @@ -0,0 +1,11 @@ + Date: Tue, 2 May 2023 18:42:46 +0200 Subject: [PATCH 2/6] Misc improvements --- README.md | 16 +++--- composer.json | 2 +- docs | 2 +- examples/bot.php | 2 +- src/Db/DbPropertiesFactory.php | 22 ++++---- src/Db/DbPropertiesTrait.php | 5 +- src/Db/DriverArray.php | 54 +++++++++---------- src/Db/MemoryArray.php | 2 +- src/Db/MysqlArray.php | 1 - src/Db/PostgresArray.php | 27 ++++++---- src/Db/RedisArray.php | 6 +-- src/Db/SqlArray.php | 6 +-- src/MTProto.php | 15 +++--- src/MTProtoTools/MinDatabase.php | 3 +- src/MTProtoTools/ReferenceDatabase.php | 3 +- src/Magic.php | 6 +++ src/Serialization.php | 10 ++-- src/SessionPaths.php | 18 +++++-- ...bstract.php => DriverDatabaseAbstract.php} | 8 ++- src/Settings/Database/Redis.php | 2 +- src/Settings/Database/SerializerType.php | 2 +- src/Settings/Database/SqlAbstract.php | 2 +- 22 files changed, 113 insertions(+), 101 deletions(-) rename src/Settings/Database/{PersistentDatabaseAbstract.php => DriverDatabaseAbstract.php} (92%) diff --git a/README.md b/README.md index 8b078298b..1649fd5ee 100644 --- a/README.md +++ b/README.md @@ -200,15 +200,15 @@ Want to add your own open-source project to this list? [Click here!](https://doc * [Queues](https://docs.madelineproto.xyz/docs/USING_METHODS.html#queues) * [Multiple method calls](https://docs.madelineproto.xyz/docs/USING_METHODS.html#multiple-method-calls) * [FULL API Documentation with descriptions](https://docs.madelineproto.xyz/API_docs/methods/) - * [Logout](https://docs.madelineproto.xyz/logout.html) * [Login](https://docs.madelineproto.xyz/docs/LOGIN.html) - * [Change 2FA password](https://docs.madelineproto.xyz/update2fa.html) - * [Get all chats, broadcast a message to all chats](https://docs.madelineproto.xyz/docs/DIALOGS.html) - * [Get the full participant list of a channel/group/supergroup](https://docs.madelineproto.xyz/getPwrChat.html) - * [Get full info about a user/chat/supergroup/channel](https://docs.madelineproto.xyz/getFullInfo.html) - * [Get info about a user/chat/supergroup/channel](https://docs.madelineproto.xyz/getInfo.html) - * [Get info about the currently logged-in user](https://docs.madelineproto.xyz/getSelf.html) - * [Upload or download files up to 2 GB](https://docs.madelineproto.xyz/docs/FILES.html) + * [Change 2FA password: update2FA](https://docs.madelineproto.xyz/update2fa.html) + * [Get all chats, broadcast a message to all chats: getDialogIds, getDialogs, getFullDialogs](https://docs.madelineproto.xyz/docs/DIALOGS.html) + * [Get the full participant list of a channel/group/supergroup: getPwrChat](https://docs.madelineproto.xyz/getPwrChat.html) + * [Get full info about a user/chat/supergroup/channel: getFullInfo](https://docs.madelineproto.xyz/getFullInfo.html) + * [Get info about a user/chat/supergroup/channel: getInfo](https://docs.madelineproto.xyz/getInfo.html) + * [Get the ID of a user/chat/supergroup/channel/update: getID](https://docs.madelineproto.xyz/getId.html) + * [Get info about the currently logged-in user: getSelf](https://docs.madelineproto.xyz/getSelf.html) + * [Upload or download files up to 2 GB: uploadFrom*, downloadTo*](https://docs.madelineproto.xyz/docs/FILES.html) * [Make a phone call and play a song](https://docs.madelineproto.xyz/docs/CALLS.html) * [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html) * Abort a pending 2FA password reset, see here for more info »: account.declinePasswordReset diff --git a/composer.json b/composer.json index 8c892f15f..039662b39 100644 --- a/composer.json +++ b/composer.json @@ -119,7 +119,7 @@ "test-php56": "tests/test-conversion.sh 5", "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php -d pcre.jit=0 vendor/bin/php-cs-fixer fix -v --diff --dry-run", "cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php -d pcre.jit=0 vendor/bin/php-cs-fixer fix -v --diff", - "psalm": "psalm", + "psalm": "psalm.phar", "docs": "php tools/build_docs.php", "docs-fix": "tools/fix_docs.sh", "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text --config tests/phpunit.xml", diff --git a/docs b/docs index a6959a7fe..0689f6a3d 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit a6959a7fe20409d539ea8fafeafe780681f943b6 +Subproject commit 0689f6a3df370f6626672149a01aa937415e91d8 diff --git a/examples/bot.php b/examples/bot.php index 1ab0cc2a0..3c78c5263 100755 --- a/examples/bot.php +++ b/examples/bot.php @@ -57,7 +57,7 @@ class MyEventHandler extends EventHandler * @see https://docs.madelineproto.xyz/docs/DATABASE.html */ protected static array $dbProperties = [ - 'dataStoredOnDb' => 'array', + 'dataStoredOnDb' => [], ]; /** diff --git a/src/Db/DbPropertiesFactory.php b/src/Db/DbPropertiesFactory.php index 9d7bc9caf..e27c48615 100644 --- a/src/Db/DbPropertiesFactory.php +++ b/src/Db/DbPropertiesFactory.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace danog\MadelineProto\Db; +use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract; use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\Database\Mysql; -use danog\MadelineProto\Settings\Database\PersistentDatabaseAbstract; use danog\MadelineProto\Settings\Database\Postgres; use danog\MadelineProto\Settings\Database\Redis; use danog\MadelineProto\Settings\Database\SerializerType; @@ -14,12 +14,13 @@ use danog\MadelineProto\Settings\DatabaseAbstract; use InvalidArgumentException; /** + * @psalm-type TOrmConfig=array{serializer?: SerializerType, enableCache?: bool, cacheTtl?: int} * This factory class initializes the correct database backend for MadelineProto. */ abstract class DbPropertiesFactory { /** - * @param SerializerType | array{serializer?: SerializerType, enableCache?: bool, cacheTtl?: int} $config + * @param TOrmConfig|'array' $config * @return DbType * @internal * @uses \danog\MadelineProto\Db\MemoryArray @@ -27,25 +28,22 @@ abstract class DbPropertiesFactory * @uses \danog\MadelineProto\Db\PostgresArray * @uses \danog\MadelineProto\Db\RedisArray */ - public static function get(DatabaseAbstract $dbSettings, string $table, SerializerType|array $config, ?DbType $value = null) + public static function get(DatabaseAbstract $dbSettings, string $table, string|array $config, ?DbType $value = null) { + if ($config === 'array') { + $config = []; + } $dbSettingsCopy = clone $dbSettings; $class = __NAMESPACE__; - if ($dbSettingsCopy instanceof PersistentDatabaseAbstract) { - if ($config instanceof SerializerType) { - $config = [ - 'serializer' => $config - ]; - } - - $config = array_merge([ + if ($dbSettingsCopy instanceof DriverDatabaseAbstract) { + $config = \array_merge([ 'serializer' => $dbSettings->getSerializer(), 'enableCache' => true, 'cacheTtl' => $dbSettings->getCacheTtl(), ], $config); - $class = $dbSettings instanceof PersistentDatabaseAbstract && (!($config['enableCache'] ?? true) || !$config['cacheTtl']) + $class = $dbSettings instanceof DriverDatabaseAbstract && (!($config['enableCache'] ?? true) || !$config['cacheTtl']) ? __NAMESPACE__ . '\\NullCache' : __NAMESPACE__; diff --git a/src/Db/DbPropertiesTrait.php b/src/Db/DbPropertiesTrait.php index 127782e1b..1b0b3a590 100644 --- a/src/Db/DbPropertiesTrait.php +++ b/src/Db/DbPropertiesTrait.php @@ -15,8 +15,9 @@ use function Amp\Future\await; * * You will have to define a `$dbProperties` static array property, with a list of properties you want to store to a database. * - * @see DbPropertiesFactory For a list of allowed property types - * @property array $dbProperties + * @psalm-import-type TOrmConfig from DbPropertiesFactory + * + * @property array $dbProperties */ trait DbPropertiesTrait { diff --git a/src/Db/DriverArray.php b/src/Db/DriverArray.php index f6685732c..49abd3dae 100644 --- a/src/Db/DriverArray.php +++ b/src/Db/DriverArray.php @@ -5,9 +5,10 @@ declare(strict_types=1); namespace danog\MadelineProto\Db; use danog\MadelineProto\Logger; -use danog\MadelineProto\Settings\Database\PersistentDatabaseAbstract; +use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract; use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\Database\SerializerType; +use danog\MadelineProto\Settings\DatabaseAbstract; use danog\MadelineProto\SettingsAbstract; use IteratorAggregate; use ReflectionClass; @@ -29,7 +30,11 @@ use function Amp\Future\await; abstract class DriverArray implements DbArray, IteratorAggregate { protected string $table; - protected PersistentDatabaseAbstract $dbSettings; + /** @var callable(mixed): mixed */ + protected $serializer; + /** @var callable(string): mixed */ + protected $deserializer; + protected DriverDatabaseAbstract $dbSettings; use ArrayCacheTrait; @@ -77,7 +82,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate return $this->offsetGet($key) !== null; } - public static function getInstance(string $table, DbType|array|null $previous, $settings): static + public static function getInstance(string $table, DbType|array|null $previous, DatabaseAbstract $settings): static { /** @var MysqlArray|PostgresArray|RedisArray */ $instance = new static(); @@ -85,6 +90,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate $instance->dbSettings = $settings; $instance->setCacheTtl($settings->getCacheTtl()); + $instance->setSerializer($settings->getSerializer()); $instance->startCacheCleanupLoop(); @@ -102,6 +108,22 @@ abstract class DriverArray implements DbArray, IteratorAggregate return $instance; } + protected function setSerializer(SerializerType $serializer): void + { + $this->serializer = match ($serializer) { + SerializerType::SERIALIZE => \serialize(...), + SerializerType::IGBINARY => \igbinary_serialize(...), + SerializerType::JSON => fn ($value) => \json_encode($value, JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), + SerializerType::STRING => strval(...), + }; + $this->deserializer = match ($serializer) { + SerializerType::SERIALIZE => \unserialize(...), + SerializerType::IGBINARY => \igbinary_unserialize(...), + SerializerType::JSON => fn ($value) => \json_decode($value, true, 256, JSON_THROW_ON_ERROR), + SerializerType::STRING => fn ($v) => $v, + }; + } + /** * Rename table of old database, if the new one is not a temporary table name. * @@ -215,30 +237,4 @@ abstract class DriverArray implements DbArray, IteratorAggregate } return \str_replace('NullCache\\', '', $instance::class); } - - /** - * Serialize retrieved value. - */ - protected function serialize(mixed $value): string - { - return match ($this->dbSettings->getSerializer()) { - SerializerType::SERIALIZE => \serialize($value), - SerializerType::IGBINARY => \igbinary_serialize($value), - SerializerType::JSON => json_encode($value, JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), - SerializerType::STRING => (string)$value, - }; - } - - /** - * Deserialize retrieved value. - */ - protected function unserialize(string $value): mixed - { - return match ($this->dbSettings->getSerializer()) { - SerializerType::SERIALIZE => \unserialize($value), - SerializerType::IGBINARY => \igbinary_unserialize($value), - SerializerType::JSON => json_decode($value, true, 256, JSON_THROW_ON_ERROR), - SerializerType::STRING => $value, - }; - } } diff --git a/src/Db/MemoryArray.php b/src/Db/MemoryArray.php index 0d005626c..c85d5a6f0 100644 --- a/src/Db/MemoryArray.php +++ b/src/Db/MemoryArray.php @@ -28,7 +28,7 @@ final class MemoryArray extends ArrayIterator implements DbArray /** * @param Memory $settings */ - public static function getInstance(string $table, $previous, Memory $settings): static + public static function getInstance(string $table, DbType|array|null $previous, $settings): static { if ($previous instanceof MemoryArray) { return $previous; diff --git a/src/Db/MysqlArray.php b/src/Db/MysqlArray.php index 028a7e8f0..19669a87a 100644 --- a/src/Db/MysqlArray.php +++ b/src/Db/MysqlArray.php @@ -22,7 +22,6 @@ use PDO; */ class MysqlArray extends SqlArray { - // Legacy protected array $settings; diff --git a/src/Db/PostgresArray.php b/src/Db/PostgresArray.php index 96e6ce6a2..438a4fad8 100644 --- a/src/Db/PostgresArray.php +++ b/src/Db/PostgresArray.php @@ -4,12 +4,13 @@ declare(strict_types=1); namespace danog\MadelineProto\Db; +use Amp\Postgres\ByteA; use Amp\Postgres\PostgresConfig; use danog\MadelineProto\Db\Driver\Postgres; use danog\MadelineProto\Exception; use danog\MadelineProto\Logger; -use danog\MadelineProto\Settings\Database\PersistentDatabaseAbstract; use danog\MadelineProto\Settings\Database\Postgres as DatabasePostgres; +use danog\MadelineProto\Settings\Database\SerializerType; use PDO; /** @@ -22,7 +23,6 @@ use PDO; */ class PostgresArray extends SqlArray { - // Legacy protected array $settings; @@ -90,16 +90,21 @@ class PostgresArray extends SqlArray } } - protected function unserialize(string $value): mixed + protected function setSerializer(SerializerType $serializer): void { - return parent::unserialize(\hex2bin($value)); + $this->serializer = match ($serializer) { + SerializerType::SERIALIZE => fn ($v) => new ByteA(\serialize($v)), + SerializerType::IGBINARY => fn ($v) => new ByteA(\igbinary_serialize($v)), + SerializerType::JSON => fn ($value) => \json_encode($value, JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), + SerializerType::STRING => strval(...), + }; + $this->deserializer = match ($serializer) { + SerializerType::SERIALIZE => \unserialize(...), + SerializerType::IGBINARY => \igbinary_unserialize(...), + SerializerType::JSON => fn ($value) => \json_decode($value, true, 256, JSON_THROW_ON_ERROR), + SerializerType::STRING => fn ($v) => $v, + }; } - - protected function serialize(mixed $value): string - { - return \bin2hex(parent::serialize($value)); - } - /** * Create table for property. */ @@ -111,7 +116,7 @@ class PostgresArray extends SqlArray CREATE TABLE IF NOT EXISTS \"{$this->table}\" ( \"key\" VARCHAR(255) PRIMARY KEY NOT NULL, - \"value\" TEXT NOT NULL + \"value\" BYTEA NOT NULL ); "); } diff --git a/src/Db/RedisArray.php b/src/Db/RedisArray.php index f19cc6931..c4b102c14 100644 --- a/src/Db/RedisArray.php +++ b/src/Db/RedisArray.php @@ -85,7 +85,7 @@ class RedisArray extends DriverArray $this->setCache($index, $value); - $this->db->set($this->rKey($index), $this->serialize($value)); + $this->db->set($this->rKey($index), ($this->serializer)($value)); $this->setCache($index, $value); } @@ -98,7 +98,7 @@ class RedisArray extends DriverArray $value = $this->db->get($this->rKey($offset)); - if ($value !== null && $value = $this->unserialize($value)) { + if ($value !== null && $value = ($this->deserializer)($value)) { $this->setCache($offset, $value); } @@ -123,7 +123,7 @@ class RedisArray extends DriverArray $len = \strlen($this->rKey('')); foreach ($request as $key) { - yield \substr($key, $len) => \unserialize($this->db->get($key)); + yield \substr($key, $len) => ($this->deserializer)($this->db->get($key)); } } diff --git a/src/Db/SqlArray.php b/src/Db/SqlArray.php index 91b391434..5ffa62809 100644 --- a/src/Db/SqlArray.php +++ b/src/Db/SqlArray.php @@ -66,7 +66,7 @@ abstract class SqlArray extends DriverArray public function getIterator(): \Traversable { foreach ($this->execute($this->queries[self::SQL_ITERATE]) as ['key' => $key, 'value' => $value]) { - yield $key => $this->unserialize($value); + yield $key => ($this->deserializer)($value); } } @@ -86,7 +86,7 @@ abstract class SqlArray extends DriverArray return null; } - $value = $this->unserialize($row['value']); + $value = ($this->deserializer)($row['value']); $this->setCache($key, $value); return $value; @@ -105,7 +105,7 @@ abstract class SqlArray extends DriverArray $this->queries[self::SQL_SET], [ 'index' => $key, - 'value' => $this->serialize($value), + 'value' => ($this->serializer)($value), ], ); $this->setCache($key, $value); diff --git a/src/MTProto.php b/src/MTProto.php index e68689266..fabfdf60b 100644 --- a/src/MTProto.php +++ b/src/MTProto.php @@ -48,6 +48,7 @@ use danog\MadelineProto\MTProtoTools\UpdatesState; use danog\MadelineProto\SecretChats\MessageHandler; use danog\MadelineProto\SecretChats\ResponseHandler; use danog\MadelineProto\SecretChats\SeqNoHandler; +use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\TLSchema; use danog\MadelineProto\TL\Conversion\BotAPI; use danog\MadelineProto\TL\Conversion\BotAPIFiles; @@ -501,14 +502,12 @@ final class MTProto implements TLCallback, LoggerGetter * @see DbPropertiesFactory */ protected static array $dbProperties = [ - 'chats' => [], - 'full_chats' => [], - 'sponsoredMessages' => [], - 'channelParticipants' => [], - 'usernames' => [], - 'session' => [ - 'config' => ['enableCache' => false], - ], + 'chats' => ['serializer' => SerializerType::SERIALIZE], + 'full_chats' => ['serializer' => SerializerType::SERIALIZE], + 'sponsoredMessages' => ['serializer' => SerializerType::SERIALIZE], + 'channelParticipants' => ['serializer' => SerializerType::SERIALIZE], + 'usernames' => ['serializer' => SerializerType::SERIALIZE], + 'session' => ['serializer' => SerializerType::SERIALIZE, 'enableCache' => false], ]; /** diff --git a/src/MTProtoTools/MinDatabase.php b/src/MTProtoTools/MinDatabase.php index cea40e39d..bbc2b237f 100644 --- a/src/MTProtoTools/MinDatabase.php +++ b/src/MTProtoTools/MinDatabase.php @@ -25,6 +25,7 @@ use danog\MadelineProto\Db\DbPropertiesTrait; use danog\MadelineProto\Exception; use danog\MadelineProto\Logger; use danog\MadelineProto\MTProto; +use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\TL\TLCallback; use Revolt\EventLoop; @@ -68,7 +69,7 @@ final class MinDatabase implements TLCallback * @see DbPropertiesFactory */ protected static array $dbProperties = [ - 'db' => [], + 'db' => ['serializer' => SerializerType::SERIALIZE], ]; public function __construct(MTProto $API) diff --git a/src/MTProtoTools/ReferenceDatabase.php b/src/MTProtoTools/ReferenceDatabase.php index 0cc27a9e3..ac6ababbd 100644 --- a/src/MTProtoTools/ReferenceDatabase.php +++ b/src/MTProtoTools/ReferenceDatabase.php @@ -26,6 +26,7 @@ use danog\MadelineProto\Exception; use danog\MadelineProto\Logger; use danog\MadelineProto\MTProto; use danog\MadelineProto\MTProto\OutgoingMessage; +use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\TL\TLCallback; use danog\MadelineProto\Tools; use Webmozart\Assert\Assert; @@ -87,7 +88,7 @@ final class ReferenceDatabase implements TLCallback * @see DbPropertiesFactory */ protected static array $dbProperties = [ - 'db' => [], + 'db' => ['serializer' => SerializerType::SERIALIZE], ]; public function __construct(private MTProto $API) diff --git a/src/Magic.php b/src/Magic.php index d72e52b8f..78998b285 100644 --- a/src/Magic.php +++ b/src/Magic.php @@ -82,6 +82,11 @@ final class Magic * */ public static bool $can_getcwd = false; + /** + * Whether we can use igbinary. + * + */ + public static bool $can_use_igbinary = false; /** * Whether we've processed forks. * @@ -224,6 +229,7 @@ final class Magic Shutdown::init(); \set_error_handler(Exception::exceptionErrorHandler(...)); \set_exception_handler(Exception::exceptionHandler(...)); + self::$can_use_igbinary = \function_exists('igbinary_serialize'); self::$isIpcWorker = \defined('MADELINE_WORKER_TYPE') ? MADELINE_WORKER_TYPE === 'madeline-ipc' : false; // Important, obtain root relative to caller script $backtrace = \debug_backtrace(0); diff --git a/src/Serialization.php b/src/Serialization.php index 574a2451f..bc651c8eb 100644 --- a/src/Serialization.php +++ b/src/Serialization.php @@ -51,11 +51,9 @@ abstract class Serialization /** * Header for session files. */ - const PHP_HEADER = ' SerializerType::SERIALIZE], $unserialized, ); } else { diff --git a/src/SessionPaths.php b/src/SessionPaths.php index 64878173a..8cbb3feda 100644 --- a/src/SessionPaths.php +++ b/src/SessionPaths.php @@ -124,10 +124,11 @@ final class SessionPaths Logger::log("Got exclusive lock of $path.lock..."); $object = Serialization::PHP_HEADER - .\chr(Serialization::VERSION) + .\chr(Serialization::VERSION_SERIALIZATION_AWARE) .\chr(PHP_MAJOR_VERSION) .\chr(PHP_MINOR_VERSION) - .\serialize($object); + .\chr(Magic::$can_use_igbinary ? 1 : 0) + .(Magic::$can_use_igbinary ? \igbinary_serialize($object) : \serialize($object)); write( "$path.temp.php", @@ -170,7 +171,7 @@ final class SessionPaths $file->seek($headerLen++); $v = \ord($file->read(null, 1)); - if ($v === Serialization::VERSION) { + if ($v >= Serialization::VERSION_OLD) { $php = $file->read(null, 2); $major = \ord($php[0]); $minor = \ord($php[1]); @@ -179,7 +180,16 @@ final class SessionPaths } $headerLen += 2; } - $unserialized = \unserialize($file->read(null, $size - $headerLen) ?? ''); + $igbinary = false; + if ($v >= Serialization::VERSION_SERIALIZATION_AWARE) { + $igbinary = (bool) \ord($file->read(null, 1)); + if ($igbinary && !Magic::$can_use_igbinary) { + throw Exception::extension('igbinary'); + } + $headerLen++; + } + $unserialized = $file->read(null, $size - $headerLen) ?? ''; + $unserialized = $igbinary ? \igbinary_unserialize($unserialized) : \unserialize($unserialized); $file->close(); } finally { $unlock(); diff --git a/src/Settings/Database/PersistentDatabaseAbstract.php b/src/Settings/Database/DriverDatabaseAbstract.php similarity index 92% rename from src/Settings/Database/PersistentDatabaseAbstract.php rename to src/Settings/Database/DriverDatabaseAbstract.php index ee847df2a..a441c4344 100644 --- a/src/Settings/Database/PersistentDatabaseAbstract.php +++ b/src/Settings/Database/DriverDatabaseAbstract.php @@ -4,12 +4,12 @@ declare(strict_types=1); namespace danog\MadelineProto\Settings\Database; -use danog\MadelineProto\Settings\DatabaseAbstract as SettingsDatabaseAbstract; +use danog\MadelineProto\Settings\DatabaseAbstract; /** * Base class for database backends. */ -abstract class PersistentDatabaseAbstract extends SettingsDatabaseAbstract +abstract class DriverDatabaseAbstract extends DatabaseAbstract { /** * For how long to keep records in memory after last read, for cached backends. @@ -21,7 +21,7 @@ abstract class PersistentDatabaseAbstract extends SettingsDatabaseAbstract protected string $password = ''; /** - * Which serializer strategy use by default + * Which serializer strategy to use by default. */ protected SerializerType $serializer = SerializerType::SERIALIZE; @@ -31,7 +31,6 @@ abstract class PersistentDatabaseAbstract extends SettingsDatabaseAbstract 'database', 'password', 'cache_ttl', - 'serializer', ]) as $object => $array) { if (isset($settings[$array])) { $this->{$object}($settings[$array]); @@ -111,7 +110,6 @@ abstract class PersistentDatabaseAbstract extends SettingsDatabaseAbstract */ abstract public function setUri(string $uri): self; - public function getSerializer(): SerializerType { return $this->serializer; diff --git a/src/Settings/Database/Redis.php b/src/Settings/Database/Redis.php index 2e5e31d96..4eff4be06 100644 --- a/src/Settings/Database/Redis.php +++ b/src/Settings/Database/Redis.php @@ -7,7 +7,7 @@ namespace danog\MadelineProto\Settings\Database; /** * Redis backend settings. */ -final class Redis extends PersistentDatabaseAbstract +final class Redis extends DriverDatabaseAbstract { /** * Database number. diff --git a/src/Settings/Database/SerializerType.php b/src/Settings/Database/SerializerType.php index e422397df..26cf9d67f 100644 --- a/src/Settings/Database/SerializerType.php +++ b/src/Settings/Database/SerializerType.php @@ -1,4 +1,4 @@ - Date: Tue, 2 May 2023 18:48:02 +0200 Subject: [PATCH 3/6] Update example --- examples/bot.php | 3 ++- src/Db/DbPropertiesFactory.php | 2 +- src/Db/DbPropertiesTrait.php | 3 +-- src/Db/Driver/Postgres.php | 14 -------------- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/examples/bot.php b/examples/bot.php index 3c78c5263..1839199f8 100755 --- a/examples/bot.php +++ b/examples/bot.php @@ -24,6 +24,7 @@ use danog\MadelineProto\Settings; use danog\MadelineProto\Settings\Database\Mysql; use danog\MadelineProto\Settings\Database\Postgres; use danog\MadelineProto\Settings\Database\Redis; +use danog\MadelineProto\Settings\Database\SerializerType; // If a stable version of MadelineProto was installed via composer, load composer autoloader if (file_exists('vendor/autoload.php')) { @@ -57,7 +58,7 @@ class MyEventHandler extends EventHandler * @see https://docs.madelineproto.xyz/docs/DATABASE.html */ protected static array $dbProperties = [ - 'dataStoredOnDb' => [], + 'dataStoredOnDb' => ['serializer' => SerializerType::SERIALIZE], ]; /** diff --git a/src/Db/DbPropertiesFactory.php b/src/Db/DbPropertiesFactory.php index e27c48615..3b383a427 100644 --- a/src/Db/DbPropertiesFactory.php +++ b/src/Db/DbPropertiesFactory.php @@ -14,7 +14,7 @@ use danog\MadelineProto\Settings\DatabaseAbstract; use InvalidArgumentException; /** - * @psalm-type TOrmConfig=array{serializer?: SerializerType, enableCache?: bool, cacheTtl?: int} + * @psalm-import-type TOrmConfig from DbPropertiesTrait * This factory class initializes the correct database backend for MadelineProto. */ abstract class DbPropertiesFactory diff --git a/src/Db/DbPropertiesTrait.php b/src/Db/DbPropertiesTrait.php index 1b0b3a590..640452140 100644 --- a/src/Db/DbPropertiesTrait.php +++ b/src/Db/DbPropertiesTrait.php @@ -15,8 +15,7 @@ use function Amp\Future\await; * * You will have to define a `$dbProperties` static array property, with a list of properties you want to store to a database. * - * @psalm-import-type TOrmConfig from DbPropertiesFactory - * + * @psalm-type TOrmConfig=array{serializer?: SerializerType, enableCache?: bool, cacheTtl?: int} * @property array $dbProperties */ trait DbPropertiesTrait diff --git a/src/Db/Driver/Postgres.php b/src/Db/Driver/Postgres.php index 4d9056f2b..a3616133e 100644 --- a/src/Db/Driver/Postgres.php +++ b/src/Db/Driver/Postgres.php @@ -53,20 +53,6 @@ final class Postgres ENCODING utf8 "); } - - $connection->query(" - CREATE OR REPLACE FUNCTION update_ts() - RETURNS TRIGGER AS $$ - BEGIN - IF row(NEW.*) IS DISTINCT FROM row(OLD.*) THEN - NEW.ts = now(); - RETURN NEW; - ELSE - RETURN OLD; - END IF; - END; - $$ language 'plpgsql' - "); $connection->close(); } catch (Throwable $e) { Logger::log($e->getMessage(), Logger::ERROR); From cbae5b35fd58483bdbbe528c3dcefdad7cdec7c1 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Tue, 2 May 2023 18:57:23 +0200 Subject: [PATCH 4/6] rm legacy --- src/Db/DbPropertiesFactory.php | 5 ++++- src/Db/DriverArray.php | 13 ------------- src/Db/MysqlArray.php | 3 --- src/Db/PostgresArray.php | 3 --- src/Db/RedisArray.php | 3 --- 5 files changed, 4 insertions(+), 23 deletions(-) diff --git a/src/Db/DbPropertiesFactory.php b/src/Db/DbPropertiesFactory.php index 3b383a427..8fcf33302 100644 --- a/src/Db/DbPropertiesFactory.php +++ b/src/Db/DbPropertiesFactory.php @@ -16,8 +16,10 @@ use InvalidArgumentException; /** * @psalm-import-type TOrmConfig from DbPropertiesTrait * This factory class initializes the correct database backend for MadelineProto. + * + * @internal */ -abstract class DbPropertiesFactory +final class DbPropertiesFactory { /** * @param TOrmConfig|'array' $config @@ -30,6 +32,7 @@ abstract class DbPropertiesFactory */ public static function get(DatabaseAbstract $dbSettings, string $table, string|array $config, ?DbType $value = null) { + // Legacy if ($config === 'array') { $config = []; } diff --git a/src/Db/DriverArray.php b/src/Db/DriverArray.php index 49abd3dae..a26291992 100644 --- a/src/Db/DriverArray.php +++ b/src/Db/DriverArray.php @@ -192,19 +192,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate return ['table', 'dbSettings']; } - public function __wakeup(): void - { - if (isset($this->settings) && \is_array($this->settings)) { - $clazz = (new ReflectionClass($this))->getProperty('dbSettings')->getType()->getName(); - /** - * @var SettingsAbstract - * @psalm-suppress UndefinedThisPropertyAssignment - */ - $this->dbSettings = new $clazz; - $this->dbSettings->mergeArray($this->settings); - unset($this->settings); - } - } final public function offsetExists($index): bool { return $this->isset($index); diff --git a/src/Db/MysqlArray.php b/src/Db/MysqlArray.php index 19669a87a..a99fd5d51 100644 --- a/src/Db/MysqlArray.php +++ b/src/Db/MysqlArray.php @@ -22,9 +22,6 @@ use PDO; */ class MysqlArray extends SqlArray { - // Legacy - protected array $settings; - /** * Initialize on startup. */ diff --git a/src/Db/PostgresArray.php b/src/Db/PostgresArray.php index 438a4fad8..027509319 100644 --- a/src/Db/PostgresArray.php +++ b/src/Db/PostgresArray.php @@ -23,9 +23,6 @@ use PDO; */ class PostgresArray extends SqlArray { - // Legacy - protected array $settings; - /** * Prepare statements. * diff --git a/src/Db/RedisArray.php b/src/Db/RedisArray.php index c4b102c14..597dec605 100644 --- a/src/Db/RedisArray.php +++ b/src/Db/RedisArray.php @@ -23,9 +23,6 @@ class RedisArray extends DriverArray { private RedisRedis $db; - // Legacy - protected array $settings; - /** * Initialize on startup. */ From fef3bf932a001bda75195396bbf5aa0b8f5c2816 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Tue, 2 May 2023 19:14:03 +0200 Subject: [PATCH 5/6] Renaming --- src/Db/DriverArray.php | 9 ++++----- src/Db/MysqlArray.php | 2 +- src/Db/PostgresArray.php | 2 +- src/Db/RedisArray.php | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Db/DriverArray.php b/src/Db/DriverArray.php index a26291992..08c342aab 100644 --- a/src/Db/DriverArray.php +++ b/src/Db/DriverArray.php @@ -51,7 +51,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate /** * Rename table. */ - abstract protected function renameTable(string $from, string $to): void; + abstract protected function moveDataFromTableToTable(string $from, string $to): void; /** * Get the value of table. @@ -125,9 +125,8 @@ abstract class DriverArray implements DbArray, IteratorAggregate } /** - * Rename table of old database, if the new one is not a temporary table name. - * - * Otherwise, simply change name of table in new database to match old table name. + * If the new db has a temporary table name, change its table name to match the old table name. + * Otherwise rename table of old database. * * @param self $new New db * @param DbArray|array|null $old Old db @@ -138,7 +137,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate if ($old->getTable() !== $new->getTable() && !\str_starts_with($new->getTable(), 'tmp') ) { - $new->renameTable($old->getTable(), $new->getTable()); + $new->moveDataFromTableToTable($old->getTable(), $new->getTable()); } else { $new->setTable($old->getTable()); } diff --git a/src/Db/MysqlArray.php b/src/Db/MysqlArray.php index a99fd5d51..1081574d9 100644 --- a/src/Db/MysqlArray.php +++ b/src/Db/MysqlArray.php @@ -103,7 +103,7 @@ class MysqlArray extends SqlArray "); } - protected function renameTable(string $from, string $to): void + protected function moveDataFromTableToTable(string $from, string $to): void { Logger::log("Moving data from {$from} to {$to}", Logger::WARNING); diff --git a/src/Db/PostgresArray.php b/src/Db/PostgresArray.php index 027509319..9fc5cc22f 100644 --- a/src/Db/PostgresArray.php +++ b/src/Db/PostgresArray.php @@ -118,7 +118,7 @@ class PostgresArray extends SqlArray "); } - protected function renameTable(string $from, string $to): void + protected function moveDataFromTableToTable(string $from, string $to): void { Logger::log("Moving data from {$from} to {$to}", Logger::WARNING); diff --git a/src/Db/RedisArray.php b/src/Db/RedisArray.php index 597dec605..b151d5f06 100644 --- a/src/Db/RedisArray.php +++ b/src/Db/RedisArray.php @@ -34,7 +34,7 @@ class RedisArray extends DriverArray { } - protected function renameTable(string $from, string $to): void + protected function moveDataFromTableToTable(string $from, string $to): void { Logger::log("Moving data from {$from} to {$to}", Logger::WARNING); $from = "va:$from"; From 17db61ae958bd42cec757ef18ad6a620867ce4eb Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sat, 6 May 2023 20:35:03 +0200 Subject: [PATCH 6/6] Fixup types --- examples/bot.php | 4 ++++ src/AnnotationsBuilder.php | 4 ++++ src/Db/DbPropertiesFactory.php | 3 +-- src/Db/DriverArray.php | 2 -- src/MTProto.php | 2 +- src/Namespace/Messages.php | 22 +++++++++++----------- src/Namespace/Payments.php | 4 ++-- 7 files changed, 23 insertions(+), 18 deletions(-) diff --git a/examples/bot.php b/examples/bot.php index 1839199f8..093c18b8e 100755 --- a/examples/bot.php +++ b/examples/bot.php @@ -95,6 +95,10 @@ class MyEventHandler extends EventHandler peer: self::ADMIN, message: "The bot was started!" ); + $this->messages->sendMedia( + peer: self::ADMIN, + media: 'BQACAgQAAxkDAAJbamRWnR-HEzE5AZi8rCd7u4QBVqkIAALkDQACkgABuVIjSOHLj_v1WC8E' + ); } /** * Handle updates from supergroups and channels. diff --git a/src/AnnotationsBuilder.php b/src/AnnotationsBuilder.php index 415814196..56b5d5916 100644 --- a/src/AnnotationsBuilder.php +++ b/src/AnnotationsBuilder.php @@ -110,6 +110,7 @@ final class Blacklist { 'Bool' => 'bool', 'true' => 'bool', 'InputMessage' => 'array|int', + 'InputMedia' => 'array|string', 'InputCheckPasswordSRP' => 'string|array', 'DataJSON' => 'mixed', 'JSONValue' => 'mixed', @@ -190,6 +191,9 @@ final class Blacklist { if ($type === 'InputMessage') { $base = "int|$base"; } + if ($type === 'InputMedia') { + $base = "string|$base"; + } if ($isVector) { $base = "list<$base>"; } diff --git a/src/Db/DbPropertiesFactory.php b/src/Db/DbPropertiesFactory.php index 8fcf33302..8497b7e49 100644 --- a/src/Db/DbPropertiesFactory.php +++ b/src/Db/DbPropertiesFactory.php @@ -9,14 +9,13 @@ use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\Database\Mysql; use danog\MadelineProto\Settings\Database\Postgres; use danog\MadelineProto\Settings\Database\Redis; -use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\DatabaseAbstract; use InvalidArgumentException; /** * @psalm-import-type TOrmConfig from DbPropertiesTrait * This factory class initializes the correct database backend for MadelineProto. - * + * * @internal */ final class DbPropertiesFactory diff --git a/src/Db/DriverArray.php b/src/Db/DriverArray.php index 08c342aab..06612be05 100644 --- a/src/Db/DriverArray.php +++ b/src/Db/DriverArray.php @@ -9,9 +9,7 @@ use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract; use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\DatabaseAbstract; -use danog\MadelineProto\SettingsAbstract; use IteratorAggregate; -use ReflectionClass; use function Amp\async; use function Amp\Future\await; diff --git a/src/MTProto.php b/src/MTProto.php index fabfdf60b..b4711e887 100644 --- a/src/MTProto.php +++ b/src/MTProto.php @@ -139,7 +139,7 @@ final class MTProto implements TLCallback, LoggerGetter * * @var string */ - const RELEASE = '7.0'; + const RELEASE = '8.0'; /** * We're not logged in. * diff --git a/src/Namespace/Messages.php b/src/Namespace/Messages.php index da7443cda..764749318 100644 --- a/src/Namespace/Messages.php +++ b/src/Namespace/Messages.php @@ -115,7 +115,7 @@ interface Messages * Send a media. * * @param array|int|string $peer Destination @see https://docs.madelineproto.xyz/API_docs/types/InputPeer.html - * @param array $media Attached media @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html + * @param string|array $media Attached media @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html * @param bool $silent Send message silently (no notification should be triggered) * @param bool $background Send message in background * @param bool $clear_draft Clear the draft @@ -129,7 +129,7 @@ interface Messages * @param array|int|string $send_as Send this message as the specified peer @see https://docs.madelineproto.xyz/API_docs/types/InputPeer.html * @return array @see https://docs.madelineproto.xyz/API_docs/types/Updates.html */ - public function sendMedia(array|int|string $peer, array $media, bool $silent = false, bool $background = false, bool $clear_draft = false, bool $noforwards = false, bool $update_stickersets_order = false, int $reply_to_msg_id = 0, int $top_msg_id = 0, string $message = '', array $reply_markup = [], array $entities = [], string $parse_mode = '', int $schedule_date = 0, array|int|string $send_as = []): array; + public function sendMedia(array|int|string $peer, array|string $media, bool $silent = false, bool $background = false, bool $clear_draft = false, bool $noforwards = false, bool $update_stickersets_order = false, int $reply_to_msg_id = 0, int $top_msg_id = 0, string $message = '', array $reply_markup = [], array $entities = [], string $parse_mode = '', int $schedule_date = 0, array|int|string $send_as = []): array; /** * Forwards messages by their IDs. @@ -517,14 +517,14 @@ interface Messages * @param bool $no_webpage Disable webpage preview * @param int $id ID of the message to edit * @param string $message New message - * @param array|array $media New attached media @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html + * @param string|array $media New attached media @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html * @param array|array $reply_markup Reply markup for inline keyboards @see https://docs.madelineproto.xyz/API_docs/types/ReplyMarkup.html * @param list|array $entities Array of [Message entities for styled text](https://core.telegram.org/api/entities) @see https://docs.madelineproto.xyz/API_docs/types/MessageEntity.html * @param ''|'HTML'|'html'|'Markdown'|'markdown' $parse_mode Whether to parse HTML or Markdown markup in the message * @param int $schedule_date Scheduled message date for [scheduled messages](https://core.telegram.org/api/scheduled-messages) * @return array @see https://docs.madelineproto.xyz/API_docs/types/Updates.html */ - public function editMessage(array|int|string $peer, bool $no_webpage = false, int $id = 0, string $message = '', array $media = [], array $reply_markup = [], array $entities = [], string $parse_mode = '', int $schedule_date = 0): array; + public function editMessage(array|int|string $peer, bool $no_webpage = false, int $id = 0, string $message = '', array|string $media = [], array $reply_markup = [], array $entities = [], string $parse_mode = '', int $schedule_date = 0): array; /** * Edit an inline bot message. @@ -532,12 +532,12 @@ interface Messages * @param array{_: 'inputBotInlineMessageID', dc_id?: int, id?: int, access_hash?: int}|array{_: 'inputBotInlineMessageID64', dc_id?: int, owner_id?: int, id?: int, access_hash?: int} $id Sent inline message ID @see https://docs.madelineproto.xyz/API_docs/types/InputBotInlineMessageID.html * @param bool $no_webpage Disable webpage preview * @param string $message Message - * @param array|array $media Media @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html + * @param string|array $media Media @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html * @param array|array $reply_markup Reply markup for inline keyboards @see https://docs.madelineproto.xyz/API_docs/types/ReplyMarkup.html * @param list|array $entities Array of [Message entities for styled text](https://core.telegram.org/api/entities) @see https://docs.madelineproto.xyz/API_docs/types/MessageEntity.html * @param ''|'HTML'|'html'|'Markdown'|'markdown' $parse_mode Whether to parse HTML or Markdown markup in the message */ - public function editInlineBotMessage(array $id, bool $no_webpage = false, string $message = '', array $media = [], array $reply_markup = [], array $entities = [], string $parse_mode = ''): bool; + public function editInlineBotMessage(array $id, bool $no_webpage = false, string $message = '', array|string $media = [], array $reply_markup = [], array $entities = [], string $parse_mode = ''): bool; /** * Press an inline callback button and get a callback answer from the bot. @@ -767,10 +767,10 @@ interface Messages * Upload a file and associate it to a chat (without actually sending it to the chat). * * @param array|int|string $peer The chat, can be [inputPeerEmpty](https://docs.madelineproto.xyz/API_docs/constructors/inputPeerEmpty.html) for bots and [inputPeerSelf](https://docs.madelineproto.xyz/API_docs/constructors/inputPeerSelf.html) for users. @see https://docs.madelineproto.xyz/API_docs/types/InputPeer.html - * @param array $media File uploaded in chunks as described in [files »](https://core.telegram.org/api/files) @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html + * @param string|array $media File uploaded in chunks as described in [files »](https://core.telegram.org/api/files) @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html * @return array{_: 'messageMediaEmpty'}|array{_: 'messageMediaPhoto', spoiler: bool, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, ttl_seconds: int}|array{_: 'messageMediaGeo', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}}|array{_: 'messageMediaContact', phone_number: string, first_name: string, last_name: string, vcard: string, user_id: int}|array{_: 'messageMediaUnsupported'}|array{_: 'messageMediaDocument', nopremium: bool, spoiler: bool, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, ttl_seconds: int}|array{_: 'messageMediaWebPage', webpage: array{_: 'webPageEmpty', id: array}|array{_: 'webPagePending', id: array, date: array}|array{_: 'webPage', id: array, url: array, display_url: array, hash: array, type: array, site_name: array, title: array, description: array, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, embed_url: array, embed_type: array, embed_width: array, embed_height: array, duration: array, author: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, cached_page?: array, attributes: list}|array{_: 'webPageNotModified', cached_page_views: array}}|array{_: 'messageMediaVenue', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, title: string, address: string, provider: string, venue_id: string, venue_type: string}|array{_: 'messageMediaGame', game: array{_: 'game', photo: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, id: array, access_hash: array, short_name: array, title: array, description: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}}}|array{_: 'messageMediaInvoice', shipping_address_requested: bool, test: bool, title: string, description: string, photo?: array{_: 'webDocument', url: array, access_hash: array, size: array, mime_type: array, attributes: list}|array{_: 'webDocumentNoProxy', url: array, size: array, mime_type: array, attributes: list}, receipt_msg_id: int, currency: string, total_amount: int, start_param: string, extended_media?: array{_: 'messageExtendedMediaPreview', w: array, h: array, thumb?: array, video_duration: array}|array{_: 'messageExtendedMedia', media: array{_: 'messageMediaEmpty'}|array{_: 'messageMediaPhoto', spoiler: bool, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, ttl_seconds: int}|array{_: 'messageMediaGeo', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}}|array{_: 'messageMediaContact', phone_number: string, first_name: string, last_name: string, vcard: string, user_id: int}|array{_: 'messageMediaUnsupported'}|array{_: 'messageMediaDocument', nopremium: bool, spoiler: bool, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, ttl_seconds: int}|array{_: 'messageMediaWebPage', webpage: array{_: 'webPageEmpty', id: array}|array{_: 'webPagePending', id: array, date: array}|array{_: 'webPage', id: array, url: array, display_url: array, hash: array, type: array, site_name: array, title: array, description: array, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, embed_url: array, embed_type: array, embed_width: array, embed_height: array, duration: array, author: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, cached_page?: array, attributes: list}|array{_: 'webPageNotModified', cached_page_views: array}}|array{_: 'messageMediaVenue', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, title: string, address: string, provider: string, venue_id: string, venue_type: string}|array{_: 'messageMediaGame', game: array{_: 'game', photo: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, id: array, access_hash: array, short_name: array, title: array, description: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}}}|array{_: 'messageMediaGeoLive', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, heading: int, period: int, proximity_notification_radius: int}|array{_: 'messageMediaPoll', poll: array{_: 'poll', id: array, closed: array, public_voters: array, multiple_choice: array, quiz: array, question: array, answers: list, close_period: array, close_date: array}, results: array{_: 'pollResults', min: array, results: list, total_voters: array, recent_voters: list, solution: array, solution_entities: list}}|array{_: 'messageMediaDice', value: int, emoticon: string}}}|array{_: 'messageMediaGeoLive', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, heading: int, period: int, proximity_notification_radius: int}|array{_: 'messageMediaPoll', poll: array{_: 'poll', id: array, closed: array, public_voters: array, multiple_choice: array, quiz: array, question: array, answers: list, close_period: array, close_date: array}, results: array{_: 'pollResults', min: array, results: list, total_voters: array, recent_voters: list, solution: array, solution_entities: list}}|array{_: 'messageMediaDice', value: int, emoticon: string} @see https://docs.madelineproto.xyz/API_docs/types/MessageMedia.html */ - public function uploadMedia(array|int|string $peer, array $media): array; + public function uploadMedia(array|int|string $peer, array|string $media): array; /** * Notify the other user in a private chat that a screenshot of the chat was taken. @@ -837,7 +837,7 @@ interface Messages * @param bool $clear_draft Whether to clear [drafts](https://core.telegram.org/api/drafts) * @param bool $noforwards Only for bots, disallows forwarding and saving of the messages, even if the destination chat doesn't have [content protection](https://telegram.org/blog/protected-content-delete-by-date-and-more) enabled * @param int $reply_to_msg_id The message to reply to - * @param list}>|array $multi_media Array of The medias to send @see https://docs.madelineproto.xyz/API_docs/types/InputSingleMedia.html + * @param list}>|array $multi_media Array of The medias to send @see https://docs.madelineproto.xyz/API_docs/types/InputSingleMedia.html * @param int $schedule_date Scheduled message date for scheduled messages * @param array|int|string $send_as Send this message as the specified peer @see https://docs.madelineproto.xyz/API_docs/types/InputPeer.html * @return array @see https://docs.madelineproto.xyz/API_docs/types/Updates.html @@ -1195,12 +1195,12 @@ interface Messages * Upload a media file associated with an [imported chat, click here for more info »](https://core.telegram.org/api/import). * * @param array|int|string $peer The Telegram chat where the media will be imported @see https://docs.madelineproto.xyz/API_docs/types/InputPeer.html - * @param array $media Media metadata @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html + * @param string|array $media Media metadata @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html * @param int $import_id Identifier of a [history import session](https://core.telegram.org/api/import), returned by [messages.initHistoryImport](https://docs.madelineproto.xyz/API_docs/methods/messages.initHistoryImport.html) * @param string $file_name File name * @return array{_: 'messageMediaEmpty'}|array{_: 'messageMediaPhoto', spoiler: bool, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, ttl_seconds: int}|array{_: 'messageMediaGeo', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}}|array{_: 'messageMediaContact', phone_number: string, first_name: string, last_name: string, vcard: string, user_id: int}|array{_: 'messageMediaUnsupported'}|array{_: 'messageMediaDocument', nopremium: bool, spoiler: bool, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, ttl_seconds: int}|array{_: 'messageMediaWebPage', webpage: array{_: 'webPageEmpty', id: array}|array{_: 'webPagePending', id: array, date: array}|array{_: 'webPage', id: array, url: array, display_url: array, hash: array, type: array, site_name: array, title: array, description: array, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, embed_url: array, embed_type: array, embed_width: array, embed_height: array, duration: array, author: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, cached_page?: array, attributes: list}|array{_: 'webPageNotModified', cached_page_views: array}}|array{_: 'messageMediaVenue', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, title: string, address: string, provider: string, venue_id: string, venue_type: string}|array{_: 'messageMediaGame', game: array{_: 'game', photo: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, id: array, access_hash: array, short_name: array, title: array, description: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}}}|array{_: 'messageMediaInvoice', shipping_address_requested: bool, test: bool, title: string, description: string, photo?: array{_: 'webDocument', url: array, access_hash: array, size: array, mime_type: array, attributes: list}|array{_: 'webDocumentNoProxy', url: array, size: array, mime_type: array, attributes: list}, receipt_msg_id: int, currency: string, total_amount: int, start_param: string, extended_media?: array{_: 'messageExtendedMediaPreview', w: array, h: array, thumb?: array, video_duration: array}|array{_: 'messageExtendedMedia', media: array{_: 'messageMediaEmpty'}|array{_: 'messageMediaPhoto', spoiler: bool, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, ttl_seconds: int}|array{_: 'messageMediaGeo', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}}|array{_: 'messageMediaContact', phone_number: string, first_name: string, last_name: string, vcard: string, user_id: int}|array{_: 'messageMediaUnsupported'}|array{_: 'messageMediaDocument', nopremium: bool, spoiler: bool, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, ttl_seconds: int}|array{_: 'messageMediaWebPage', webpage: array{_: 'webPageEmpty', id: array}|array{_: 'webPagePending', id: array, date: array}|array{_: 'webPage', id: array, url: array, display_url: array, hash: array, type: array, site_name: array, title: array, description: array, photo?: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, embed_url: array, embed_type: array, embed_width: array, embed_height: array, duration: array, author: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}, cached_page?: array, attributes: list}|array{_: 'webPageNotModified', cached_page_views: array}}|array{_: 'messageMediaVenue', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, title: string, address: string, provider: string, venue_id: string, venue_type: string}|array{_: 'messageMediaGame', game: array{_: 'game', photo: array{_: 'photoEmpty', id: array}|array{_: 'photo', has_stickers: array, id: array, access_hash: array, file_reference: array, date: array, sizes: list, video_sizes: list, dc_id: array}, id: array, access_hash: array, short_name: array, title: array, description: array, document?: array{_: 'documentEmpty', id: array}|array{_: 'document', id: array, access_hash: array, file_reference: array, date: array, mime_type: array, size: array, thumbs: list, video_thumbs: list, dc_id: array, attributes: list}}}|array{_: 'messageMediaGeoLive', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, heading: int, period: int, proximity_notification_radius: int}|array{_: 'messageMediaPoll', poll: array{_: 'poll', id: array, closed: array, public_voters: array, multiple_choice: array, quiz: array, question: array, answers: list, close_period: array, close_date: array}, results: array{_: 'pollResults', min: array, results: list, total_voters: array, recent_voters: list, solution: array, solution_entities: list}}|array{_: 'messageMediaDice', value: int, emoticon: string}}}|array{_: 'messageMediaGeoLive', geo: array{_: 'geoPointEmpty'}|array{_: 'geoPoint', long: array, lat: array, access_hash: array, accuracy_radius: array}, heading: int, period: int, proximity_notification_radius: int}|array{_: 'messageMediaPoll', poll: array{_: 'poll', id: array, closed: array, public_voters: array, multiple_choice: array, quiz: array, question: array, answers: list, close_period: array, close_date: array}, results: array{_: 'pollResults', min: array, results: list, total_voters: array, recent_voters: list, solution: array, solution_entities: list}}|array{_: 'messageMediaDice', value: int, emoticon: string} @see https://docs.madelineproto.xyz/API_docs/types/MessageMedia.html */ - public function uploadImportedMedia(array|int|string $peer, array $media, int $import_id = 0, string $file_name = ''): array; + public function uploadImportedMedia(array|int|string $peer, array|string $media, int $import_id = 0, string $file_name = ''): array; /** * Complete the [history import process](https://core.telegram.org/api/import), importing all messages into the chat. diff --git a/src/Namespace/Payments.php b/src/Namespace/Payments.php index 5e8fb02e1..c9f5d0465 100644 --- a/src/Namespace/Payments.php +++ b/src/Namespace/Payments.php @@ -76,10 +76,10 @@ interface Payments /** * Generate an [invoice deep link](https://core.telegram.org/api/links#invoice-links). * - * @param array $invoice_media Invoice @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html + * @param string|array $invoice_media Invoice @see https://docs.madelineproto.xyz/API_docs/types/InputMedia.html * @return array{_: 'payments.exportedInvoice', url: string} @see https://docs.madelineproto.xyz/API_docs/types/payments.ExportedInvoice.html */ - public function exportInvoice(array $invoice_media): array; + public function exportInvoice(array|string $invoice_media): array; /** * Informs server about a purchase made through the App Store: for official applications only.