Completed
Pull Request — develop (#27)
by Chris
13:09
created

Parser::handleTag()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 27
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 8.439
c 0
b 0
f 0
cc 6
eloc 19
nc 9
nop 1
1
<?php
2
3
namespace Chrisyue\PhpM3u8\Parser;
4
5
use Chrisyue\PhpM3u8\Model\Mapping\AttributeMetadatas;
6
use Chrisyue\PhpM3u8\Model\Mapping\TagMetadatas;
7
use Chrisyue\PhpM3u8\Model\MediaSegment;
8
use Chrisyue\PhpM3u8\Model\Tag\AbstractAttributeList;
9
use Chrisyue\PhpM3u8\Model\Mapping\TagMetadata;
10
use Chrisyue\PhpM3u8\Model\Tag\FormattedTagInterface;
11
12
class Parser
13
{
14
    private $builder;
15
    private $tagMetadatas;
16
17
    public function __construct(PlaylistBuilder $builder)
18
    {
19
        $this->builder = $builder;
20
        $this->tagMetadatas = new TagMetadatas();
21
22
        $this->builder->initPlaylist();
23
    }
24
25
    public function parseLine($line)
26
    {
27
        $line = trim($line);
28
        if (empty($line)) {
29
            return;
30
        }
31
32
        if ('#' === $line[0]) {
33
            return $this->handleTag($line);
34
        }
35
36
        $this->builder->addUri($line);
37
    }
38
39
    public function getPlaylist()
40
    {
41
        return $this->builder->getResult();
42
    }
43
44
    private function handleTag($tag)
45
    {
46
        list($tag, $value) = array_pad(explode(':', substr($tag, 1)), 2, true);
47
        $tagMetadata = $this->tagMetadatas->get($tag);
48
        if (null === $tagMetadata) {
49
            return;
50
        }
51
52
        $class = $tagMetadata->getType();
53
        if (class_exists($class)) {
54
            switch (true) {
55
                case is_subclass_of($class, AbstractAttributeList::class):
56
                    $value = $this->createAttrTag($class, $value);
57
                    break;
58
                case is_subclass_of($class, FormattedTagInterface::class):
59
                    $value = $this->createFormattedTag($class, $value);
60
            }
61
        }
62
63
        switch ($tagMetadata->getProperty()->getDeclaringClass()->getName()) {
64
            case MediaSegment::class:
65
                $this->builder->addMediaSegmentTag($tagMetadata, $value);
66
                break;
67
            default:
68
                $this->builder->addPlaylistTag($tagMetadata, $value);
69
        }
70
    }
71
72
    private function createAttrTag($class, $value)
73
    {
74
        $attrMetadatas = new AttributeMetadatas($class);
75
        $attrTag = new $class();
76
        $this->parseAttributeListValue($value, function ($key, $val) use ($attrTag, $attrMetadatas) {
77
            if (!$attrMetadatas->get($key)) {
78
                return;
79
            }
80
81
            $metadata = $attrMetadatas->get($key);
82
            $metadata->getProperty()->setValue($attrTag, 'string' === $metadata->getType() ? trim($val, '"') : $val);
83
        });
84
85
        return $attrTag;
86
    }
87
88
    private function createFormattedTag($class, $value)
89
    {
90
        return $class::fromString($value);
91
    }
92
93
    private function parseAttributeListValue($value, callable $handler)
94
    {
95
        foreach (explode(',', $value) as $attr) {
96
            list($key, $value) = explode('=', $attr);
97
98
            $handler($key, $value);
99
        }
100
    }
101
}
102