first commit

This commit is contained in:
Mr.Qin
2022-08-19 19:48:37 +08:00
commit afdd648b65
3275 changed files with 631084 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
use Yansongda\Supports\Str;
trait Accessable
{
/**
* __get.
*
* @return mixed
*/
public function __get(string $key)
{
return $this->get($key);
}
/**
* __set.
*
* @param mixed $value
*/
public function __set(string $key, $value): void
{
$this->set($key, $value);
}
/**
* get.
*
* @param mixed $default
*
* @return mixed
*/
public function get(?string $key = null, $default = null)
{
if (is_null($key)) {
return method_exists($this, 'toArray') ? $this->toArray() : $default;
}
$method = 'get'.Str::studly($key);
if (method_exists($this, $method)) {
return $this->{$method}();
}
return $default;
}
/**
* set.
*
* @param mixed $value
*/
public function set(string $key, $value): self
{
$method = 'set'.Str::studly($key);
if (method_exists($this, $method)) {
$this->{$method}($value);
}
return $this;
}
/**
* Whether a offset exists.
*
* @see https://php.net/manual/en/arrayaccess.offsetexists.php
*
* @param mixed $offset an offset to check for
*
* @return bool true on success or false on failure.
*
* The return value will be casted to boolean if non-boolean was returned.
*/
public function offsetExists($offset)
{
return !is_null($this->get($offset));
}
/**
* Offset to retrieve.
*
* @see https://php.net/manual/en/arrayaccess.offsetget.php
*
* @param mixed $offset the offset to retrieve
*
* @return mixed can return all value types
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* Offset to set.
*
* @see https://php.net/manual/en/arrayaccess.offsetset.php
*
* @param mixed $offset the offset to assign the value to
* @param mixed $value the value to set
*
* @return void
*/
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
/**
* Offset to unset.
*
* @see https://php.net/manual/en/arrayaccess.offsetunset.php
*
* @param mixed $offset the offset to unset
*
* @return void
*/
public function offsetUnset($offset)
{
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
use ReflectionClass;
use Yansongda\Supports\Str;
trait Arrayable
{
/**
* toArray.
*/
public function toArray(): array
{
$result = [];
foreach ((new ReflectionClass($this))->getProperties() as $item) {
$k = $item->getName();
$method = 'get'.Str::studly($k);
$result[Str::snake($k)] = method_exists($this, $method) ? $this->{$method}() : $this->{$k};
}
return $result;
}
}

View File

@@ -0,0 +1,207 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
/**
* Trait HasHttpRequest.
*
* @property string $baseUri
* @property float $timeout
* @property float $connectTimeout
*/
trait HasHttpRequest
{
/**
* Http client.
*
* @var Client|null
*/
protected $httpClient = null;
/**
* Http client options.
*
* @var array
*/
protected $httpOptions = [];
/**
* Send a GET request.
*
* @return array|string
*/
public function get(string $endpoint, array $query = [], array $headers = [])
{
return $this->request('get', $endpoint, [
'headers' => $headers,
'query' => $query,
]);
}
/**
* Send a POST request.
*
* @param string|array $data
*
* @return array|string
*/
public function post(string $endpoint, $data, array $options = [])
{
if (!is_array($data)) {
$options['body'] = $data;
} else {
$options['form_params'] = $data;
}
return $this->request('post', $endpoint, $options);
}
/**
* Send request.
*
* @return array|string
*/
public function request(string $method, string $endpoint, array $options = [])
{
return $this->unwrapResponse($this->getHttpClient()->{$method}($endpoint, $options));
}
/**
* Set http client.
*/
public function setHttpClient(Client $client): self
{
$this->httpClient = $client;
return $this;
}
/**
* Return http client.
*/
public function getHttpClient(): Client
{
if (is_null($this->httpClient)) {
$this->httpClient = $this->getDefaultHttpClient();
}
return $this->httpClient;
}
/**
* Get default http client.
*/
public function getDefaultHttpClient(): Client
{
return new Client($this->getOptions());
}
/**
* setBaseUri.
*/
public function setBaseUri(string $url): self
{
if (property_exists($this, 'baseUri')) {
$parsedUrl = parse_url($url);
$this->baseUri = ($parsedUrl['scheme'] ?? 'http').'://'.
$parsedUrl['host'].(isset($parsedUrl['port']) ? (':'.$parsedUrl['port']) : '');
}
return $this;
}
/**
* getBaseUri.
*/
public function getBaseUri(): string
{
return property_exists($this, 'baseUri') ? $this->baseUri : '';
}
public function getTimeout(): float
{
return property_exists($this, 'timeout') ? $this->timeout : 5.0;
}
public function setTimeout(float $timeout): self
{
if (property_exists($this, 'timeout')) {
$this->timeout = $timeout;
}
return $this;
}
public function getConnectTimeout(): float
{
return property_exists($this, 'connectTimeout') ? $this->connectTimeout : 3.0;
}
public function setConnectTimeout(float $connectTimeout): self
{
if (property_exists($this, 'connectTimeout')) {
$this->connectTimeout = $connectTimeout;
}
return $this;
}
/**
* Get default options.
*/
public function getOptions(): array
{
return array_merge([
'base_uri' => $this->getBaseUri(),
'timeout' => $this->getTimeout(),
'connect_timeout' => $this->getConnectTimeout(),
], $this->getHttpOptions());
}
/**
* setOptions.
*
* @return $this
*/
public function setOptions(array $options): self
{
return $this->setHttpOptions($options);
}
public function getHttpOptions(): array
{
return $this->httpOptions;
}
public function setHttpOptions(array $httpOptions): self
{
$this->httpOptions = $httpOptions;
return $this;
}
/**
* Convert response.
*
* @return array|string
*/
public function unwrapResponse(ResponseInterface $response)
{
$contentType = $response->getHeaderLine('Content-Type');
$contents = $response->getBody()->getContents();
if (false !== stripos($contentType, 'json') || stripos($contentType, 'javascript')) {
return json_decode($contents, true);
} elseif (false !== stripos($contentType, 'xml')) {
return json_decode(json_encode(simplexml_load_string($contents, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
}
return $contents;
}
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
use RuntimeException;
trait Serializable
{
/**
* toJson.
*/
public function toJson(): string
{
return $this->serialize();
}
/**
* Specify data which should be serialized to JSON.
*
* @see https://php.net/manual/en/jsonserializable.jsonserialize.php
*
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource
*
* @since 5.4.0
*/
public function jsonSerialize()
{
if (method_exists($this, 'toArray')) {
return $this->toArray();
}
return [];
}
/**
* String representation of object.
*
* @see https://php.net/manual/en/serializable.serialize.php
*
* @return string the string representation of the object or null
*
* @since 5.1.0
*/
public function serialize()
{
if (method_exists($this, 'toArray')) {
return json_encode($this->toArray());
}
return json_encode([]);
}
/**
* Constructs the object.
*
* @see https://php.net/manual/en/serializable.unserialize.php
*
* @param string $serialized <p>
* The string representation of the object.
* </p>
*
* @since 5.1.0
*/
public function unserialize($serialized)
{
$data = json_decode($serialized, true);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new RuntimeException('Invalid Json Format');
}
$this->unserializeArray($data);
}
public function unserializeArray(array $data): void
{
foreach ($data as $key => $item) {
if (method_exists($this, 'set')) {
$this->set($key, $item);
}
}
}
}

View File

@@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
namespace Yansongda\Supports\Traits;
/**
* Trait ShouldThrottle.
*
* @property \Redis $redis
*/
trait ShouldThrottle
{
/**
* @var array
*/
protected $throttle = [
'limit' => 60,
'period' => 60,
'count' => 0,
'reset_time' => 0,
];
/**
* isThrottled.
*/
public function isThrottled(string $key, int $limit = 60, int $period = 60, bool $autoAdd = false): bool
{
if (-1 === $limit) {
return false;
}
$now = microtime(true) * 1000;
$this->redis->zRemRangeByScore($key, 0, $now - $period * 1000);
$this->throttle = [
'limit' => $limit,
'period' => $period,
'count' => $this->getThrottleCounts($key, $period),
'reset_time' => $this->getThrottleResetTime($key, $now),
];
if ($this->throttle['count'] < $limit) {
if ($autoAdd) {
$this->throttleAdd($key, $period);
}
return false;
}
return true;
}
/**
* 限流 + 1.
*/
public function throttleAdd(string $key, int $period = 60): void
{
$now = microtime(true) * 1000;
$this->redis->zAdd($key, $now, $now);
$this->redis->expire($key, $period * 2);
}
/**
* 获取下次重置时间.
*
* @param float $now 现在的毫秒时间
*/
public function getThrottleResetTime(string $key, float $now): int
{
$data = $this->redis->zRangeByScore(
$key,
$now - $this->throttle['period'] * 1000,
$now,
['limit' => [0, 1]]
);
if (0 === count($data)) {
return $this->throttle['reset_time'] = time() + $this->throttle['period'];
}
return intval(reset($data) / 1000) + $this->throttle['period'];
}
/**
* 获取限流相关信息.
*
* @param mixed $default
*
* @return mixed
*/
public function getThrottleInfo(?string $key = null, $default = null)
{
if (is_null($key)) {
return $this->throttle;
}
if (isset($this->throttle[$key])) {
return $this->throttle[$key];
}
return $default;
}
/**
* 获取已使用次数.
*/
public function getThrottleCounts(string $key, int $period = 60): int
{
$now = microtime(true) * 1000;
return $this->redis->zCount($key, $now - $period * 1000, $now);
}
}