0
1
C. Hetzel, 12. Sept. 2013
Datenbankabfragen über
CSS-Selektoren
Unter Verwendung der CssSelector-Komponente
von Symfony2...
2 C. Hetzel, 12. Sept. 2013
Zur Person
Carsten Hetzel
Seit 2000 in der IT als
Softwareengineer tätig, seit 10
Jahren als F...
3 C. Hetzel, 12. Sept. 2013
Die Anforderung
Kundenfreundliche Abfragen
großer, strukturierter Datenmengen
4 C. Hetzel, 12. Sept. 2013
Die Anforderung
Für einen Kunden war in einer Browser basierten
Software eine Suchfunktion ber...
5 C. Hetzel, 12. Sept. 2013
Die Anforderung
Beispiel:
Wir wollen alle Objekte X angezeigt bekommen,
die irgendwo unterhalb...
6 C. Hetzel, 12. Sept. 2013
Die Idee:
CSS-Selektoren
CSS-Selektoren
7 C. Hetzel, 12. Sept. 2013
Aufbau von CSS-Selektoren
* -> Alle Elemente.
E -> Alle Elemente des Typs "E"
E[foo] -> Alle E...
8 C. Hetzel, 12. Sept. 2013
Die Idee: CSS-Selektoren
Um bestimmte Elemente in einem HTML-Dokument auszuwählen und zu bearb...
9 C. Hetzel, 12. Sept. 2013
Die Idee: CSS-Selektoren
Was könnte problematisch sein?
Datenbankmodelle sind nicht notwendige...
10 C. Hetzel, 12. Sept. 2013
Hierarchische Datenstrukturen
und Datenmodelle
und Datenmodelle
Ziel ist, Datenbankabfragen ü...
11 C. Hetzel, 12. Sept. 2013
Hierarchische Datenstrukturen
und Datenmodelle
und Datenmodelle
Wie den einzelnen Beispielen ...
12 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
CssSelector stellt eine
statische Hilfsfunktion zur
Verfügung. Die...
13 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
Da die Klasse CssSelector primär zur Konvertierung von CSS-
Selekt...
14 C. Hetzel, 12. Sept. 2013
Intermezzo!
Never use „new“
(unless you‘re supposed to)
15 C. Hetzel, 12. Sept. 2013
Never use „new“
(unless you‘re supposed to)
(unless you‘re supposed to)
Hilft auch ohne Kennt...
16 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
Da CssSelector als
Fassade dient und die
Komplexität der
interagie...
17 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
Probleme, die sich aus der gegebenen Implementierung der
CssSelect...
18 C. Hetzel, 12. Sept. 2013
Die Komponente XPathTranslator
Offensichtlich ist die Komponente XPathTranslator diejenige, d...
19 C. Hetzel, 12. Sept. 2013
Der Parser
Der Parser zerteilt über
einen Tokenizer
zunächst den CSS-
Selektor in einzelne
To...
20 C. Hetzel, 12. Sept. 2013
Die Node-Klassen
Jeder Bestandteil eines
CSS-Selektors wird
durch eine
gleichlautende Klasse
...
21 C. Hetzel, 12. Sept. 2013
XPathTranslator im Detail
Auch hier wird ähnlich wie
bei der XssSelector-
Klasse eine Reihe v...
22 C. Hetzel, 12. Sept. 2013
XPathTranslator im Detail
In cssToXPath() wird der
Selektor zunächst in
Node-Instanzen
(Selec...
23 C. Hetzel, 12. Sept. 2013
Die Extension-Klassen
Jede Extension-Klasse
ist dafür zuständig, die
für sie relevanten Node-...
24 C. Hetzel, 12. Sept. 2013
XPathExtensions im Detail
Der Vorgang lässt sich
anschaulich an der
Umsetzung der
„HashNode“ ...
25 C. Hetzel, 12. Sept. 2013
CSS-Selektoren für
Datenbankstatements
Als Datenbankschicht wurde das ORM Propel
verwendet - ...
26 C. Hetzel, 12. Sept. 2013
Die Implementierung auf
einen Blick
Es wurde eine einfache Symfony2
Anwendung generiert mit C...
27 C. Hetzel, 12. Sept. 2013
DbQueryTranslator im Detail
Der DbQueryTranslator
orientiert sich am
XPathTranslator (und mac...
28 C. Hetzel, 12. Sept. 2013
Extensions im Detail
Basis für alle weiteren
Operationen ist ein Query-
Objekt des gewünschte...
29 C. Hetzel, 12. Sept. 2013
Extensions im Detail
Hier als Beispiel noch die
Implementierung für
AttributeNodes, mit denen...
30 C. Hetzel, 12. Sept. 2013
Die Anwendung in
Bildern
Über den CssSelector
„Author“ werden alle
Authoren angezeigt.
Er kan...
31 C. Hetzel, 12. Sept. 2013
Die Anwendung in
Bildern
Durch den Join mit Books
wird somit Robert Martin
zweimal angezeigt....
32 C. Hetzel, 12. Sept. 2013
Die Anwendung in
Bildern
Wie man dem Profiler entnehmen kann, werden die korrekten
Datenbanka...
33 C. Hetzel, 12. Sept. 2013
Ausblick
Zusätzliche Funktionalitäten wie „distinct“ oder
Aggregatfunktionen sind denkbar.
Vi...
34 C. Hetzel, 12. Sept. 2013
Fragen? ;-)
35 C. Hetzel, 12. Sept. 2013
Vielen Dank für Ihre
Aufmerksamkeit!
Upcoming SlideShare
Loading in...5
×

2013-09-12, sfugcgn: CSS-Selektoren für Datenbankabfragen nutzen

230

Published on

In diesem Vortrag vom Symfony User Group Cologne Treffen in Köln zeige ich, wie man mit Hilfe von CSS-Selektoren und der CssSelector-Komponente des Symfony2 Frameworks Datenbankabfragen generieren kann. Diese Technik ermöglicht auch Laien einfache Abfragen von komplexen Datenbeständen effizient durchzuführen.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
230
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
2
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • Hinweis: Dieses Problem ist einfach, weil es von einer festen Hierarchie ausgeht! Hinweis: Die Auswahl der darzustellenden Objekte kann nicht PHP-seitig stattfinden, denn dafür ist die Datenmenge zu groß.
  • Vereinfachung: Author und Buch haben eine 1:N-Relation Was fällt am letzten Statement auf? Es kann der selbe Author mehrfach in der Ergebnismenge auftreten! Hier wäre ein „distinct“ nötig, etwa: Books[title^=Clean] Author.distinct()
  • Hinweise: - Die XPath\Translator-Komponente bietet z.B. über den Konstruktor einen anderen Parser zu verwenden. Dem Anwender von CssSelector wird aber keine Möglichkeit geboten einen anderen Parser zu injizieren! - Auf diese Weise kann weder in den Parsing-Prozess eingegriffen, noch dezidiert auf Ereignisse reagiert werden!
  • Hinweise: - Die XPath\Translator-Komponente bietet z.B. über den Konstruktor einen anderen Parser zu verwenden. Dem Anwender von CssSelector wird aber keine Möglichkeit geboten einen anderen Parser zu injizieren! - Auf diese Weise kann weder in den Parsing-Prozess eingegriffen, noch dezidiert auf Ereignisse reagiert werden!
  • Anmerkung: Ist noch jemand bei mir?
  • Transcript of "2013-09-12, sfugcgn: CSS-Selektoren für Datenbankabfragen nutzen"

    1. 1. 1 C. Hetzel, 12. Sept. 2013 Datenbankabfragen über CSS-Selektoren Unter Verwendung der CssSelector-Komponente von Symfony2 Datenbankabfragen gestalten. Von Carsten Hetzel.
    2. 2. 2 C. Hetzel, 12. Sept. 2013 Zur Person Carsten Hetzel Seit 2000 in der IT als Softwareengineer tätig, seit 10 Jahren als Freelancer Likes: Softwaredesign, SF2 (ach was), BDD mit Behat, Oracle-Datenbanken Hobbies: Joggen, Reiten, Klavierspielen http://www.coding-inquiries.de
    3. 3. 3 C. Hetzel, 12. Sept. 2013 Die Anforderung Kundenfreundliche Abfragen großer, strukturierter Datenmengen
    4. 4. 4 C. Hetzel, 12. Sept. 2013 Die Anforderung Für einen Kunden war in einer Browser basierten Software eine Suchfunktion bereitzustellen, die beliebigeObjekte einer Objekthierarchie abfragen und darstellen können sollte. Probleme: - Ca. 1 Mio. Objekte. - Ca. 60 Objekttypen. - Ca. 16 Mio. Parameter.- Die Suchanfragen mussten für Laien möglich sein.
    5. 5. 5 C. Hetzel, 12. Sept. 2013 Die Anforderung Beispiel: Wir wollen alle Objekte X angezeigt bekommen, die irgendwo unterhalb eines Objekts A hängen bei dem der Parameter "a" den Wert 10 hat.
    6. 6. 6 C. Hetzel, 12. Sept. 2013 Die Idee: CSS-Selektoren CSS-Selektoren
    7. 7. 7 C. Hetzel, 12. Sept. 2013 Aufbau von CSS-Selektoren * -> Alle Elemente. E -> Alle Elemente des Typs "E" E[foo] -> Alle Elemente des Typs "E", die ein Attribut "foo" besitzen. E[foo="bar"] -> Alle Elemente des Typs "E", deren Attribut "foo" den Wert "bar" hat. E#10 -> Alle Elemente des Typs "E", deren Attribut "ID" den Wert 10 hat (entspricht E[id=10]). E.myClass -> Alle Elemente des Typs "E", deren Attribut "class" mindestens "myClass" enthält (entspricht E[class~="myClass"]). E F -> Alle Elemente des Typs "F", die Nachkommen von "E"-Elementen sind, sich also irgendwo unterhalb eines E befinden. E > F -> Alle Elemente des Typs "F", die ein direktes Kind von einem "E"-Element sind. E, F -> Alle Elemente des Typs "E" und "F". Siehe: http://www.w3schools.com/cssref/css_selectors.asp oder http://www.w3.org/TR/2009/CR-CSS2-20090908/selector.html
    8. 8. 8 C. Hetzel, 12. Sept. 2013 Die Idee: CSS-Selektoren Um bestimmte Elemente in einem HTML-Dokument auszuwählen und zu bearbeiten werden sogenannte CSS-Selektoren verwendet. Ein solcher Selektor beschreibt den Pfad und die Eigenschaften der Elemente, welche ausgewählt und durch Zuweisung von Eigenschaftswerten verändert werden sollen. CSS-Selektoren sind eine einfache Notation für die Auswahl von Elementen in einem HTML-Dokument. Ein HTML-Dokument ist eine konkrete hierarchische Datenstruktur. Schlussfolgerung: CSS-Selektoren können für beliebige hierarchische Datenstrukturen verwendet werden.
    9. 9. 9 C. Hetzel, 12. Sept. 2013 Die Idee: CSS-Selektoren Was könnte problematisch sein? Datenbankmodelle sind nicht notwendigerweise hierarchisch. Es können nicht (einfach) alle Abfragen, die über SQL möglich sind, über CSS-Selektoren abgebildet werden. Beispiel: Selektiere alle Äpfel, die schwerer sind, als die schwerste Birne. Oder doch(?): Apfel[gewicht>Birne:max(gewicht)]
    10. 10. 10 C. Hetzel, 12. Sept. 2013 Hierarchische Datenstrukturen und Datenmodelle und Datenmodelle Ziel ist, Datenbankabfragen über die Formulierung von Selektoren zu generieren. Beispiele: Author select * from author Author#1 select * from author where id = 1 Author[lastname=Martin] select * from author where lastname = 'Martin' Author[lastname=Martin] Books select b.* from author a join books b on b.author_id = a.id where a.lastname = 'Martin' Books[title^=Clean] Author select a.* from books b join author a on a.id = b.author_id where b.title like 'Clean%'
    11. 11. 11 C. Hetzel, 12. Sept. 2013 Hierarchische Datenstrukturen und Datenmodelle und Datenmodelle Wie den einzelnen Beispielen zu entnehmen ist, können Referenzen in Datenbankmodellen in beiden Richtungen genutzt werden, selbst wenn die Entitäten, wie in diesem vereinfachten Beispiel, nicht über eine 1:N-, sondern über eine N:M-Relation verbunden sind. Die "logische" Hierarchie ergibt sich durch die Wahl der Selektoren.ACHTUNG: Die "natürliche" Verknüpfung von zwei Tabellen findet über ihre gegenseitigen Referenzen statt. Trotz dieser Einschränkung kann es zu großen Ergebnismengen und mehreren gleichen Ergebnisdatensätzen kommen!
    12. 12. 12 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector CssSelector stellt eine statische Hilfsfunktion zur Verfügung. Diese baut lediglich einen Translator zusammen, der die eigentliche Arbeit der Konvertierung des CSS- Ausdrucks in einen XPath-Ausdruck durchführt. class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...} class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...}
    13. 13. 13 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector Da die Klasse CssSelector primär zur Konvertierung von CSS- Selektoren zu XPath-Ausdrücken gedacht ist, stelltsie eine entsprechende Objekthierarchie zusammen. Sie agiert damit als Fassade zum dahinterliegenden, komplexen Objektstruktur.Der Translator ist dementsprechend ein XPath-Translator und verwendet für seine Arbeit die dazugehörigenExtensions und den eigentlichen Parser.
    14. 14. 14 C. Hetzel, 12. Sept. 2013 Intermezzo! Never use „new“ (unless you‘re supposed to)
    15. 15. 15 C. Hetzel, 12. Sept. 2013 Never use „new“ (unless you‘re supposed to) (unless you‘re supposed to) Hilft auch ohne Kenntnisse von OO-Prinzipien und Entwurfsmustern bessere Lösungen hervor zu bringen Erzwingt Dependency Injection Hilft in Komponenten zu denken Fördert flexibilität und Testbarkeit von Code Statische Methoden sind KEIN Ersatz!
    16. 16. 16 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector Da CssSelector als Fassade dient und die Komplexität der interagierenden Objekte versteckt, ist die Verwendung von „new“ hier akzeptabel. Insgesamt ist die Implementierung nicht gut, weil sie keine Einflussnahme auf den Parsingprozess und die Konfiguration der Objekte erlaubt. class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...} class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...}
    17. 17. 17 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector Probleme, die sich aus der gegebenen Implementierung der CssSelector-Komponente ergeben: CssSelector::toXPath() erzeugt eine direkte Abhängigkeit im Client-Code. Jeder Aufruf von CssSelector::toXPath() erzeugt alle verwendeten Objekte neu. CssSelector ist weder wiederverwendbar, noch erweiterbar. Aber: toXPath() macht was es soll. ;-)
    18. 18. 18 C. Hetzel, 12. Sept. 2013 Die Komponente XPathTranslator Offensichtlich ist die Komponente XPathTranslator diejenige, die die eigentliche Arbeit macht. Verwendet einen Parser, um den CSS-Selektor in eine Node-Struktur umzuwandeln. Benutzt Extensions um die verschiedenen NodeTypen (ElementNode, AttributeNode etc.) in einen XPath-Ausdruck umzuwandeln.
    19. 19. 19 C. Hetzel, 12. Sept. 2013 Der Parser Der Parser zerteilt über einen Tokenizer zunächst den CSS- Selektor in einzelne Tokens. Die Tokens werden anschließend in entsprechende Node- Instanzen umgewandelt und zurück geliefert.
    20. 20. 20 C. Hetzel, 12. Sept. 2013 Die Node-Klassen Jeder Bestandteil eines CSS-Selektors wird durch eine gleichlautende Klasse repräsentiert. Der Parser wandelt also den Selektor in eine Objekthierarchie um und erzeugt dazu die jeweiligen Instanzen.
    21. 21. 21 C. Hetzel, 12. Sept. 2013 XPathTranslator im Detail Auch hier wird ähnlich wie bei der XssSelector- Klasse eine Reihe von zusätzlichen Hilfsklassen instanziiert, um die Verarbeitung in separate Aufgabenbereiche aufzutrennen. Zusätzlilch zur Konfiguration durch CssSelector nimmt also auch noch Translator selber seine Konfiguration in die Hand. class Translator implements TranslatorInterface{ ... public function __construct(ParserInterface $parser = null) { $this->mainParser = $parser ?: new Parser(); $this ->registerExtension(new ExtensionNodeExtension($this)) ->registerExtension(new ExtensionCombinationExtension()) ->registerExtension(new ExtensionFunctionExtension()) ->registerExtension(new ExtensionPseudoClassExtension()) ->registerExtension(new ExtensionAttributeMatchingExtension()) ; } ...} class Translator implements TranslatorInterface{ ... public function __construct(ParserInterface $parser = null) { $this->mainParser = $parser ?: new Parser(); $this ->registerExtension(new ExtensionNodeExtension($this)) ->registerExtension(new ExtensionCombinationExtension()) ->registerExtension(new ExtensionFunctionExtension()) ->registerExtension(new ExtensionPseudoClassExtension()) ->registerExtension(new ExtensionAttributeMatchingExtension()) ; } ...}
    22. 22. 22 C. Hetzel, 12. Sept. 2013 XPathTranslator im Detail In cssToXPath() wird der Selektor zunächst in Node-Instanzen (SelectorNode) und anschließend über selectorToXPath() in einen XPath-Ausdruck umgewandelt. class Translator implements TranslatorInterface{ ... public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::') { $selectors = $this->parseSelectors($cssExpr); /** @var SelectorNode $selector */ foreach ($selectors as $selector) { if (null !== $selector- >getPseudoElement()) { throw new ExpressionErrorException('Pseudo-elements are not supported.'); } } $translator = $this; return implode(' | ', array_map(function (SelectorNode $selector) use ($translator, $prefix) { return $translator->selectorToXPath($selector, $prefix); }, $selectors)); } ...} class Translator implements TranslatorInterface{ ... public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::') { $selectors = $this->parseSelectors($cssExpr); /** @var SelectorNode $selector */ foreach ($selectors as $selector) { if (null !== $selector- >getPseudoElement()) { throw new ExpressionErrorException('Pseudo-elements are not supported.'); } } $translator = $this; return implode(' | ', array_map(function (SelectorNode $selector) use ($translator, $prefix) { return $translator->selectorToXPath($selector, $prefix); }, $selectors)); } ...}
    23. 23. 23 C. Hetzel, 12. Sept. 2013 Die Extension-Klassen Jede Extension-Klasse ist dafür zuständig, die für sie relevanten Node- Instanzen in einen XPath-Ausdruck umzuwnadeln. Dabei werden vom Translator die dazu registrierten Methoden aufgerufen.
    24. 24. 24 C. Hetzel, 12. Sept. 2013 XPathExtensions im Detail Der Vorgang lässt sich anschaulich an der Umsetzung der „HashNode“ zeigen: Ein Ausdruck wie „Author#1“ soll das Element mit der ID „1“. Die HashNode hat eine SelectorNode und die gewünschte ID. Beide Bestandteile werden vom Translator in den finalen XPath-Ausdruck konvertiert. class NodeExtension extends AbstractExtension{ ... public function translateHash(NodeHashNode $node) { $xpath = $this->translator- >nodeToXPath($node->getSelector()); return $this->translator- >addAttributeMatching($xpath, '=', '@id', $node->getId()); } ...} class NodeExtension extends AbstractExtension{ ... public function translateHash(NodeHashNode $node) { $xpath = $this->translator- >nodeToXPath($node->getSelector()); return $this->translator- >addAttributeMatching($xpath, '=', '@id', $node->getId()); } ...} class AttributeMatchingExtension extends AbstractExtension{ ... public function translateEquals(XPathExpr $xpath, $attribute, $value) { return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value))); } ...} class AttributeMatchingExtension extends AbstractExtension{ ... public function translateEquals(XPathExpr $xpath, $attribute, $value) { return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value))); } ...}
    25. 25. 25 C. Hetzel, 12. Sept. 2013 CSS-Selektoren für Datenbankstatements Als Datenbankschicht wurde das ORM Propel verwendet - es lassen sich aber auch andere ORMs oder DBALs wie z.B. Doctrine verwenden. Die Realisierung des Translators wurde an XPathTranslator angelehnt. Das Datenmodell besteht aus Authoren und Büchern mit einer 1:N-Beziehung.
    26. 26. 26 C. Hetzel, 12. Sept. 2013 Die Implementierung auf einen Blick Es wurde eine einfache Symfony2 Anwendung generiert mit Controllern zu Book und Author. Der DbQueryTranslator wandelt den CSS-Selektor in ein ModelCriteria- Objekt um - entweder vom Typ AuthorQuery oder BookQuery. Die Extensions sind dafür zuständig die API der Propel-Query-Klassen anzusprechen.
    27. 27. 27 C. Hetzel, 12. Sept. 2013 DbQueryTranslator im Detail Der DbQueryTranslator orientiert sich am XPathTranslator (und macht die gleichen Fehler). Damit die NodeExtension die richtigen Model-Klassen finden kann, benötigt sie deren Namespace. Der Rest funktioniert analog: Parsen des Selektors und Umwandeln der Nodes in ein ModelCriteria (bzw. AuthorQuery oder BookQuery). class Translator{ public function __construct( ParserInterface $parser = null ) { $this->mainParser = $parser ? : new Parser(); $modelNS = 'AppDbModelSelectorBundleModel'; $this->registerExtension( new ExtensionNodeExtension( $this, null, $modelNS ) ) ->registerExtension( new ExtensionCombinationExtension() ) ->registerExtension( new ExtensionAttributeMatchingExtension() ); } public function cssToDbQuery( $cssExpr ) { $selectors = $this->parseSelectors( $cssExpr ); $query = null; foreach( $selectors as $selector ){ $query = $this->selectorToDbQuery( $selector, $query ); } return $query; } ...} class Translator{ public function __construct( ParserInterface $parser = null ) { $this->mainParser = $parser ? : new Parser(); $modelNS = 'AppDbModelSelectorBundleModel'; $this->registerExtension( new ExtensionNodeExtension( $this, null, $modelNS ) ) ->registerExtension( new ExtensionCombinationExtension() ) ->registerExtension( new ExtensionAttributeMatchingExtension() ); } public function cssToDbQuery( $cssExpr ) { $selectors = $this->parseSelectors( $cssExpr ); $query = null; foreach( $selectors as $selector ){ $query = $this->selectorToDbQuery( $selector, $query ); } return $query; } ...}
    28. 28. 28 C. Hetzel, 12. Sept. 2013 Extensions im Detail Basis für alle weiteren Operationen ist ein Query- Objekt des gewünschten Models. Dazu wird der Name der ElementNode ermittelt und im Namespace der Models geprüft, ob es eine passende Klasse gibt, also AuthorQuery oder BookQuery gesucht. Query-Klassen werden bei Propel über die Statische „create()“-Methode erzeugt. class NodeExtension extends AbstractExtension{ public function translateElement( NodeElementNode $node ) { $element = $node->getElement(); $queryClassName = $this- >modelNamespace . $element . 'Query'; if( ! class_exists( $queryClassName ) ) throw new RuntimeException( sprintf( 'Model %s not supported!', $queryClassName ) ); return $queryClassName::create(); } ...} class NodeExtension extends AbstractExtension{ public function translateElement( NodeElementNode $node ) { $element = $node->getElement(); $queryClassName = $this- >modelNamespace . $element . 'Query'; if( ! class_exists( $queryClassName ) ) throw new RuntimeException( sprintf( 'Model %s not supported!', $queryClassName ) ); return $queryClassName::create(); } ...}
    29. 29. 29 C. Hetzel, 12. Sept. 2013 Extensions im Detail Hier als Beispiel noch die Implementierung für AttributeNodes, mit denen where-Bedingungen für die Datenbank erzeugt werden. Die SelectorNode kapselt dabei wieder den Zugriff auf die Datenbanktabelle, die AttributeNode die Bedingungen für einzelne Spalten der Tabelle. class NodeExtension extends AbstractExtension{ ... public function translateAttribute( NodeAttributeNode $node ) { $attribute = $node->getAttribute(); $operator = $node->getOperator(); $value = $node->getValue(); $query = $this->translator- >nodeToDbQuery( $node->getSelector() ); return $this- >translator->addAttributeMatching( $query, $operator, $attribute, $value ); } ...} class NodeExtension extends AbstractExtension{ ... public function translateAttribute( NodeAttributeNode $node ) { $attribute = $node->getAttribute(); $operator = $node->getOperator(); $value = $node->getValue(); $query = $this->translator- >nodeToDbQuery( $node->getSelector() ); return $this- >translator->addAttributeMatching( $query, $operator, $attribute, $value ); } ...}
    30. 30. 30 C. Hetzel, 12. Sept. 2013 Die Anwendung in Bildern Über den CssSelector „Author“ werden alle Authoren angezeigt. Er kann alternativ auch weggelassen werden. In den Beispieldaten hat Robert Martin zwei Bücher und Martin Fowler eines.
    31. 31. 31 C. Hetzel, 12. Sept. 2013 Die Anwendung in Bildern Durch den Join mit Books wird somit Robert Martin zweimal angezeigt. Der Translator wäre nützlicherweise so anzupassen, dass er einen Pseudoknoten „distinct“ erlaubt, um diesen Effekt zu vermeidenn.
    32. 32. 32 C. Hetzel, 12. Sept. 2013 Die Anwendung in Bildern Wie man dem Profiler entnehmen kann, werden die korrekten Datenbankabfragen generiert. Der Selector „Book[title*=Coder] Author[Lastname=Martin]“ wurde umgesetzt.
    33. 33. 33 C. Hetzel, 12. Sept. 2013 Ausblick Zusätzliche Funktionalitäten wie „distinct“ oder Aggregatfunktionen sind denkbar. Virtuelle Attribute wie „Book.count()“ können realisiert werden. Bei bestimmten Zugriffen können Hints für den Ausführungsplan ergänzt werden. ...
    34. 34. 34 C. Hetzel, 12. Sept. 2013 Fragen? ;-)
    35. 35. 35 C. Hetzel, 12. Sept. 2013 Vielen Dank für Ihre Aufmerksamkeit!
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×