Die folgenden Variablen und Operatoren können genutzt werden, um Tagging-Regeln zu erstellen (sei vorsichtig, denn bei einigen Werten musst du Anführungszeichen hinzufügen, z.B. ``language = "de"``):
-=========== ============================================== ======== ==========
-Variable Bedeutung Operator Bedeutung
------------ ---------------------------------------------- -------- ----------
-title Titel des Artikels <= Kleiner gleich als…
-url URL des Artikels < Kleiner als…
-isArchived Ob der Artikel archiviert ist oder nicht => Größer gleich als…
-isStarred Ob der Artikel favorisiert ist oder nicht > Größer als…
-content Inhalt des Eintrags = Gleich zu…
-language Sprache des Eintrags != Nicht gleich zu…
-mimetype MIME-Typ des Eintrags OR Eine Regel oder die andere
-readingTime Die geschätzte Lesezeit in Minuten AND Eine Regel und die andere
-domainName Der Domain-Name des Eintrags matches Testet, dass ein Feld einer Suche (unabhängig von Groß- und Kleinschreibung) übereinstimmt. Z.B.: title matches "Fußball"
-=========== ============================================== ======== ==========
+=========== ============================================== ========== ==========
+Variable Bedeutung Operator Bedeutung
+----------- ---------------------------------------------- ---------- ----------
+title Titel des Artikels <= Kleiner gleich als…
+url URL des Artikels < Kleiner als…
+isArchived Ob der Artikel archiviert ist oder nicht => Größer gleich als…
+isStarred Ob der Artikel favorisiert ist oder nicht > Größer als…
+content Inhalt des Eintrags = Gleich zu…
+language Sprache des Eintrags != Nicht gleich zu…
+mimetype MIME-Typ des Eintrags OR Eine Regel oder die andere
+readingTime Die geschätzte Lesezeit in Minuten AND Eine Regel und die andere
+domainName Der Domain-Name des Eintrags matches Testet, dass ein Feld einer Suche (unabhängig von Groß- und Kleinschreibung) übereinstimmt. Z.B.: title matches "Fußball"
+ notmatches
+=========== ============================================== ========== ==========
The following variables and operators can be used to create tagging rules (be careful, for some values, you need to add quotes, for example ``language = "en"``):
-=========== ============================================== ======== ==========
-Variable Meaning Operator Meaning
------------ ---------------------------------------------- -------- ----------
-title Title of the entry <= Less than…
-url URL of the entry < Strictly less than…
-isArchived Whether the entry is archived or not => Greater than…
-isStarred Whether the entry is starred or not > Strictly greater than…
-content The entry's content = Equal to…
-language The entry's language != Not equal to…
-mimetype The entry's mime-type OR One rule or another
-readingTime The estimated entry's reading time, in minutes AND One rule and another
-domainName The domain name of the entry matches Tests that a subject is matches a search (case-insensitive). Example: title matches "football"
-=========== ============================================== ======== ==========
+=========== ============================================== ========== ==========
+Variable Meaning Operator Meaning
+----------- ---------------------------------------------- ---------- ----------
+title Title of the entry <= Less than…
+url URL of the entry < Strictly less than…
+isArchived Whether the entry is archived or not => Greater than…
+isStarred Whether the entry is starred or not > Strictly greater than…
+content The entry's content = Equal to…
+language The entry's language != Not equal to…
+mimetype The entry's mime-type OR One rule or another
+readingTime The estimated entry's reading time, in minutes AND One rule and another
+domainName The domain name of the entry matches Tests that a subject is matches a search (case-insensitive). Example: title matches "football"
+ notmatches Tests that a subject is not matches a search (case-insensitive). Example: title notmatches "football"
+=========== ============================================== ========== ==========
mimetype The type MIME de l'article OR Telle règle ou telle autre règle
readingTime Le temps de lecture de l'article, en minutes AND Telle règle et telle règle
domainName Le nom de domaine de l'article matches Contient telle chaîne de caractère (insensible à la casse). Exemple : title matches "football"
+ notmaches Ne contient pas telle chaîne de caractère (insensible à la casse). Exemple : title notmatches "football"
=========== ============================================== ========== ==========
$manager->persist($tr3);
+ $tr4 = new TaggingRule();
+ $tr4->setRule('content notmatches "basket"');
+ $tr4->setTags(['foot']);
+ $tr4->setConfig($this->getReference('admin-config'));
+
+ $manager->persist($tr4);
+
$manager->flush();
}
* @Assert\Length(max=255)
* @RulerZAssert\ValidRule(
* allowed_variables={"title", "url", "isArchived", "isStared", "content", "language", "mimetype", "readingTime", "domainName"},
- * allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches"}
+ * allowed_operators={">", "<", ">=", "<=", "=", "is", "!=", "and", "not", "or", "matches", "notmatches"}
* )
* @ORM\Column(name="rule", type="string", nullable=false)
*/
/**
* Set tags.
*
- * @param array<string> $tags
+ * @param array <string> $tags
*
* @return TaggingRule
*/
--- /dev/null
+<?php
+
+namespace Wallabag\CoreBundle\Operator\Doctrine;
+
+/**
+ * Provides a "notmatches" operator used for tagging rules.
+ *
+ * It asserts that a given pattern is not contained in a subject, in a
+ * case-insensitive way.
+ *
+ * This operator will be used to compile tagging rules in DQL, usable
+ * by Doctrine ORM.
+ * It's registered in RulerZ using a service (wallabag.operator.doctrine.matches);
+ */
+class NotMatches
+{
+ public function __invoke($subject, $pattern)
+ {
+ if ($pattern[0] === "'") {
+ $pattern = sprintf("'%%%s%%'", substr($pattern, 1, -1));
+ }
+
+ return sprintf('UPPER(%s) NOT LIKE UPPER(%s)', $subject, $pattern);
+ }
+}
--- /dev/null
+<?php
+
+namespace Wallabag\CoreBundle\Operator\PHP;
+
+/**
+ * Provides a "notmatches" operator used for tagging rules.
+ *
+ * It asserts that a given pattern is not contained in a subject, in a
+ * case-insensitive way.
+ *
+ * This operator will be used to compile tagging rules in PHP, usable
+ * directly on Entry objects for instance.
+ * It's registered in RulerZ using a service (wallabag.operator.array.matches);
+ */
+class NotMatches
+{
+ public function __invoke($subject, $pattern)
+ {
+ return stripos($subject, $pattern) === false;
+ }
+}
tags:
- { name: rulerz.operator, target: doctrine, operator: matches, inline: true }
+ wallabag.operator.array.notmatches:
+ class: Wallabag\CoreBundle\Operator\PHP\NotMatches
+ tags:
+ - { name: rulerz.operator, target: native, operator: notmatches }
+
+ wallabag.operator.doctrine.notmatches:
+ class: Wallabag\CoreBundle\Operator\Doctrine\NotMatches
+ tags:
+ - { name: rulerz.operator, target: doctrine, operator: notmatches, inline: true }
+
wallabag_core.helper.redirect:
class: Wallabag\CoreBundle\Helper\Redirect
arguments:
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
-
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
# unread: 'Unread entries'
or: 'Eine Regel ODER die andere'
and: 'Eine Regel UND eine andere'
matches: 'Testet, ob eine <i>Variable</i> auf eine <i>Suche</i> zutrifft (Groß- und Kleinschreibung wird nicht berücksichtigt).<br />Beispiel: <code>title matches "Fußball"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: 'One rule OR another'
and: 'One rule AND another'
matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
+ notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: 'Una regla U otra'
and: 'Una regla Y la otra'
matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: "Une règle OU l’autre"
and: "Une règle ET l’autre"
matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>"
+ notmatches: "Teste si un <i>sujet</i> ne correspond pas à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title notmatches \"football\"</code>"
entry:
page_titles:
or: "Una regola O un'altra"
and: "Una regola E un'altra"
matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: "Una règla O l'autra"
and: "Una règla E l'autra"
matches: 'Teste se un <i>subjècte</i> correspond a una <i>recerca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: 'Jedna reguła LUB inna'
and: 'Jedna reguła I inna'
matches: 'Sprawdź czy <i>temat</i> pasuje <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł zawiera "piłka nożna"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: 'Uma regra OU outra'
and: 'Uma regra E outra'
matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
or: 'Bir kural veya birbaşkası'
and: 'Bir kural ve diğeri'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
+ # notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
page_titles:
<tr>
<td>domainName</td>
<td>{{ 'config.form_rules.faq.variable_description.domainName'|trans }}</td>
- <td>matches</td>
- <td>{{ 'config.form_rules.faq.operator_description.matches'|trans|raw }}</td>
+ <td>matches<br />notmaches</td>
+ <td>{{ 'config.form_rules.faq.operator_description.matches'|trans|raw }}<br />{{ 'config.form_rules.faq.operator_description.notmatches'|trans|raw }}</td>
</tr>
</tbody>
</table>
$this->assertEquals(false, $content['is_starred']);
$this->assertEquals('New title for my article', $content['title']);
$this->assertEquals(1, $content['user_id']);
- $this->assertCount(1, $content['tags']);
+ $this->assertCount(2, $content['tags']);
}
public function testPostSameEntry()
$this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']);
$this->assertEquals(true, $content['is_archived']);
$this->assertEquals(false, $content['is_starred']);
- $this->assertCount(2, $content['tags']);
+ $this->assertCount(3, $content['tags']);
}
public function testPostArchivedAndStarredEntry()
->findOneByUrl($url);
$tags = $entry->getTags();
- $this->assertCount(1, $tags);
+ $this->assertCount(2, $tags);
$this->assertEquals('wallabag', $tags[0]->getLabel());
$em->remove($entry);
$tags = $entry->getTags();
- $this->assertCount(1, $tags);
- $this->assertEquals('wallabag', $tags[0]->getLabel());
+ $this->assertCount(2, $tags);
+ $this->assertEquals('wallabag', $tags[1]->getLabel());
$em->remove($entry);
$em->flush();
$this->assertEquals($contentInDB->getLanguage(), $content[0]['language']);
$this->assertEquals($contentInDB->getReadingtime(), $content[0]['reading_time']);
$this->assertEquals($contentInDB->getDomainname(), $content[0]['domain_name']);
- $this->assertEquals(['foo bar', 'baz'], $content[0]['tags']);
+ $this->assertEquals(['foo bar', 'baz', 'foot'], $content[0]['tags']);
}
public function testXmlExport()
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId('http://0.0.0.0/entry1', $this->getLoggedInUserId());
- $this->assertEquals(3, count($entry->getTags()));
+ $this->assertEquals(4, count($entry->getTags()));
// tag already exists and already assigned
$client->submit($form, $data);
->getRepository('WallabagCoreBundle:Entry')
->find($entry->getId());
- $this->assertEquals(3, count($newEntry->getTags()));
+ $this->assertEquals(4, count($newEntry->getTags()));
// tag already exists but still not assigned to this entry
$data = [
->getRepository('WallabagCoreBundle:Entry')
->find($entry->getId());
- $this->assertEquals(3, count($newEntry->getTags()));
+ $this->assertEquals(4, count($newEntry->getTags()));
}
public function testAddMultipleTagToEntry()
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.usinenouvelle.com is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.usinenouvelle.com is ok');
- $this->assertEquals(0, count($content->getTags()));
+ $this->assertEquals(1, count($content->getTags()));
$createdAt = $content->getCreatedAt();
$this->assertEquals('2011', $createdAt->format('Y'));
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://lexpansion.lexpress.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://lexpansion.lexpress.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://lexpansion.lexpress.fr is ok');
- $this->assertEquals(2, count($content->getTags()));
+ $this->assertEquals(3, count($content->getTags()));
$content = $client->getContainer()
->get('doctrine.orm.entity_manager')
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://www.liberation.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.liberation.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.liberation.fr is ok');
- $this->assertEquals(0, count($content->getTags()));
+ $this->assertEquals(1, count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
}
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for https://ma.ttias.be is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for https://ma.ttias.be is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for https://ma.ttias.be is ok');
- $this->assertEquals(2, count($content->getTags()));
+ $this->assertEquals(3, count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertEquals('2016-10-26', $content->getCreatedAt()->format('Y-m-d'));
}
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://www.zataz.com is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.zataz.com is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.zataz.com is ok');
- $this->assertEquals(0, count($content->getTags()));
+ $this->assertEquals(1, count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertEquals('2016-09-08', $content->getCreatedAt()->format('Y-m-d'));
}
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://www.framablog.org is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.framablog.org is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.framablog.org is ok');
- $this->assertEquals(1, count($content->getTags()));
+ $this->assertEquals(2, count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
}
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://www.liberation.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.liberation.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.liberation.fr is ok');
- $this->assertEquals(0, count($content->getTags()));
+ $this->assertEquals(1, count($content->getTags()));
$content = $client->getContainer()
->get('doctrine.orm.entity_manager')
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for https://www.mediapart.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for https://www.mediapart.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for https://www.mediapart.fr is ok');
- $this->assertEquals(2, count($content->getTags()));
+ $this->assertEquals(3, count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertEquals('2016-09-08', $content->getCreatedAt()->format('Y-m-d'));
}