5
Tags:
php
Skrevet af
Bruger #2779
@ 25.09.2010
Indledning
Sitemagic CMS er et PHP-baseret framework og Content Management System i stærk fremgang. Denne artikel vil introducere dig til udvikling af udvidelser til den populære danske platform,
Sitemagic CMS.
Sitemagic CMS er et simpelt men både stærkt og fleksibelt framework til udviklere, der gør det muligt at producere stærke online-applikationer i en fart. Resultatet er færre linjer kode samt større sikkerhed og pålidelighed.
Frameworket stiller en lang række funktioner til rådighed, hvilket omfatter alt fra database-funktionalitet til GUI-komponenter (indtastningsfelter, knapper, lister, træ-visninger osv).
Koden bag Sitemagic CMS er baseret på Objekt Orienteret Programmering (OOP). Kendskab til klasser og objekter vil derfor være en fordel.
Målet er, at du efter at have læst denne artikel, kan skrive dine egne udvidelser til Sitemagic CMS. Kode-eksemplerne i denne artikel resulterer i en færdig gæstebog/tagwall-udvidelse, som kan indsættes på indholdssider i Sitemagic CMS.
Har du ikke arbejdet med Sitemagic CMS før, så besøg først
CMS-guiden, som giver en god introduktion til systemet. Det kan også betale sig at opsætte Sitemagic CMS på eget webhotel, så det hele kan prøves af. Derudover er
udvikler-dokumentationen guld værd, hvis der er kode i disse eksempler som du ikke forstå.
Bemærk: De følgende par afsnit handler om hvordan Sitemagic CMS fungerer. Hvis du bare er interesseret i at se hvordan en udvidelse laves til Sitemagic CMS, så sprig direkte til afsnittet "Hello world".
Kort om Sitemagic CMS
Sitemagic CMS er et framework med en række standard-moduler som udgør et Content Management System. Produktet kan downloades gratis fra
http://sitemagic.dk. Den gratis udgave gemmer data i XML filer, mens Enterprise-udgaven benytter den lynhurtige MySQL database. Enterprise-udgaven koster penge, men udviklere kan også få denne udgave gratis, ved at
kontakte Sitemagic-teamet.
En generel guide til opsætning og konfiguration findes på adressen
http://cms-guide.dk. Artiklen her vil derfor ikke behandle disse emner nærmere. Det er dog relevant at se på strukturen af Sitemagic CMS, for at få en forståelse for hvordan løsningen hænger sammen.
- base
Mappe med alle klasser til frameworket
- data
Mappe med XML-data-filer (i Enterprise-versionen bruges i stedet en MySQL database)
- extensions
Mappe med alle udvidelserne
- files
Mappe med filer der bruges på websiden (fx billeder, video osv.)
- images
Mappe med ikon-pakker til Sitemagic
- templates
Mappe med design-skabeloner
- config.xml.php
XML fil med indstillinger (fx brugernavn og adgangskode til login, samt navn på udvidelsen der som standard skal vises)
Altså er mapperne extensions, images og templates, samt filen config.xml.php, de relevante dele når det kommer til tilpasning af Sitemagic CMS. Vi kommer til at tilføje filer til mappen extensions i denne guide.
Generelt om udvidelser
Normalt består en webside, baseret på Sitemagic CMS, i grove træk af en menu og et indholdsområde. I indholdsområdet indlæses udvidelserne. Når en besøgende kigger på hjemmesiden, ser han eller hun normalt blot tekst og billeder - men det er i virkeligheden udvidelsen SMPages, der viser indholdet.
I denne artikel laver vi også en normal udvidelse (en gæstebog). Den skal dog ikke indlæses i indholdsområdet ligesom de andre udvidelser. I stedet er vi interesseret i at lave en udvidelse som kan trækkes ind på en indholdsside, samme med øvrig tekst og billeder. Dette er muligt takket være SMPages udvidelsen, som understøtter såkaldte Indholdsside-udvidelser (altså en "mini-udvidelse" inde i en "rigtig" udvidelse).
En udvidelse ligger i mappen extensions, og består som minimum af følgende filer:
- Main.class.php (selve udvidelsen)
- metadata.xml (information om udvidelsen)
Filen Main.class.php indeholder en klasse, som udgør udvidelsen. Denne vender vi tilbage til.
Filen metadata.xml indeholder lidt generel information om vores udvidelse, herunder navn, ejer/forfatter, versionsnummer og information om eventuelle afhængigheder.
Derudover kan en udvidelse også indeholde følgende:
- Languages (mappe med sprog-filer)
- ContentPageExtension.class.php (indholdsside-udvidelse)
Mappen Languages indeholder XML-filer med oversættelser til udvidelsen.
Filen ContentPageExtension.class.php kan kaldes noget andet, men dækker over vores "mini-udvidelse" (indhodsside-udvidelse). Det er altså denne fil der udgør vores gæstebog, som skal kunne trækkes ind på en indholdsside samme med tekst og billeder.
Sådan fungerer udvidelser
Indtil videre har denne artikel givet indtryk af, at kun én udvidelse kører af gangen. Dette er dog ikke helt korrekt. Faktisk kan alle installerede udvidelser få lov til at afvikle kode, hver gang en side indlæses - men det er kun én udvidelse der får lov til at blive indlæst i indholds-området. Eksempelvis bygger udvidelsen SMMenu en navigationsmenu, selv om udvidelsen SMPages bliver kørt og viser tekst og billeder. Dette muliggøres af Sitemagic CMS, som lader de forskellige moduler afvikle kode på forskellige tidspunkter.
På billedet nedenfor vises princippet, hvor 3 udvidelser skiftevis får kaldt metoderne PreInit, Init og InitComplete. Livscyklussen består dog af
flere metoder end vist.
Det smarte ved livscyklussen er, at den giver mulighed for at udvidelserne kan interagere med hinanden på bestemte tidspunkter. Dette udnytter de fleste udvidelser fx til at registrere links i menuen, så brugeren kan tilgå dem i kontrolpanelet. Dette ser vi et eksempel på senere.
Den udvidelse der afvikles i indholds-området kaldes vores Main Extension - dvs. den primære udvidelse. Hvilken udvidelse der får lov til at være Main Extension afgøres af en parameter i URL'en der ser således ud: SMExt=SMPages. Dette er ikke noget brugeren skal tænke på - parameteren indsættes typisk i URL'en automatisk, når der klikkes på en knap eller et link - fx i menuen. Mere om dette senere.
Al denne tekniske snak kan måske virke forvirrende, men brikkerne falder sikkert på plads, så snart du ser nogle kode-eksempler.
Hello world - min først udvidelse
Vi vil straks kaste os over vores første udvidelse. Start med at oprette de nødvendige filer og mapper til den nye udvidelse:
- I mappen extensions oprettes en ny mappe med navnet HelloWorld
- I den nye HelloWorld mappe oprettes disse filer: Main.class.php, ContentPageExtension.class.php og metadata.xml.php (det er ikke en fejl at filen ender på .php - det forhindrer folk i at åbne den via webserveren udefra)
I det følgende ser du indholdet til de 3 filer. Kopier indholdet ind i de respektive filer. Forklaringen til koden findes i selve kode-filerne som kommentarer. Du kan også blot downloade kode-eksemplet (vedhæftet som HelloWorld.zip)
Bemærk: Det anbefales at koden åbnes uden for udvikleren.dk, da kodeboksene nedenfor er så små, at det bliver svært at overskue koden.
Main.class.php- <?php
-
- // Bemærk at klassen skal hedde det samme som udvidelsens mappe (HelloWorld)
- class HelloWorld extends SMExtension
- {
- // Funktionen PreInit er den første der afvikles for en udvidelse.
- public function PreInit()
- {
- // En udvidelse kan køre i to tilstande - Dedicated Execution Mode og
- // Shared Execution Mode. Hvis du vil læse mere om de to tilstande,
- // så besøg flg. URL: http://sitemagic.org/dev/ExtLifeCycle.html
- // Indholdsside-udvidelser skal ikke kunne køre i Dedicated Execution
- // Mode, så vi smider en fejl hvis dette forsøges.
- if ($this->context->GetExecutionMode() === SMExecutionMode::$Dedicated)
- throw new Exception("Dedicated execution mode not supported");
- }
-
- // Funktionen PreTemplateUpdate afvikles forholdsvis sent i livscyklussen.
- // Funktionen afvikles umiddelbart før indhold fra den primære udvidelse
- // (kaldet Main Extension) indsættes i design-skabelonen. Hvad mere relevant er,
- // at netop dette stadie i livscyklussen giver mulighed for at indsætte links i
- // menuen.
- public function PreTemplateUpdate()
- {
- // Vi indlæser funktionaliteten fra udvidelsen SMMenu.
- // Import-funktionen returnerer False, hvis SMMenu ikke er installeret.
- $smMenuExists = SMExtensionManager::Import("SMMenu", "SMMenu.classes.php");
-
- if ($smMenuExists === true) // Hvis SMMenu er installeret, fortsætter vi
- {
- // Vi tager nu fat i menu-elementet til kontrolpanelet.
- // Funktionen GetChild returnerer NULL, hvis elementet ikke findes.
- // Elementet findes kun, hvis brugeren er logget ind i kontrolpanelet!
- $adminItem = SMMenuManager::GetInstance()->GetChild("SMMenuAdmin");
-
- if ($adminItem !== null) // Hvis admin-menu'en findes, indsætter vi et link
- {
- // 2 nye links oprettes og indsættes i admin-menuen.
- // SMMenuItem skabes med et unikt ID (begynder med navnet på udvidelsen), en titel på linket, og selve link URL'en.
- // Funktionen SMExtensionManager::GetExtensionUrl("HelloWorld") genererer et link til udvidelsen med navnet HelloWorld,
- // som vi efterfølgende tilføjer endnu en URL parameter, HelloWorldFunktion=SigHej og HelloWorldFunktion=VisBoks.
- // Bemærk at URL parameteren får et unikt navn (det begynder med navnet på udvidelsen).
-
- $link1 = new SMMenuItem("HelloWorldSigHej", "Min udvidelse (hej)", SMExtensionManager::GetExtensionUrl("HelloWorld") . "&HelloWorldFunktion=SigHej");
- $adminItem->AddChild($link1);
-
- $link2 = new SMMenuItem("HelloWorldVisBoks", "Min udvidelse (boks)", SMExtensionManager::GetExtensionUrl("HelloWorld") . "&HelloWorldFunktion=VisBoks");
- $adminItem->AddChild($link2);
- }
-
- // Her opretter vi et 3. link som altid vises - ligegyldigt om man er logget ind eller ej.
- $link3 = new SMMenuItem("HelloWorldForAlle", "Min udvidelse (for alle)", SMExtensionManager::GetExtensionUrl("HelloWorld") . "&HelloWorldFunktion=ForAlle");
- SMMenuManager::GetInstance()->AddChild($link3);
- }
- }
-
- // Denne funktion bliver KUN afviklet for den primære udvidelse - dvs. den udvidelse som er valgt
- // til at køre i Sitemagic CMS. Man vælger at køre en udvidelse ved at angive den i URL'en med
- // URL-parameteren SMExt=NavnPaaUdvidelse (fx SMExt=HelloWorld).
- // De to links vi oprettede i menuen fik tildelt en URL-adresse med funktionen SMExtensionManager::GetExtensionUrl("HelloWorld"),
- // som sørger for at tilføje SMExt=HelloWorld.
- public function Render()
- {
- // I denne funktion kan vi udskrive (returnere) det som vi ønsker modulet skal vise
- // når det afvikles som den primære udvidelse (Main Extension).
-
- // Du husker sikkert at vi tilføjede en ekstra URL parameter til de 3 links vi oprettede.
- // Vi tjekker her hvilket link der blev klikket på, ved at tjekke værdien af URL-parameteren.
-
- // Hvis du foretrækker "ren" PHP kode, så kunne værdien i URL'en også være tjekkes sådan: isset($_GET["HelloWorldFunktion]) === "SigHej"
- if (SMEnvironment::GetQueryValue("HelloWorldFunktion") === "SigHej")
- {
- $udskriv = "Hej med dig! :-)";
- return $udskriv;
- }
- if (SMEnvironment::GetQueryValue("HelloWorldFunktion") === "VisBoks")
- {
- $udskriv = "<div style=\"width: 100px; height: 100px; background-color: #DD0000\"> </div>";
- return $udskriv;
- }
- if (SMEnvironment::GetQueryValue("HelloWorldFunktion") === "ForAlle")
- {
- $udskriv = "Tak fordi du kiggede forbi";
- return $udskriv;
- }
- }
-
- // Når vi udvikler vores indholdsside-udvidelse ("mini-udvidelse"), vil vi ikke få brug for Render() funktionen, eller at registrere
- // links i menuen. Dette er kun aktuelt hvis man vil lave en almindelig udvidelse. Vi har derimod brug for at fortælle udvidelsen
- // SMPages at vi har lavet en mini-udvidelse, og at den skal gøre den tilgængelig i Sitemagic CMS. Dette gør vi nedenfor:
-
- // Koden i dette eksempel er opbygget logisk i forhold til artiklen, således at den er nemmere at forklare.
- // I virkeligheden afvikles funktionen InitComplete dog meget tidligere end fx Render() og PreTemplateUpdate(),
- // og kunne derfor med rette placeres længere oppe i koden. Men af hensyn til artiklen er den oprettet her.
- // I virkeligheden betyder det jo heller ikke noget hvor den er placeret - det er Objekt Orienteret Programmering.
- public function InitComplete()
- {
- // Vi indlæser funktionaliteten fra udvidelsen SMPages.
- // Import-funktionen returnerer False, hvis SMPages ikke er installeret.
- $smPagesExists = SMExtensionManager::Import("SMMenu", "SMMenu.classes.php");
-
- if ($smPagesExists === true) // Hvis SMPages er installeret, fortsætter vi
- {
- // Funktionen SMPagesExtensionList::GetInstance()->GetReadyState() fortæller os,
- // om brugeren er ved at indsætte en indholdsside-udvidelse på en indholdsside.
- // Det er kun relevant at fortælle udvidelsen SMPages om vores indholdsside-udvidelse,
- // hvis en bruger er ved at indsætte en indholdsside-udvidelse.
- if (SMPagesExtensionList::GetInstance()->GetReadyState() === true)
- {
- $kategori = "Min test";
- $udvidelse = "HelloWorld";
- $fil = "ContentPageExtension.class.php";
- $klasse = "HelloWorldContentPageExtension";
-
- // Vi registrerer vores indholdsside-udvidelse.
- // Funktionen SMPagesExtensionList::GetInstance()->AddExtension() kaldes med navnet på
- // kategorien som vores udvidelse skal vises under (vi fandt på vores egen - "Min test"),
- // hvad selve indholdsside-udvidelsen skal hedde (fx "Lille boks"), under hvilken udvidelse vores
- // indholdsside-udvidelse findes ("HelloWorld"), hvad filen hedder som indeholder koden til vores
- // indholdsside-udvidelse ("ContentPageExtension.class.php"), hvad klassen (OOP) som udgør selve
- // indholdsside-udvidelsen hedder ("HelloWorldContentPageExtension"), et valgfrit argument (fx "Lille"),
- // og endelig bredden og højden, som man forventer indholdsside-udvidelsen cirka vil fylde (100 x 25),
- // hvilke bruges til at vise en "dummy" af indholdsside-udvidelsen når en bruger redigerer en indholdsside.
-
- // Vi registrerer nu den samme indholdsside-udvidelse 3 gange, men med forskellige navne, argumenter og størrelser.
- // Det giver indtryk af at brugeren får 3 nye indholdsside-udvidelser, men i virkeligheden er det én og samme
- // indholdsside-udvidelse, der blot foretager sig forskellige ting afhængig af argumentet ("Lille", "Mellem" eller "Stor").
-
- SMPagesExtensionList::GetInstance()->AddExtension($kategori, "Lille boks", $udvidelse, $fil, $klasse, "Lille", 100, 25);
- SMPagesExtensionList::GetInstance()->AddExtension($kategori, "Mellem boks", $udvidelse, $fil, $klasse, "Mellem", 200, 50);
- SMPagesExtensionList::GetInstance()->AddExtension($kategori, "Stor boks", $udvidelse, $fil, $klasse, "Stor", 300, 75);
- }
- }
- }
- }
-
- ?>
ContentPageExtension.class.php- <?php
-
- SMExtensionManager::Import("SMPages", "SMPagesExtension.class.php", true);
-
- // Vores indholdsside-udvidelse udgøres af denne klasse.
- // Bemærk at klassen får et unikt navn, ved at starte klasse-navnet
- // med navnet på vores udvidelse (HelloWorld)
- class HelloWorldContentPageExtension extends SMPagesExtension
- {
- // Den eneste funktion der findes på en indholdsside-udvidelse er Render().
- // Den har til formål at udskrive det som brugeren skal se. Det kan være alt
- // fra simpel tekst til en avanceret applikation som eksempelvis et forum.
- public function Render()
- {
- $argument = $this->argument; // Indeholder Lille, Mellem eller Stor.
-
- // Denne indholdsside-udvidelse udskriver en rød boks i forskellige
- // størrelser, afhængig af værdien i $argument.
-
- $width = 0;
- $height = 0;
-
- if ($argument === "Lille")
- {
- $width = 100;
- $height = 25;
- }
- else if ($argument === "Mellem")
- {
- $width = 200;
- $height = 50;
- }
- else if ($argument === "Stor")
- {
- $width = 300;
- $height = 75;
- }
-
- $udskriv = "<div style=\"width: " . $width . "px; height: " . $height . "px; background-color: #DD0000\"> </div>";
- return $udskriv;
- }
- }
-
- ?>
metadata.xml.php- <?xml version="1.0" encoding="ISO-8859-1"?>
- <entries>
- <entry key="Title" value="Hello World (test)" />
- <entry key="Description" value="Dette er en lille test-udvidelse" />
- <entry key="Author" value="Dit navn" />
- <entry key="Company" value="Evt. dit firmanavn" />
- <entry key="Website" value="http://min-hjemmeside.dk" />
- <entry key="Email" value="post@min-hjemmeside.dk" />
- <entry key="Version" value="1" />
- <entry key="Dependencies" value="" />
- <entry key="Notes" value="" />
- </entries>
Test nu den nye udvidelse. Gå til Sitemagic CMS i en webbrowser. I menuen dukker et eller flere nye links op, afhængig af om du er logget ind eller ej. Prøv at trykke på de nye links for at se udvidelsen udskrive nyt indhold. Bemærk også at der i URL'en står ?SMExt=HelloWorld - altså navnet på vores udvidelse, som dermed bliver Main Extension.
Prøv også at indsætte den nye indholdsside-udvidelse på en af de eksisterende indholdssider. Læs hvordan i
guiden til Sitemagic CMS (se listen over knapper i redigerings-programmet nederst på siden).
Vores Hello World eksempel er ganske simpelt, idet der kun udskriver tekst og HTML kode. Det er dog muligt at lave langt mere avanceret funktionalitet, hvilket Sitemagic CMS i sig selv vidner om, da al funktionalitet bestå i udvidelser og indholdsside-udvidelser.
Udvikling af gæstebog
Lad os nu tage hul på at lave vores gæstebog. Denne vil blive lidt mere avanceret, idet vi ser på hvordan GUI-biblioteket benyttes til at skabe tekst-felter og knapper, hvordan database-funktionaliteten gør det let at gemme og indlæse data, og hvordan sprogfilerne kan bruges til at skabe internationale udvidelser.
Vi starter med at oprette de nødvendige filer. Opret mappen SMComments under mappen extensions. I denne mappe oprettes:
- Opret de samme filer som i Hello World eksempelet.
- Opret mappen Languages med to underliggende filer: da.xml og en.xml (dansk og engelsk)
- Opret filerne SMComments.classes.php (data-lag) og tables.sql (tabel-definition til Sitemagic CMS Enterprise)
Vi vil i denne omgang skabe "smuk" seperation mellem layout og data. Det betyder at vi laver seperate klasser til håndtering af data (SMComments.classes.php) og den grafiske del (ContentPageExtension.class.php)
Denne udvidelse vil være at finde på den officielle sektion med
udvidelser til Sitemagic CMS. Hvis du vil have fat i kodefilerne, så hent dog i stedet den vedhæftede udgave her fra udvikleren.dk, da den indeholder alle kommentarerne som vist nedenfor.
Main.class.phpI denne fil registrerer vi vores nye indholdsside-udvidelse i udvidelsen SMPages
- <?php
-
- // Læg mærke til at klassen har samme navn som udvidelsens mappe (SMComments)
- class SMComments extends SMExtension
- {
- private $smPagesExists = false;
- private $lang = null;
-
- public function PreInit()
- {
- // Smid en fejl hvis udvidelsen forsøges afviklet alene (Dedicated Execution Mode).
- // Læs mere om Execution Mode her: http://sitemagic.org/dev/ExtLifeCycle.html
- if ($this->context->GetExecutionMode() === SMExecutionMode::$Dedicated)
- throw new Exception("Dedicated execution mode not supported");
- }
-
- public function Init()
- {
- // Import udvidelsen SMPages.
- // Funktionen returnerer True hvis udvidelsen er installeret, ellers False.
- $this->smPagesExists = SMExtensionManager::Import("SMPages", "SMPages.classes.php");
- }
-
- public function InitComplete()
- {
- if ($this->smPagesExists === true) // Fortsæt hvis SMPages er installeret
- {
- // Hvis brugeren er ved at indsætte en indholdsside-udvidelse ("mini-udvidelse"),
- // så registerer vi vores indholdsside-udvidelse, så den kan vælges i listen.
- // Læs mere om indholdsside-udvidelser her: http://sitemagic.org/dev/ExtSMPages.html
- // Indholdsside-udvidelsen registreres med en kategori-titel som indholdsside-udvidelsen
- // vises under, en titel til selve indholdsside-udvidelsen, navnet på udvidelsen som
- // indholdsside-udvidelsen ligger i (SMComments), navnet på filen som udgør indholdsside-udvidelsen
- // (ContentPageExtension.class.php), navnet på klassen som udgør indholdsside-udvidelsen
- // (SMCommentsContentPageExtension), et valgtfrit argument (tomt) samt forventet højde og bredde
- // på indholdsside-udvidelsen.
- if (SMPagesExtensionList::GetInstance()->GetReadyState() === true)
- SMPagesExtensionList::GetInstance()->AddExtension($this->getTranslation("Title"), $this->getTranslation("CommentBox"), "SMComments", "ContentPageExtension.class.php", "SMCommentsContentPageExtension", "", 350, 140);
- }
- }
-
- // Funktion til at hente oversættelser fra sprogfilerne.
- // Hvis brugeren har valgt Dansk da han/hun loggede ind, returneres
- // oversættelser på dansk. Hvis Engelsk blev valgt, returneres engelske tekster.
- private function getTranslation($key)
- {
- SMTypeCheck::CheckObject(__METHOD__, "key", $key, SMTypeCheckType::$String);
-
- if ($this->lang === null)
- $this->lang = new SMLanguageHandler("SMComments");
-
- return $this->lang->GetTranslation($key);
- }
- }
-
- ?>
ContentPageExtension.class.phpI denne fil udskriver vi selve indholdsside-udvidelsen.
- <?php
-
- SMExtensionManager::Import("SMPages", "SMPagesExtension.class.php", true); // Indeholder klassen SMPagesExtension
- require_once(dirname(__FILE__) . "/SMComments.classes.php"); // Indeholder vores data-lag
-
- // Bemærk at navnet på klassen begynder md navnet på udvidelsen (SMComments).
- // Dette er for at skabe et unikt klasse-navn som ikke skaber konflikter.
- class SMCommentsContentPageExtension extends SMPagesExtension
- {
- private $lang; // Variabel til sprog-håndtering
- private $msg; // Variabel til fejl/succes-besked
-
- private $uid; // Variabel til instans-unikt ID
-
- private $txtName; // Variabel til tekst-felt til indtastning af navn
- private $txtComment; // Variabel til tekst-felt til indtastning af kommentar
- private $cmdSubmit; // Variabel til knap til indsendelse af kommentaren
-
- // Variabel til associativt array bestående af kommentar-objekter
- // og tilhørende slette-knapper, som vises når brugeren er logget ind i kontrolpanelet.
- private $comments;
-
- // konstruktøren på SMPagesExtension (som vi arver fra)
- // overskrives. Læs mere om basis-klassen SMPagesExtension
- // her: http://sitemagic.org/dev/ExtSMPages.html
- public function __construct(SMContext $context, $pageId, $instanceId, $arg)
- {
- SMTypeCheck::CheckObject(__METHOD__, "pageId", $pageId, SMTypeCheckType::$String);
- SMTypeCheck::CheckObject(__METHOD__, "instanceId", $instanceId, SMTypeCheckType::$Integer);
- SMTypeCheck::CheckObject(__METHOD__, "arg", $arg, SMTypeCheckType::$String);
-
- // Variablerne på klassen er defineret i SMPagesExtension (som der arves fra)
- $this->context = $context; // Objekt der fx giver adgang til hjemmesidens design-skabelon
- $this->pageId = $pageId; // Unikt ID på siden som indeholder SMComments-udvidelsen
- $this->instanceId = $instanceId; // Unikt ID på en bestemt instans af SMComments-udvidelsen
- $this->argument = $arg; // Et valgfrit argument som kan registreres sammen med udvidelsen (benyttes ikke til denne udvidelse)
-
- $this->lang = new SMLanguageHandler("SMComments"); // Skaber sprog-objekt
- $this->msg = "";
-
- $this->uid = "SMComments" . $this->instanceId; // Helt unikt ID (til GUI-kontroller) for denne instans af indholdsside-udvidelsen
-
- $this->comments = null;
-
- $this->createControls(); // Skab alle GUI-kontroller (indtastningsfelter + knapper)
- $this->handlePostBack(); // Modtag eventuelle data (kommentarer) fra brugeren, og registrer klik på knapper
- $this->loadData(); // Indlæs data (tidligere indsendte kommentarer)
- }
-
- // Denne funktion skaber de GUI-kontroller vi har brug for.
- // Dvs. indtastningsfelter og knapper. GUI-kontrollerne
- // udskrives i funktionen Render().
- private function createControls()
- {
- // Et indtastningsfelt skabes.
- // Klassen SMInput repræsenterer alle input-typerne (indtastningsfelt,
- // checkbox, radio-button, upload-felt osv). Det første argument skal være
- // et unikt ID (bemærk at det starter med navnet på udvidelsen), det andet
- // argument er typen af input-kontrol (tekst-felt).
- // Læs mere om SMInput her: http://sitemagic.org/dev/GuiInput.html
- $this->txtName = new SMInput($this->uid . "Name", SMInputType::$Text);
- $this->txtName->SetAttribute(SMInputAttributeText::$Style, "width: 150px"); // Sæt bredde til 150 pixels
- $this->txtName->SetAttribute(SMInputAttributeText::$MaxLength, "30"); // Max antal tegn sættes til 30
-
- // Her skabes også en tekst-boks, men af den såkaldte Area-type, som giver
- // mulighed for indtastning af flere linjer tekst.
- $this->txtComment = new SMInput($this->uid . "Comment", SMInputType::$Textarea);
- $this->txtComment->SetAttribute(SMInputAttributeText::$Style, "width: 250px; height: 70px"); // Sæt bredde og højde
- $this->txtComment->SetAttribute(SMInputAttributeTextarea::$MaxLength, "1000"); // Max antal tegn sættes til 1000
-
- // Her skabes en knap som bruges til at indsende kommentaren.
- // Knappen skal ligesom alt andet også have et unikt ID.
- $this->cmdSubmit = new SMLinkButton($this->uid . "Submit");
- $this->cmdSubmit->SetIcon(SMImageProvider::GetImage(SMImageType::$Save)); // Her tilføjer vi et ikon til knappen
- $this->cmdSubmit->SetTitle($this->lang->GetTranslation("Submit")); // Her tilføjer vi en tekst til knappen
- }
-
- // Denne funktion tjekker om brugeren klikker på en knap
- // (fx submit-knappen for at gemme en kommentar). Hvis dette
- // er tilfældet hentes navn og kommentar, og gemmes i systemet.
- private function handlePostBack()
- {
- // Funktionen GetForm() på context-objektet giver adgang til en
- // formular på hjemmesiden, som bruges til at sende data
- // til serveren. Metoden PostBack() på denne formular returnerer
- // True, hvis brugeren har sendt data (fx ved at klikke på en knap)
- if ($this->context->GetForm()->PostBack() === true)
- {
- // Her tjekker vi om brugeren trykkede på submit-knappen.
- // Hvis dette er tilfældet, returnerer funktionen
- // PerformedPostBack() True.
- if ($this->cmdSubmit->PerformedPostBack() === true)
- {
- // Først sikrer vi at brugeren har udfyldt navn- og kommentar-felt
-
- if ($this->txtName->GetValue() === "" || $this->txtComment->GetValue() === "")
- {
- $this->msg = $this->lang->GetTranslation("MissingData");
- return;
- }
-
- // Nu tjekker vi at antallet af indtastede tegn ikke overstiger vores max-begrænsninger.
-
- if (strlen($this->txtName->GetValue()) > 30)
- {
- $this->msg = $this->lang->GetTranslation("NameLengthExceeded");
- return;
- }
-
- if (strlen($this->txtComment->GetValue()) > 1000)
- {
- $this->msg = $this->lang->GetTranslation("CommentLengthExceeded");
- return;
- }
-
- // Brugerens kommentar oprettes og gemmes i systemet
-
- // Bemærk funktionen SMRandom::CreateGuid() som skaber et unikt ID.
- // Læs mere herom på: http://sitemagic.org/dev/ApiRandom.html
- $comment = new SMCommentsItem($this->pageId, $this->instanceId, SMRandom::CreateGuid(), $this->txtName->GetValue(), $this->txtComment->GetValue());
- $result = $comment->CommitPersistent(); // Returnerer False hvis kommentaren ikke kunne gemmes
-
- if ($result === false)
- {
- $this->msg = $this->lang->GetTranslation("UnknownError");
- return;
- }
-
- // Gem en besked om at alt gik godt og rens formularen for den gamle tekst
-
- $this->msg = $this->lang->GetTranslation("CommentSaved");
- $this->clearForm();
- }
- else
- {
- // Tjekker om der blev trykket på en af kommentarernes slet-knapper
- // hvis brugeren er logget ind.
-
- if (SMAuthentication::Authorized() === true)
- {
- $this->loadData(); // Vi indlæser først kommentarerne sammen med slet-knapperne
-
- // Vi gennemløber nu alle slet-knapper, og "spørger" om de er blevet klikket på
-
- $comment = null;
- for ($i = 0 ; $i < count($this->comments) ; $i++)
- {
- $comment = $this->comments[$i];
-
- // Hvis en kommentars slet-knap blev brugt, slettes kommentaren
- if ($comment["cmdDelete"]->PerformedPostBack() === true)
- {
- $comment["comment"]->DeletePersistent(); // Slet fra databasen
- unset($this->comments[$i]); // Slet fra arrayet med kommentarer
- break;
- }
- }
- }
- }
- }
- }
-
- // Denne funktion indlæser alle de tidligere indsendte kommentarer.
- // Dataene udskrives i funktionen Render().
- private function loadData()
- {
- // Afbryd hvis kommentarerne allerede er blevet indlæst,
- // hvilket er tilfældet hvis en slet-knap er blevet brugt.
- if ($this->comments !== null)
- return;
-
- // Hent alle kommentarer som tilhører siden og den specifikke instans af kommentar-
- // udvidelsen. Kommentarerne returnereres som et array af SMCommentsItem objekter.
- $comments = SMCommentsLoader::GetComments($this->pageId, $this->instanceId);
-
- // Kommentarerne overføres til et nyt array som også indeholder en slet-knap,
- // hvis administratoren er logget ind i kontrolpanelet.
-
- $this->comments = array();
- $cmdDelete = null;
-
- foreach ($comments as $comment)
- {
- // Opret kun slet-knap hvis brugeren er logget ind i kontrolpanelet
- if (SMAuthentication::Authorized() === true)
- {
- $cmdDelete = new SMLinkButton($this->uid . "Delete" . $comment->GetCommentId()); // Unikt ID tildeles
- $cmdDelete->SetIcon(SMImageProvider::GetImage(SMImageType::$Delete)); // Slet-ikon tildeles
- $cmdDelete->SetTitle($this->lang->GetTranslation("Delete")); // Tekst tildeles
- $cmdDelete->SetOnclick("if (SMMessageDialog.ShowConfirmDialog('" . $this->lang->GetTranslation("DeleteWarning") . "') === false) { return false; }"); // Her beder vi brugeren bekræfte sletning hvis knappen benyttes
- }
-
- // Tildel kommentar-objekt og slet-knap til arrayet $this->comments på klassen
- $this->comments[] = array(
- "comment" => $comment,
- "cmdDelete" => $cmdDelete
- );
- }
- }
-
- // Denne funktion bruges til at rense indtastningsfelterne
- private function clearForm()
- {
- $this->txtName->SetValue("");
- $this->txtComment->SetValue("");
- }
-
- // Funktionen Render udskriver de eksisterenden kommentarer
- // samt indtastningsfelter så brugeren kan indsende en ny kommentar.
- public function Render()
- {
- $output = "";
-
- // Eventuel meddelelse udskrives (fx at kommentaren blev gemt)
-
- if ($this->msg !== "")
- $output .= "<i>" . $this->msg . "</i><br><br>";
-
- // Nedenfor udskrives GUI-kontrollerne i en formular som
- // den besøgende på hjemmesiden kan udfylde med en ny kommentar.
-
- $output .= "
- <table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">
- <tr>
- <td style=\"width: 100px\">" . $this->lang->GetTranslation("Name") . "</td>
- <td style=\"width: 250px\">" . $this->txtName->Render() . "</td>
- </tr>
- <tr>
- <td style=\"width: 100px\">" . $this->lang->GetTranslation("Comment") . "</td>
- <td style=\"width: 250px\">" . $this->txtComment->Render() . "</td>
- </tr>
- <tr>
- <td style=\"width: 100px\"> </td>
- <td style=\"width: 250px\"> </td>
- </tr>
- <tr>
- <td style=\"width: 100px\"> </td>
- <td style=\"width: 250px\"><div style=\"text-align: right\">" . $this->cmdSubmit->Render() . "</div></td>
- </tr>
- </table>
- ";
-
- // Nedenfor udskrives alle kommentarerne. Hvis brugeren er logget ind
- // i kontrolpanlet, udskrives også en knap til at slette en kommentar.
-
- foreach ($this->comments as $comment)
- {
- $output .= "
- <br>
- <hr style=\"height: 1px; border-bottom-style: none\">
- " . (($comment["cmdDelete"] !== null) ? $comment["cmdDelete"]->Render() . " " : "") . "
- <b>" . $comment["comment"]->GetName() . "</b> (" . date($this->lang->GetTranslation("DateTimeFormat"), $comment["comment"]->GetTimeStamp()) . ")
- <hr style=\"height: 1px; border-bottom-style: none\">
- " . nl2br($comment["comment"]->GetComment()) . "
- <br>
- ";
- }
-
- return $output;
- }
- }
-
- ?>
SMComments.classes.phpDenne fil indeholder data-laget, dvs. den rå behandling af data, samt adgangen til databasen.
- <?php
-
- // En instans af denne klasse repræsenterer netop én kommentar
- // som er skrevet på en bestemt side, med et bestemt kommentar-felt
- // (måske er der flere kommentar-felter på den samme side).
- class SMCommentsItem
- {
- // Disse variabler bruges til at gemme data om en kommentar
- private $pageId; // String (Guid)
- private $instanceId; // Integer
- private $commentId; // String (Guid)
- private $name; // String
- private $comment; // String
- private $timestamp; // Integer
-
- // Konstruktøren kaldes når et nyt kommentar-objekt skabes.
- // $pageId: Et unikt ID for den side som kommentaren er skrevet på
- // $instanceId: Et unikt ID for den indholdsside-udvidelse som kommentaren er skrevet i
- // $commentId: Et unikt ID der identificerer en kommentar
- // $name: Navnet på brugeren som har skrevet en kommentar
- // $comment: Selve kommentaren
- // $timestamp: Tidspunktet kommentaren oprettes
- public function __construct($pageId, $instanceId, $commentId, $name = "", $comment = "", $timestamp = -1)
- {
- // Her valideres variablernes typer for at sikre mod klassiske kode-fejl
- // i PHP som er "dynamically typed" - læs mere her: http://sitemagic.org/dev/ApiTypes.html
- SMTypeCheck::CheckObject(__METHOD__, "pageId", $pageId, SMTypeCheckType::$String);
- SMTypeCheck::CheckObject(__METHOD__, "instanceId", $instanceId, SMTypeCheckType::$Integer);
- SMTypeCheck::CheckObject(__METHOD__, "commentId", $commentId, SMTypeCheckType::$String);
- SMTypeCheck::CheckObject(__METHOD__, "name", $name, SMTypeCheckType::$String);
- SMTypeCheck::CheckObject(__METHOD__, "comment", $comment, SMTypeCheckType::$String);
- SMTypeCheck::CheckObject(__METHOD__, "timestamp", $timestamp, SMTypeCheckType::$Integer);
-
- // Dataene gemmes på selve klassen.
- $this->pageId = $pageId;
- $this->instanceId = $instanceId;
- $this->commentId = $commentId;
- $this->name = $name;
- $this->comment = $comment;
- $this->timestamp = $timestamp;
- }
-
- // I det følgende defineres set- og get-funktioner til dataene,
- // så værdierne kan hentes og ændres i den grafiske brugerflade.
-
- public function GetPageId()
- {
- return $this->pageId;
- }
-
- public function GetInstanceId()
- {
- return $this->instanceId;
- }
-
- public function GetCommentId()
- {
- return $this->commentId;
- }
-
- public function SetName($value)
- {
- SMTypeCheck::CheckObject(__METHOD__, "value", $value, SMTypeCheckType::$String);
- $this->name = $value;
- }
-
- public function GetName()
- {
- return $this->name;
- }
-
- public function SetComment($value)
- {
- SMTypeCheck::CheckObject(__METHOD__, "value", $value, SMTypeCheckType::$String);
- $this->comment = $value;
- }
-
- public function GetComment()
- {
- return $this->comment;
- }
-
- public function GetTimeStamp()
- {
- return $this->timestamp;
- }
-
- // Database functions
- // Her defineres funktionaliteten som gør det muligt at gemme og opdatere kommentarer i databasen.
- // Læs meget mere om brugen af data-kilder i Sitemagic CMS: http://sitemagic.org/dev/ApiDS.html
-
- // Denne funktion gemmer en ny kommentar, eller opdaterer den hvis den allerede findes
- public function CommitPersistent()
- {
- $db = new SMDataSource("SMComments"); // Åben data-filen (eller database-tabellen)
- $kvc = new SMKeyValueCollection(); // Opret et array til dataene (understøtter kun strings som data)
-
- $this->timestamp = time();
-
- if (self::GetPersistent($this->commentId) !== null) // Opdater eksisterende kommentar
- {
- // Bemærk: Denne udvidelse benytter ikke selv muligheden for at opdatere kommentarer.
- // Men det kunne tænkes at et andet modul vil gøre det muligt at administrere
- // kommentarer - derfor stiller vi funktionaliteten til rådighed. Det er altid en god
- // ide at gøre det muligt for andre at bygge videre på ens egen funktionalitet.
-
- // Indsæt data som skal opdateres i arrayet
- $kvc["name"] = $this->name;
- $kvc["comment"] = $this->comment;
- $kvc["timestamp"] = (string)$this->timestamp;
- $updateCount = $db->Update($kvc, "commentid = '" . $this->commentId . "'"); // Opdater dataene - antal opdaterede elementer returneres
-
- if ($updateCount === 0)
- return false;
- }
- else
- {
- // Indsæt data som skal gemmes i arrayet
- $kvc["pageid"] = $this->pageId;
- $kvc["instanceid"] = (string)$this->instanceId;
- $kvc["commentid"] = $this->commentId;
- $kvc["name"] = $this->name;
- $kvc["comment"] = $this->comment;
- $kvc["timestamp"] = (string)$this->timestamp;
- $db->Insert($kvc); // Gem dataene
- }
-
- return true;
- }
-
- // Denne funktion sletter kommentaren permanent
- public function DeletePersistent()
- {
- $db = new SMDataSource("SMComments");
- $deleteCount = $db->Delete("commentid = '" . $this->commentId . "'");
-
- if ($deleteCount === 0)
- return false;
-
- return true;
- }
-
- // Dette er en statisk funktion som gør det muligt at hente en kommentar fra databasen.
- public static function GetPersistent($commentId)
- {
- SMTypeCheck::CheckObject(__METHOD__, "commentId", $commentId, SMTypeCheckType::$String);
-
- $ds = new SMDataSource("SMComments");
- $records = $ds->Select("*", "commentid = '" . $commentId . "'");
-
- // Hvis ingen data blev fundet, returner vi null
- if (count($records) === 0)
- return null;
-
- $record = $records[0];
-
- // Her skaber vi et kommentar-objekt med de fundne data og returnerer det.
- // Alle data i $record objektet er af typen String - men husk at konstruktøren
- // i klassen SMCommentsItem forventer at nogle af argumenterne er af typen Integer
- // - derfor konverteres disse værdier således: (int)$record["xyz"]
- return new SMCommentsItem($record["pageid"], (int)$record["instanceid"], $record["commentid"], $record["name"], $record["comment"], (int)$record["timestamp"]);
- }
- }
-
- class SMCommentsLoader
- {
- // Denne funktion returnerer alle kommentarer skrevet for en bestemt side og et bestemt kommentar-felt (indholdsside-udvidelse)
- public static function GetComments($pageId, $instanceId)
- {
- SMTypeCheck::CheckObject(__METHOD__, "pageId", $pageId, SMTypeCheckType::$String);
- SMTypeCheck::CheckObject(__METHOD__, "instanceId", $instanceId, SMTypeCheckType::$Integer);
-
- // Data hentes ud, sorteret efter tidspunkt (timestamp)
- $ds = new SMDataSource("SMComments");
- $records = $ds->Select("*", "pageid = '" . $pageId . "' AND instanceid = '" . $instanceId . "'", "timestamp DESC");
-
- // Omdan alle records til rigtige kommentar-objekter og returner
-
- $comments = array();
-
- foreach ($records as $record)
- $comments[] = new SMCommentsItem($record["pageid"], (int)$record["instanceid"], $record["commentid"], $record["name"], $record["comment"], (int)$record["timestamp"]);
-
- return $comments;
- }
- }
-
- ?>
Languages/da.xmlFilen da.xml i mappen Languages indeholder alle danske ord og tekster til udvidelsen.
- <?xml version="1.0" encoding="ISO-8859-1"?>
- <entries>
- <entry key="Title" value="Kommentarer" />
- <entry key="CommentBox" value="Kommentarboks" />
- <entry key="Name" value="Navn" />
- <entry key="Comment" value="Kommentar" />
- <entry key="Submit" value="Send" />
- <entry key="Delete" value="Slet" />
- <entry key="DeleteWarning" value="Bekræft venligst sletning" />
- <entry key="DateTimeFormat" value="d-m-Y H:i:s" />
- <entry key="MissingData" value="Udfyld venligst alle felter" />
- <entry key="NameLengthExceeded" value="Navnet kan højest indeholde 30 karakterer" />
- <entry key="CommentLengthExceeded" value="Kommentaren kan højest indeholde 1000 karakterer" />
- <entry key="UnknownError" value="En ukendt fejl opstod" />
- <entry key="CommentSaved" value="Kommentaren blev gemt" />
- </entries>
Languages/en.xmlFilen en.xml i mappen Languages indeholder alle engelske ord og tekster til udvidelsen.
- <?xml version="1.0" encoding="ISO-8859-1"?>
- <entries>
- <entry key="Title" value="Comments" />
- <entry key="CommentBox" value="Comment box" />
- <entry key="Name" value="Name" />
- <entry key="Comment" value="Comment" />
- <entry key="Submit" value="Send" />
- <entry key="Delete" value="Delete" />
- <entry key="DeleteWarning" value="Please confirm deletion" />
- <entry key="DateTimeFormat" value="Y-m-d H:i:s" />
- <entry key="MissingData" value="Please fill out all fields" />
- <entry key="NameLengthExceeded" value="Name can contain a maximum of 30 characters" />
- <entry key="CommentLengthExceeded" value="Comment can contain a maximum of 1000 characters" />
- <entry key="UnknownError" value="An unknown error occured" />
- <entry key="CommentSaved" value="Comment saved" />
- </entries>
metadata.xml.phpFilen indeholder lidt generel information om udvidelsen så som navn, forfatter og versionsnummer. Disse informationer bruges af Sitemagic CMS til at tjekke for nyere versioner af udvidelsen (gælder dog kun for officielle udvidelser udviklet af Sitemagic-teamet).
- <?xml version="1.0" encoding="ISO-8859-1"?>
- <entries>
- <entry key="Title" value="Sitemagic comments extension" />
- <entry key="Description" value="Allows for a commentary field to be inserted into an ordinary content page" />
- <entry key="Author" value="Jimmy Thomsen" />
- <entry key="Company" value="Sitemagic" />
- <entry key="Website" value="http://sitemagic.org" />
- <entry key="Email" value="dev@sitemagic.org" />
- <entry key="Version" value="20100904" />
- <entry key="Dependencies" value="" />
- <entry key="Notes" value="" />
- </entries>
tables.sqlFilen indeholder SQL-koden til at skabe den nødvendige database-tabel til Sitemagic CMS Enterprise. Hvis den almindelige udgave af Sitemagic CMS benyttes, skal denne fil ikke bruges til noget.
- CREATE TABLE IF NOT EXISTS SMComments
- (
- `pageid` varchar(32) DEFAULT NULL,
- `instanceid` integer DEFAULT NULL,
- `commentid` varchar(32) DEFAULT NULL,
- `name` varchar(30) DEFAULT NULL,
- `comment` text DEFAULT NULL,
- `timestamp` integer DEFAULT NULL
- ) ENGINE = InnoDB CHARACTER SET latin1 COLLATE latin1_swedish_ci;
Koden i det foregående udgør altså således vores nye indholdsside-udvidelse (som er vedhæftet denne artikel som SMComments.zip). Vores gæstebog kan nu trækkes ind på en hvilken som helst indholdsside, og giver således de besøgende mulighed for at kommentere indholdet.
Sådan kommer du videre
At beskrive hele Sitemagic frameworket er en stor opgave, og det er på ingen måde dækket af denne korte artikel. Vi kan passende kalde det en smagsprøve. Jeg håber dog at den valgte artikel-form, hvor der tages udgangspunkt i kommenterede kode-eksempler, har lært dig noget, og givet dig mod på flere eksperimenter med Sitemagic CMS.
Det kan anbefales at kigge på koden til nogle af de eksisterende udvidelser. Den medfølgende udvidelse SMLogin er forholdsvis simpel, og derfor et godt udgangspunkt. Er du interesseret i at se endnu en indholdsside-udvidelse, er udvidelsen
Vurdering et godt bud.
Intet slår dog den rå dokumentation. En dags tid eller to spenderet på
http://sitemagic.org/dev vil være godt givet ud. Her skulle du være i stand til at opnå den nødvendige viden for at komme videre.
Har du spørgsmål, kan
forummet på Sitemagic.dk altid bruges. Her kan der spørges til alt lige fra hjælp til opsætning, til råd og vejledning om udvikling af udvidelser.
- God fornøjelse med udvikling til Sitemagic CMS! :-)
Vedhæftede filer:
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (1)
Bemærk at der i koden til gæstebogen er en fejl der potentielt udgør et sikkerhedsproblem. Det er muligt at indsætte JavaScript, som vil blive fortolket på hjemmesiden.
I filen ContentPageExtension.class.php skal foreach-løkken på linje 246 se således ud:
foreach ($this->comments as $comment)
{
$output .= "
<br>
<hr style=\"height: 1px; border-bottom-style: none\">
" . (($comment["cmdDelete"] !== null) ? $comment["cmdDelete"]->Render() . " " : "") . "
<b>" . htmlentities($comment["comment"]->GetName()) . "</b> (" . date($this->lang->GetTranslation("DateTimeFormat"), $comment["comment"]->GetTimeStamp()) . ")
<hr style=\"height: 1px; border-bottom-style: none\">
" . nl2br(htmlentities($comment["comment"]->GetComment())) . "
<br>
";
}
Bemærk at htmlentities(..) er tilføjet ved print af en gæsts navn og besked.
Du skal være
logget ind for at skrive en kommentar.