Skip to content

Commit e678c4b

Browse files
committed
added sync blocks and fixes
1 parent 16aba2b commit e678c4b

22 files changed

Lines changed: 332 additions & 59 deletions

config/contentable.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@
4545
],
4646

4747
'actions' => [
48-
48+
'sync' => Yuges\Contentable\Actions\SyncBlocksAction::class,
49+
],
50+
51+
'calculators' => [
52+
'duration' => [
53+
'class' => Yuges\Contentable\Calculators\DurationCalculator::class,
54+
'symbol' => [
55+
'time' => 0.04,
56+
],
57+
],
4958
],
5059
];

src/Abstracts/BlockData.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#[MergeValidationRules]
1717
abstract class BlockData extends Data implements BlockDataInterface, PropertyMorphableData
1818
{
19+
protected const DURATION = 0.0;
20+
1921
#[PropertyForMorph]
2022
public string $type;
2123

@@ -66,4 +68,9 @@ public static function rules(): array
6668
'type' => [Rule::enum(Config::getBlockTypeClass(BlockType::class))],
6769
];
6870
}
71+
72+
public function duration(): float
73+
{
74+
return static::DURATION;
75+
}
6976
}

src/Actions/.gitkeep

Whitespace-only changes.

src/Actions/SyncBlocksAction.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
namespace Yuges\Contentable\Actions;
4+
5+
use Illuminate\Support\Collection;
6+
use Yuges\Contentable\Models\Block;
7+
use Yuges\Contentable\Models\Content;
8+
9+
class SyncBlocksAction
10+
{
11+
public function __construct(
12+
protected Content $content
13+
) {
14+
}
15+
16+
public static function create(Content $content): self
17+
{
18+
return new static($content);
19+
}
20+
21+
/**
22+
* @param Collection<array-key, Block> $blocks
23+
*/
24+
public function execute(Collection $blocks): array
25+
{
26+
$changes = [
27+
'created' => [], 'deleted' => [], 'updated' => [],
28+
];
29+
30+
$models = $this->content->blocks()->get();
31+
32+
$ids = [
33+
'current' => $models->modelKeys(),
34+
'records' => $blocks->map(fn (Block $block) => $block->getKey())->filter()->toArray(),
35+
];
36+
37+
$deleted = array_diff($ids['current'], $ids['records']);
38+
39+
if (count($deleted)) {
40+
$models->filter(fn (Block $block) => in_array($block->getKey(), $deleted))->each->delete();
41+
42+
$changes['deleted'] = $deleted;
43+
}
44+
45+
$blocks->each(function (Block $block) use ($ids, $models, &$changes) {
46+
$block->content_id = $this->content->getKey();
47+
48+
if (! in_array($block->getKey(), $ids['current'])) {
49+
$block->save();
50+
51+
$changes['created'][] = $block->getKey();
52+
} else {
53+
$model = $models->find($block)->first();
54+
55+
$model->setRawAttributes(
56+
array_merge(
57+
$model->getAttributes(),
58+
$block->getAttributes()
59+
)
60+
);
61+
62+
if ($model->isDirty()) {
63+
$model->save();
64+
65+
$changes['updated'][] = $block->getKey();
66+
}
67+
}
68+
});
69+
70+
return $changes;
71+
}
72+
}

src/Calculators/DurationCalculator.php

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@
22

33
namespace Yuges\Contentable\Calculators;
44

5+
use Yuges\Contentable\Models\Block;
6+
use Yuges\Contentable\Config\Config;
57
use Yuges\Contentable\Models\Content;
68

79
class DurationCalculator
810
{
911
CONST CHARACTERS_PER_SECOND = 25;
1012

11-
private Content $content;
13+
public function __construct(
14+
protected Content $content
15+
) {
16+
}
17+
18+
public static function create(Content $content): self
19+
{
20+
return new static($content);
21+
}
1222

1323
public function setContent(Content $content): self
1424
{
@@ -22,17 +32,36 @@ public function calculate(): int
2232
$seconds = 0;
2333

2434
if (! $this->content->relationLoaded('blocks')) {
35+
$this->content->load('blocks');
36+
}
37+
38+
if ($this->content->blocks->isEmpty()) {
2539
return $seconds;
2640
}
2741

28-
if (empty($this->content->blocks)) {
42+
$seconds = $this->content->blocks->sum(fn (Block $block) => $block->data->duration());
43+
44+
return round($seconds);
45+
}
46+
47+
public static function duration(string|array|null $data): float
48+
{
49+
$seconds = 0.0;
50+
51+
if (! $data) {
2952
return $seconds;
3053
}
3154

32-
foreach ($this->content->blocks as $block) {
33-
$seconds += strlen($block->data->text ?? '') / self::CHARACTERS_PER_SECOND;
55+
if (is_string($data)) {
56+
$data = [$data];
3457
}
3558

59+
$time = Config::getDurationCalculatorSymbolTime();
60+
61+
array_walk_recursive($data, function ($item) use ($time, &$seconds) {
62+
$seconds += strlen($item ?? '') * $time;
63+
});
64+
3665
return $seconds;
3766
}
3867
}

src/Casts/AsData.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function set(
4040
}
4141

4242
return [
43-
'type' => $value->getType(),
43+
'type' => $value->getType()->value,
4444
'data' => $value->toJsonData(),
4545
];
4646
}

src/Config/Config.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Yuges\Contentable\Models\Content;
88
use Yuges\Contentable\Interfaces\BlockType;
99
use Yuges\Contentable\Interfaces\Contentable;
10+
use Yuges\Contentable\Actions\SyncBlocksAction;
1011
use Yuges\Contentable\Interfaces\BlockDataInterface;
12+
use Yuges\Contentable\Calculators\DurationCalculator;
1113

1214
class Config extends \Yuges\Package\Config\Config
1315
{
@@ -94,4 +96,37 @@ public static function getContentableObserverClass(mixed $default = null): strin
9496
{
9597
return self::get('models.contentable.observer', $default);
9698
}
99+
100+
public static function getSyncBlocksAction(
101+
Content $content,
102+
mixed $default = null
103+
): SyncBlocksAction
104+
{
105+
return self::getSyncBlocksActionClass($default)::create($content);
106+
}
107+
108+
/** @return class-string<SyncBlocksAction> */
109+
public static function getSyncBlocksActionClass(mixed $default = null): string
110+
{
111+
return self::get('actions.sync', $default);
112+
}
113+
114+
public static function getDurationCalculator(
115+
Content $content,
116+
mixed $default = null
117+
): DurationCalculator
118+
{
119+
return self::getDurationCalculatorClass($default)::create($content);
120+
}
121+
122+
/** @return class-string<DurationCalculator> */
123+
public static function getDurationCalculatorClass(mixed $default = null): string
124+
{
125+
return self::get('calculators.duration.class', $default);
126+
}
127+
128+
public static function getDurationCalculatorSymbolTime(mixed $default = null): float
129+
{
130+
return self::get('calculators.duration.symbol.time', $default);
131+
}
97132
}

src/Data/Blocks/DelimiterData.php

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

77
class DelimiterData extends \Yuges\Contentable\Abstracts\BlockData
88
{
9+
protected const DURATION = 0.5;
10+
911
public string $type = BlockType::Delimiter->value;
1012

1113
public function __construct() {

src/Data/Blocks/HeaderData.php

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

33
namespace Yuges\Contentable\Data\Blocks;
44

5+
use Yuges\Contentable\Config\Config;
56
use Yuges\Contentable\Enums\BlockType;
67
use Yuges\Contentable\Enums\HeaderLevel;
78

@@ -22,4 +23,9 @@ public function getData(): array
2223
'level' => $this->level,
2324
];
2425
}
26+
27+
public function duration(): float
28+
{
29+
return Config::getDurationCalculatorClass()::duration($this->text);
30+
}
2531
}

src/Data/Blocks/ListData.php

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

33
namespace Yuges\Contentable\Data\Blocks;
44

5+
use Yuges\Contentable\Config\Config;
56
use Yuges\Contentable\Enums\BlockType;
67
use Yuges\Contentable\Enums\ListStyle;
78

@@ -22,4 +23,9 @@ public function getData(): array
2223
'style' => $this->style,
2324
];
2425
}
26+
27+
public function duration(): float
28+
{
29+
return Config::getDurationCalculatorClass()::duration($this->items);
30+
}
2531
}

0 commit comments

Comments
 (0)