Manuell databasfråga i eZ Publish, för ökad prestanda
tisdag, januari 24th, 2012eZ Publish är ett mycket kompetent system för innehållshantering, men ibland kan man behöva gå förbi alla praktiska funktioner som finns. Bland annat kan det vara aktuellt att göra detta när man vill lista en stor mängd data i tabellform, till exempel en medlemslista. Vi hade ett projekt där kunden ville att ungefär 900 medlemmar skulle visas samtidigt i en lista, samt på en Googlekarta, vilket gjorde att det inte blev riktigt optimalt att använda de befintliga funktionerna i eZ Publish, det gick helt enkelt för långsamt. För att lösa problemet byggde jag en modul med en custom fetch som tog hand om det hela istället för de inbyggda fetch-funktionerna. Hur man bygger en egen modul finns väl dokumenterat och det är inget jag tänker beskriva nu, däremot fanns det väldigt lite information (i princip obefintlig) om hur man hämtar ut information direkt ur databasen. Genom att studera databasen och med hjälp av lite reverse enginering kom jag fram till följande.
Om man utgår från tabellen ezcontentobject_tree
som representerar nodträdet så kan man köra en sql-fråga för att få fram alla barn till en viss nod.
SELECT et.contentobject_id id FROM ezcontentobject_tree et WHERE et.parent_node_id = 2
Satsen ovan ger följande resultat.
+------+ | id | +------+ | 58 | | 59 | | 76 | | 122 | +------+
Alltså, en lista på de objekt-id’n som finns direkt under noden med id 2.
Information om varje objekt lagras i tabellen ezcontentobject_attribute, därför gör man en JOIN för att få ut även denna information. Satsen blir då så här.
SELECT et.contentobject_id id, en.data_text namn FROM ezcontentobject_tree et LEFT JOIN ezcontentobject_attribute en ON et.contentobject_id = en.contentobject_id AND et.contentobject_version = en.version AND en.contentclassattribute_id = 361 WHERE et.parent_node_id = 97 AND et.contentobject_is_published = 1 AND et.is_hidden = 0 AND et.is_invisible = 0
Här hämtas alltså information från tabellen ezcontentobject_attribute med contentclassattribut_id lika med 361, vilket är objektets namn i detta fall. Detta id hittar man i administrationsgränssnittet under Setup->Classes och sedan den klass objektet är en instans av. Se bilden nedan.
Jag har i satsen ovan lagt till tre villkor i slutet som ser till att man bara får träffar på noder som är publicerade och synliga på sajten.
Resultatet blir.
+------+-----------------------------+ | id | namn | +------+-----------------------------+ | 398 | COOP OBS! LILLESTRØM | | 399 | COOP OBS! LØREN | | 400 | COOP OBS! MARIERO | | 401 | COOP OBS! MORENEN | | 402 | COOP OBS! NORD AVD. HARSTAD | +------+-----------------------------+
För varje attribut man vill hämta ut måste man alltså göra en extra JOIN enligt ovan.
Om man vill hämta attribut av typen ezurl måste man göra två extra JOINs eftersom själva urlen sparas i tabellen ezurl
och korskopplas i tabellen ezurl_object_link
. Det man måste lägga till är alltså.
LEFT JOIN ezcontentobject_attribute eu ON et.contentobject_id = eu.contentobject_id AND et.contentobject_version = eu.version AND eu.contentclassattribute_id = 367 LEFT JOIN ezurl_object_link eol ON eu.id = eol.contentobject_attribute_id AND eu.version = eol.contentobject_attribute_version LEFT JOIN ezurl eurl ON eol.url_id = eurl.id
Den kompletta sql-frågan blev så här.
SELECT et.contentobject_id id, en.data_text name, etel.data_text tele, efa.data_text fax, pnr.data_text postnr, por.data_text postort, em.data_text email, eurl.url url FROM ezcontentobject_tree et LEFT JOIN ezcontentobject_attribute en ON et.contentobject_id = en.contentobject_id AND et.contentobject_version = en.version AND en.contentclassattribute_id = 361 LEFT JOIN ezcontentobject_attribute etel ON et.contentobject_id = etel.contentobject_id AND et.contentobject_version = etel.version AND etel.contentclassattribute_id = 362 LEFT JOIN ezcontentobject_attribute efa ON et.contentobject_id = efa.contentobject_id AND et.contentobject_version = efa.version AND efa.contentclassattribute_id = 363 LEFT JOIN ezcontentobject_attribute pnr ON et.contentobject_id = pnr.contentobject_id AND et.contentobject_version = pnr.version AND pnr.contentclassattribute_id = 364 LEFT JOIN ezcontentobject_attribute por ON et.contentobject_id = por.contentobject_id AND et.contentobject_version = por.version AND por.contentclassattribute_id = 365 LEFT JOIN ezcontentobject_attribute em ON et.contentobject_id = em.contentobject_id AND et.contentobject_version = em.version AND em.contentclassattribute_id = 366 LEFT JOIN ezcontentobject_attribute eu ON et.contentobject_id = eu.contentobject_id AND et.contentobject_version = eu.version AND eu.contentclassattribute_id = 367 LEFT JOIN ezurl_object_link eol ON eu.id = eol.contentobject_attribute_id AND eu.version = eol.contentobject_attribute_version LEFT JOIN ezurl eurl ON eol.url_id = eurl.id WHERE et.parent_node_id = 97 AND et.contentobject_is_published = 1 AND et.is_hidden = 0 AND et.is_invisible = 0
Resultatet av frågan blir.
+------+-----------------------------+-------------+-------------+--------+------------+------------------------------+------+ | id | name | tele | fax | postnr | postort | email | url | +------+-----------------------------+-------------+-------------+--------+------------+------------------------------+------+ | 398 | COOP OBS! LILLESTRØM | 63 80 55 00 | 63 81 38 30 | 2000 | LILLESTRØM | xxxxx.xxxxx@obs.coop.no | NULL | | 399 | COOP OBS! LØREN | 22 65 50 65 | 22 64 57 17 | 0513 | OSLO | xxx.xxx.xxx.xxx@obs.coop.no | NULL | | 400 | COOP OBS! MARIERO | 51 82 50 50 | 51 82 50 51 | 4095 | STAVANGER | xxxx.xxxxxxx@obs.coop.no | NULL | | 401 | COOP OBS! MORENEN | 69 84 65 00 | 69 84 65 51 | 1859 | SLITU | xxxxxx.xxxxxxx@obs.coop.no | NULL | | 402 | COOP OBS! NORD AVD. HARSTAD | 77 02 89 00 | 77 02 89 01 | 9406 | HARSTAD | xxxxxx.xxxxxx.x@nord.coop.no | NULL | +------+-----------------------------+-------------+-------------+--------+------------+------------------------------+------+
Den här datan använde vi sedan för att bygga en lista över medlemmarna. Vi valde dessutom att generera html-koden direkt i modulen eftersom vi fortfarande inte var helt nöjda med prestandan när vi använde de befintliga template-funktionerna.
Resultatet kan du se här: http://elektronikkbransjen.no/Medlem/Medlemsoversikt
All utdata från sql-satserna ovan är förkortade, den vekliga utdatan var mer än 900 rader.
Epost-adresserna i utdatan ovan är modifierade på grund av sekretess.