Completed
Push — master ( 32aa8e...7def67 )
by Jeremy
21s queued 15s
created

RuleBasedTagger::fixEntry()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Wallabag\CoreBundle\Helper;
4
5
use Psr\Log\LoggerInterface;
6
use RulerZ\RulerZ;
7
use Wallabag\CoreBundle\Entity\Entry;
8
use Wallabag\CoreBundle\Entity\Tag;
9
use Wallabag\CoreBundle\Entity\TaggingRule;
10
use Wallabag\CoreBundle\Repository\EntryRepository;
11
use Wallabag\CoreBundle\Repository\TagRepository;
12
use Wallabag\UserBundle\Entity\User;
13
14
class RuleBasedTagger
15
{
16
    private $rulerz;
17
    private $tagRepository;
18
    private $entryRepository;
19
    private $logger;
20
21
    public function __construct(RulerZ $rulerz, TagRepository $tagRepository, EntryRepository $entryRepository, LoggerInterface $logger)
22
    {
23
        $this->rulerz = $rulerz;
24
        $this->tagRepository = $tagRepository;
25
        $this->entryRepository = $entryRepository;
26
        $this->logger = $logger;
27
    }
28
29
    /**
30
     * Add tags from rules defined by the user.
31
     *
32
     * @param Entry $entry Entry to tag
33
     */
34
    public function tag(Entry $entry)
35
    {
36
        $rules = $this->getRulesForUser($entry->getUser());
37
38
        $clonedEntry = $this->fixEntry($entry);
39
40
        foreach ($rules as $rule) {
41
            if (!$this->rulerz->satisfies($clonedEntry, $rule->getRule())) {
42
                continue;
43
            }
44
45
            $this->logger->info('Matching rule.', [
46
                'rule' => $rule->getRule(),
47
                'tags' => $rule->getTags(),
48
            ]);
49
50
            foreach ($rule->getTags() as $label) {
51
                $tag = $this->getTag($label);
52
53
                $entry->addTag($tag);
54
            }
55
        }
56
    }
57
58
    /**
59
     * Apply all the tagging rules defined by a user on its entries.
60
     *
61
     * @return array<Entry> A list of modified entries
62
     */
63
    public function tagAllForUser(User $user)
64
    {
65
        $rules = $this->getRulesForUser($user);
66
        $entriesToUpdate = [];
67
        $tagsCache = [];
68
69
        $entries = $this->entryRepository
70
            ->getBuilderForAllByUser($user->getId())
71
            ->getQuery()
72
            ->getResult();
73
74
        foreach ($entries as $entry) {
75
            $clonedEntry = $this->fixEntry($entry);
76
77
            foreach ($rules as $rule) {
78
                if (!$this->rulerz->satisfies($clonedEntry, $rule->getRule())) {
79
                    continue;
80
                }
81
82
                foreach ($rule->getTags() as $label) {
83
                    // avoid new tag duplicate by manually caching them
84
                    if (!isset($tagsCache[$label])) {
85
                        $tagsCache[$label] = $this->getTag($label);
86
                    }
87
88
                    $tag = $tagsCache[$label];
89
90
                    $entry->addTag($tag);
91
92
                    $entriesToUpdate[] = $entry;
93
                }
94
            }
95
        }
96
97
        return $entriesToUpdate;
98
    }
99
100
    /**
101
     * Fetch a tag.
102
     *
103
     * @param string $label The tag's label
104
     *
105
     * @return Tag
106
     */
107
    private function getTag($label)
108
    {
109
        $label = mb_convert_case($label, \MB_CASE_LOWER);
110
        $tag = $this->tagRepository->findOneByLabel($label);
0 ignored issues
show
Bug introduced by
The method findOneByLabel() does not exist on Wallabag\CoreBundle\Repository\TagRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

110
        /** @scrutinizer ignore-call */ 
111
        $tag = $this->tagRepository->findOneByLabel($label);
Loading history...
111
112
        if (!$tag) {
113
            $tag = new Tag();
114
            $tag->setLabel($label);
115
        }
116
117
        return $tag;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $tag also could return the type array|integer which is incompatible with the documented return type Wallabag\CoreBundle\Entity\Tag.
Loading history...
118
    }
119
120
    /**
121
     * Retrieves the tagging rules for a given user.
122
     *
123
     * @return array<TaggingRule>
124
     */
125
    private function getRulesForUser(User $user)
126
    {
127
        return $user->getConfig()->getTaggingRules();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $user->getConfig()->getTaggingRules() returns the type Doctrine\Common\Collections\ArrayCollection which is incompatible with the documented return type Wallabag\CoreBundle\Entity\TaggingRule[].
Loading history...
128
    }
129
130
    /**
131
     * Update reading time on the fly to match the proper words per minute from the user.
132
     */
133
    private function fixEntry(Entry $entry)
134
    {
135
        $clonedEntry = clone $entry;
136
        $clonedEntry->setReadingTime($entry->getReadingTime() / $entry->getUser()->getConfig()->getReadingSpeed() * 200);
0 ignored issues
show
Bug introduced by
$entry->getReadingTime()...getReadingSpeed() * 200 of type double is incompatible with the type integer expected by parameter $readingTime of Wallabag\CoreBundle\Entity\Entry::setReadingTime(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

136
        $clonedEntry->setReadingTime(/** @scrutinizer ignore-type */ $entry->getReadingTime() / $entry->getUser()->getConfig()->getReadingSpeed() * 200);
Loading history...
137
138
        return $clonedEntry;
139
    }
140
}
141