Skip to content

Commit ccce34a

Browse files
author
liutao
committed
add Str::class
1 parent e5c39c7 commit ccce34a

4 files changed

Lines changed: 71 additions & 27 deletions

File tree

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
}
88
},
99
"require": {
10-
"symfony/string": "*",
1110
"php": ">=8.0"
1211
},
1312
"require-dev": {

src/Data.php

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,20 @@
1010
use Ltaooo\Data\Attribute\DataAttribute;
1111
use Ltaooo\Data\Contract\ArrayAble;
1212
use Ltaooo\Data\Traits\ArrayAccessTrait;
13+
use Ltaooo\Data\Util\Str;
1314
use ReflectionClass;
1415
use ReflectionProperty;
15-
use function Symfony\Component\String\u;
1616

1717
class Data implements ArrayAble, ArrayAccess, JsonSerializable
1818
{
1919
use ArrayAccessTrait;
20-
protected ?ReflectionClass $_staticReflection = null;
2120

22-
protected array $_strCache = [];
21+
protected ?ReflectionClass $_staticReflection = null;
2322

23+
/**
24+
* @param array|ArrayAble $data
25+
* @throws
26+
*/
2427
public function __construct(array|Arrayable $data = [])
2528
{
2629
$this->fill($data instanceof Arrayable ? $data->toArray() : $data);
@@ -66,8 +69,8 @@ public function fill(array $data): static
6669
}
6770
foreach ($this->getStaticReflection()->getProperties() as $property) {
6871
$propertyName = $property->getName();
69-
$camelCasePropertyName = $this->strCamel($propertyName);
70-
$snakePropertyName = $this->strSnake($propertyName);
72+
$camelCasePropertyName = Str::camel($propertyName);
73+
$snakePropertyName = Str::snake($propertyName);
7174
if (
7275
!array_key_exists($camelCasePropertyName, $data)
7376
&& !array_key_exists($snakePropertyName, $data)
@@ -117,7 +120,7 @@ protected function propertyToArray(object $object, bool $toSnake, ReflectionProp
117120
if ($this->isInsideProperty($property)) {
118121
continue;
119122
}
120-
$name = $toSnake ? $this->strSnake($property->getName()) : $property->getName();
123+
$name = $toSnake ? Str::snake($property->getName()) : $property->getName();
121124
$result[$name] = $this->forValue($property->getValue($object), $toSnake);
122125
}
123126
return $result;
@@ -156,28 +159,9 @@ protected function getStaticReflection(): ReflectionClass
156159
return $this->_staticReflection ?? $this->getReflectionClass($this);
157160
}
158161

159-
protected function strCamel(string $str)
160-
{
161-
if (isset($this->_strCache['camel'][$str])) {
162-
return $this->_strCache['camel'][$str];
163-
}
164-
return $this->_strCache['camel'][$str] = u($str)->camel()->toString();
165-
}
166-
167-
protected function strSnake(string $str)
168-
{
169-
if (isset($this->_strCache['snake'][$str])) {
170-
return $this->_strCache['snake'][$str];
171-
}
172-
return $this->_strCache['snake'][$str] = u($str)->snake()->toString();
173-
}
174-
175162
protected function isInsideProperty(ReflectionProperty $property): bool
176163
{
177-
if (isset($this->_strCache['inside'][$property->getName()])) {
178-
return $this->_strCache['inside'][$property->getName()];
179-
}
180-
return $this->_strCache['inside'][$property->getName()] = u($property->getName())->startsWith('_');
164+
return Str::startsWith($property->getName(), '_');
181165
}
182166

183167
}

src/Util/Str.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Ltaooo\Data\Util;
5+
6+
7+
class Str
8+
{
9+
private static array $_strCache = [];
10+
11+
public static function camel(string $str): string
12+
{
13+
if (isset(static::$_strCache['camel'][$str])) {
14+
return static::$_strCache['camel'][$str];
15+
}
16+
return static::$_strCache['camel'][$str] = lcfirst(static::studly($str));
17+
}
18+
19+
public static function snake(string $str, string $delimiter = '_'): string
20+
{
21+
if (isset(static::$_strCache['snake'][$str])) {
22+
return static::$_strCache['snake'][$str];
23+
}
24+
if (!ctype_lower($str)) {
25+
$str = preg_replace('/\s+/u', '', ucwords($str));
26+
27+
$str = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $str));
28+
}
29+
30+
return static::$_strCache['snake'][$str] = $str;
31+
}
32+
33+
public static function lower($value): array|bool|string|null
34+
{
35+
return mb_strtolower($value, 'UTF-8');
36+
}
37+
38+
public static function startsWith(string $haystack, string $prefix): bool
39+
{
40+
if (isset(static::$_strCache['startsWith'][$haystack][$prefix])) {
41+
return static::$_strCache['startsWith'][$haystack][$prefix];
42+
}
43+
44+
return static::$_strCache['startsWith'][$haystack][$prefix] = str_starts_with($haystack, $prefix);
45+
}
46+
47+
public static function studly(string $value, string $gap = ''): string
48+
{
49+
$value = ucwords(str_replace(['-', '_'], ' ', $value));
50+
51+
return str_replace(' ', $gap, $value);
52+
}
53+
}

tests/Feature/DataTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Ltaooo\Data\Attribute\DataAttribute;
44
use Ltaooo\Data\Data;
5+
use Ltaooo\Data\Util\Str;
56

67
test('data', function () {
78

@@ -25,6 +26,13 @@
2526
->and($b->addressDetail)->toBe($a->addressDetail);
2627
});
2728

29+
test('str', function () {
30+
expect(Str::snake('HelloWorld'))->toBe('hello_world')
31+
->and(Str::camel('hello_world'))->toBe('helloWorld')
32+
->and(Str::camel(''))->toBe('')
33+
->and(Str::startsWith('hello', 'he'))->toBeTrue();
34+
});
35+
2836

2937
#[DataAttribute(toSnakeArray: true)]
3038
class A extends Data

0 commit comments

Comments
 (0)