Nie czepiaj się, chodziło mi o powszechną implementacje Intercepting Filters w wielu, wielu frameworkach. Przykro mi, że nie zrozumiałeś.
Kasjan
14.10.2007, 22:23:11
Cytat(NuLL @ 14.10.2007, 18:23:20 )

A co jesli chcesz operowac na jakis danych zawartych w akcji ?
mam globalne obiekty $get i $post (lub $request) i tylko przez nie (zgodnie z narzucona sobie specyfikacja cms) moge sie odwolywac do $_GET i $_POST (lub $_REQUEST) i moge je edytowac przez plugin.
poza tym plugins::before i plugins::after mozna sobie zautomatyzowac - od czego mamy extends / mozna zrobic dekoratory
Cysiaczek
15.10.2007, 07:48:05
Z mojego punktu widzenia to sa po prostu akcje
przed i akcje
po - niezależnie jak mądrze je nazwać ;p.
Takie rzeczy rozwiązuje sie moim zdaniem na poziomie frameworka, a nie CMS.
@Null - da się nawet taki bajer zobić, że możesz filtrować zmienne w akcji. Oczywiście nie lokalne zmienne metody, tylko zmienne, do których akcja się odwołuje. Z tego, co pamiętam, bo w swoim FW masz.
<?php
$this->post->zmienna;
?>
Jesteś w stanie przefiltrować zawartość danych POST pod kątem konkretnej akcji niejako z zewnątrz - bez jawnego wywołania kodu filtrujacego wewnątrz akcji, a zwyczajnie dodajac jakiś plik z informacją, co i jak ma zostać przefiltrowane.
Pozdrawiam.
gamecreator
6.11.2007, 01:09:33
Najpierw trzeba by jedną rzecz doprecyzować:
Są
wtyczki [plugins] i są
rozszerzenia [extensions]. Rozszerzenia to rzecz trochę bardziej ogólna, bo pozwalają na różne sposoby rozszerzać kod główny: np. dodając nowe inlcudy, dziedzicząc klasy interfejsów, dodając pliki językowe, szablony, filtry itp. Wtyczki to pewien podzbiór rozszerzeń.
Pluginy to inaczej
wtyczki.
A jeśli jest
wtyczka, musi też być i
gniazdko 
Gniazdkiem są tzw. "hooki" [haki? miejsca zaczepienia?], czyli przewidziane wcześniej miejsca w kodzie głównym, do których można podczepiać kod wtyczek. Tak więc jeśli chcemy mieć możliwość dołączania pluginów w skrypcie, to musimy od począku pisać skrypt pod tym kątem i zostawiać "hooki" dla wywołań pluginów w miejscach, gdzie przewidujemy jakieś możliwości rozszerzania. Jeśli piszemy w taki sposób, możemy łatwo dodawać pluginy, które podczepią się do tych miejsc i coś zrobią. Jednak kod główny [core] pozostanie niezmieniony.
@faster: Dobrze kombinujesz. Co do Twoich wątpliwości, jak można rozszerzyć działanie kodu głównego bez zmieniania go, odpowiedź jest prosta: polimorfizm. Jeśli kod główny jest napisany w taki sposób, by działał na ogólnych interfejsach, zamiast na konkretnych obiektach, można bardzo łatwo rozszerzyć system o nowe klasy, które będą pasować do wywołań tego głównego kodu i będą nadpisywać [nie dosłownie, lecz poprzez polimorfizm] jego funkcje. Hooki w stylu before() i after() to najprostszy przykład czegoś takiego. Większe możliwości daje jednak dziedziczenie i nadpisywanie metod interfejsów w klasach pochodnych [w innych językach zwie się to "funkcje wirtualne" lub "polimorficzne"].
Jeśli jednak chcemy zmieniać każdą możliwą część systemu, to system od podstaw musi być w taki sposób napisany, by wszystkie jego składniki były pluginami, a główny kod zajmowałby się jedynie ich ładowaniem i rejestrowaniem powiązań między nimi. To jest już trudniejsze do zrobienia [choć nie niemożliwe

] i wymaga dobrego przemyślenia. Może też być mniej wydajne, bo praktycznie wszelkie wywołania musiałyby być dispatchowane w tablicy zarejestrowanych usług.
I tu przyszedł mi do głowy jeszcze jeden problem: baza danych. Często jest tak, że pluginy także potrzebują przechowywać jakieś informacje w bazie danych. O ile dodanie dodatkowej tabeli z kluczami obcymi jeszcze jakoś da się w miarę łatwo zrobić z poziomu pluginu, o tyle już np. modyfikacja struktury istniejących tabel może być trudna, o ile wogóle ma to jakiś sens. Wie ktoś może, jak rozwiązywane jest dodawanie pluginów z rozszerzaniem struktury bazy danych? Bo aktualnie istniejące bazy danych są raczej mało "polimorficzne" ;J
P.S.: @nasty, @Athlan: Ale robicie byki, kupcie sobie słowniki ;P
deirathe
20.11.2007, 15:58:49
skoro mowa o rozszerzeniach to czy widzicie jakieś bezpieczne sposoby na instalacje takowych rozszerzeń z poziomu użytkownika. Powiedzmy np że wchodzi do panelu w opcje rozszerzenia i sobie wyklikuje co mu tam potrzeba i voila.
splatch
20.11.2007, 22:07:10
Pokusiłem się o wklepanie odrobiny kodu. Jest on niekompletny, aczkolwiek daje pogląd na całą sprawę od strony źródeł. Całość oparta mniej więcej stanowi wyciąg ze źródeł
OSGi i
Eclipse przepisany do PHP.
Definicja "paczki", części aplikacji<?php
/**
* Paczka działająca w otoczeniu aplikacji. Obiekty tej klasy są tworzone
* przez framework a nie przez użytkownika. Nie musi on rozszeżać tej klasy
* jest ona tylko zestawem informacji co się dzieje w runtime.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
class Bundle {
/**
* Pobranie usług jakie chce używać i udostępniać paczka.
*
* @return object[] Lista usług, bez określonego interfejsu.
*/
function getRegisteredServices() {
}
/**
* Pobranie nagłówków z informacjami na temat paczki.
*
* @return Header Lista z unikalnymi nagłówkami.
*/
function getHeaders() {
}
/**
* Pobranie informacji o stanie paczki.
*
* @return stan paczki (któraś z wartości stałych z IState).
*/
function getState();
}
?>
Informacje o nagłówkach trzymane np w pliku .ini<?php
/**
* Nagłówek z infomacjami na temat wymagań paczki.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
/**
* Nazwa nagłówka.
*
* @return string Najlepiej z zakresu stałych ISupportedHeaders.
*/
function getName() {}
/**
* Wartość nagłówka.
*
* @return string
*/
function getValue() {}
}
/**
* Lista domyślnych nagłówków, jakie są domyślnie wspierane.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface ISupportedHeaders {
/**
* Nazwa nagłówka z informacjami o zależnościach paczki.
* W wymaganiach można podać również wersję w jakiej paczka
* powinna występować. Brak informacji o wersji oznacza, że
* paczka współpracuje z dowolną wersją.
*
* require-bundle = pl.dywicki.db: 0.5, pl.dywicki.view: 1.1
*/
const REQUIRE_BUNDLES = "require-bundle";
/**
* Informacje o dostawcy paczki.
*
* vendor-name = Łukasz Dywicki
* vendor-url = <a href=\"http://dywicki.pl\" target=\"_blank\">http://dywicki.pl</a>
* vendor-organization = Code-House.org
*/
const VENDOR_NAME = "vendor-name";
const VENDOR_URL = "vendor-url";
const VENDOR_ORGANIZATION = "vendor-organization";
/**
* Informacje o paczce.
*
* bundle-name = pl.dywicki.view.explorer
* bundle-version = 0.5.13
*/
const BUNDLE_NAME = "bundle-name";
const BUNDLE_VERSION = "bundle-version";
}
?>
Kontekst w jakim działa aplikacja, chodzi tu głównie o warstwę usług a nie request response etc.
<?php
/**
* Kontekst działania rozszeżenia.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface IBundleContext {
/**
* Pobranie jakiejś usługi.
*
* @return object Interfejs nie jest określony
*/
function getServices();
// Fragment z listenerami do propagacji informacji.
function addFrameworkListener(IFrameworkListener $listener);
function removeFrameworkListener(IFrameworkListener $listener);
function addBundleListener(IBundleListener $listener);
function removeBundleListener(IBundleListener $listener);
}
?>
Definicja pluginu - jedyne co od niego wymagamy to start i stop, opcjonalnie install, uninstall.
<?php
/**
* Rozszeżenie jakiegoś extension pointa.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface IPlugin {
/**
* Uruchomienie pluginu.
*
* @param $context Kontekst w jakim działa plugin.
*/
function start(IBundleContext $context);
/**
* Zatrzymanie pluginu
*
* @param $context Kontekts, w którym działał plugin.
*/
function stop(IBundleContext $context);
}
?>
Warunki dla pluginów<?php
/**
* Interfejs reprezentujący warunek, jaki powinien spełniać plugin.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface ICriteria {
/**
* Sprawdzenie czy plugin jest "ok".
*
* @param $plugin Implementacja rozszeżenia.
*/
function isValid(IPlugin $plugin);
}
// przykładowa implementacja
class InstanceOfCriteria implements ICriteria {
public function __construct(string $name) {
$this->interfaceName = $name;
}
function isValid(IPlugin $plugin) {
return ($plugin instanceof $this->interfaceName);
}
}
?>
Hook = extension point - czyli miejsce, w którym ktoś się wpina przez pluginy
<?php
/**
* Definicja nowego EP.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface IExtensionPoint {
/**
* Nazwa EP (opcjonalna).
*
* @return string.
*/
function getName();
/**
* Identyfikator EP (obowiązkowy)
*
* @return Unikalny identyfikator EP.
*/
function getExtensionPointId();
/**
* Warunki, jakie muszą spełnić pluginy, by być uznane
* za poprawne rozszeżenia danego EP.
*
* @return ICriteria[] Lista warunków.
*/
function getCriteria();
}
?>
Rejestr rozszerzeń - czyli coś, w czym wszystkie EP są dodawane, usuwane i przetrzymywane.
<?php
/**
* Centralny rejestr trzymający listę extension pointów.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface IExtensionRegistry {
/**
* Dodanie nowej definicji EP do rejestru.
*
* @param $point
*/
function registerExtensionPoint(IExtensionPoint $point);
/**
* Pobranie EP o danym identyfikatorze.
*
* @param $namespace Przestrzeń nazw rozszeżenia (np. pl.dywicki.content)
* @return IExtensionPoint
*/
function getExtensionPoint(string $namespace);
/**
* Pobranie listy wszystkich EP.
*
* @return IExtensionPoint[] Tablica zawierająca EP.
*/
function getExtensionPoints();
/**
* Dodanie listenera nasłuchującego zmian.
*
* @param $listener Ktoś, kto chce dużo wiedzieć.
*/
function addRegistryListener(IRegistryListener $listener);
/**
* Usunięcie listenera, który obserwuje zmiany w rejestrze.
*
* @param $listener Ktoś, kto już nie chce chce dużo wiedzieć.
*/
function removeRegistryListener(IRegistryListener $listener);
}
?>
Stany, w jakich może być paczka (paczka != plugin)
<?php
/**
* Interfejs reprezentujący stan paczki.
*
* @author Łukasz Dywicki <luke@code-house.net>
*/
interface IState {
/**
* Paczka zainstalowana.
*/
const INSTALLED = 0x01;
/**
* Paczka niezainstalowana.
*/
const UNINSTALLED = 0x02;
/**
* Paczka w fazie uruchamiania.
*/
const ACTIVATING = 1;
/**
* Paczka uruchomiona.
*/
const ACTIVE = 2;
/**
* Paczka zatrzymana.
*/
const STOPED = 3;
/**
* Paczka podczas zatrzymywania.
*/
const STOPPING = 4;
}
?>
Babcia@Stefa
5.03.2008, 12:17:15
Moje rozwiązanie jest takie:
Archiwum (np. rar, zip itp.) {
- plik 1
- plik 2
- plik 3
- info.xml
}
Info.xml
<?xml version="1.0"?>
<plugin>
<folders>
<create folder="nazwa folderu"/>
</folders>
<menu>
<menu key="xD" link="page,testplugin"/>
</menu>
<files>
<file unpack="ścieżka wyjściowa" name="nazwa z archiwum"/>
</files>
</files>
</plugin>
Jest ono bardzo proste ;]
Pozdrawiam, Babcia@Stefa
@splatch - myslisz ze daloby sie to wykorzystac w PHP ? Zastanawiam sie jaki narzut kodu i czasu wynikalby z takiego rozwiazania

Dzieki za ten kod - mi ciezko by bylo to wyciagnac a myslalem o tym ostatnio. Zastanawiam sie nad napisaniem jakies prostej aplikacji z tego korzystajacej - ale zobaczymy jak z czasem i czy wogole sie uda
specialplan
11.03.2008, 16:52:28
Podepne sie, by nie zakladac nowego tematu.
Od jakiegos czasu pracuje nad systemem pluginow. W CMS, nad ktorym obecnie spedzam wiele godzin w pracy, poprzez plugin rozumie sie klase (lub ich zbior) odpowiedzialna za jakies dodatkowe, doinstalowalne funkcje (np system newsow, ktory mozna doinstalowac do zrodla i jego funkcjonalnosci beda dostepne w calym silniku). Mam juz dzialajacy instalator i ogolna obsluge takich paczek (usuwanie, aktywowanie, deaktywowanie, startowanie, restartowanie itd). Nie bede sie w to teraz zaglebial...
Stanalem jednak na rozdrozu, jesli chodzi o rejestr funkcjonalnosci. Zalozmy, ze klasa news zawiera kilka metod publicznych, jak np addNews, deleteNews, modifyNews, displayNews itd itp. Jednym z rozwiazan, na jakie wpadlem jest stworzenie z pomoca Reflection API rejestru metod publicznych, ktore dany plugin udostepnia i operowanie na nich w dowolnym miejscu systemu (Factory, Autoloading itd). Czyli rejestruje sobie moje funkcjonalnosci i pozniej, np w warstwie widoku tylko odwoluje sie do danej metody, np PluginManager::dispatch(nazwaPluginu, zarejestrowanaFunkcjonalnosc, argumenty) (to taki luzny bardzo przyklad). Mysle, ze to calkiem wygodne.
Moj PM wpadl jednak na karkolomny pomysl zdynamizowania zarejestrowanych uslug. Chodzi mu po glowie, by w panelu administracyjnym, gdzie wylistowane sa dostepne w rejestrze uslugi, po kliknieciu na dana nazwe metody dla danego pluginu od razu mozna bylo z tego miejsca go obsluzyc. Nie za bardzo wiem jak sie do tego dobrac, poniewaz musialoby to byc super-uniwersalne, jako ze dodawanie newsow rozni sie, powiedzmy od wyswietlenia lokacji na wtyczce Google Maps;] Spedzam drugi dzien na probie rozplanowania jakiegos Buildera formularzy, jednak co chwila wychodza jakies problemy zwiazane z uniwersalizacja takiego systemu.
Probowalem jakies diagramy UML na Decoratorze rozrysowywac, jednak jak dla mnie to ciagle za ogolne dzialanie, by to objac jakos sensownie bez miliona linijek kodu ;]
Jesli ktos rozumie, o co mi chodzi, to moze jakies pomysly wpadna do glowy?:_)
carbolymer
11.03.2008, 23:30:17
Jakiś czas temu naskrobałem sobie nawet dobry plugin system. Jego mechanika działania wygląda tak:
Jest aplikacja PHP zbudowana z kilku-kilkunastu klas.
Jest klasa Matrix - klasa bazowa, z której powinny dziedziczyć te klasy, w których mogły by się wczepiać pluginy.
Jej działanie jest takie: przed (on[nazwaklasy]_pre_[nazwafunkcji]) i po (on[nazwaklasy]_post_[nazwafunkcji]) wywołaniem metody jednej z klas aplikacji jest wywoływana metoda pluginu (metoda pre musi mieć zgodną liczbę argumentów co do funkcjiobsługiwanej - metoda post przyjmuje tylko 1 argument, wartość zwracaną przez funkcję obsługiwaną) o odpowiedniej nazwie która ma możliwość modyfikowania argumentów i wyniku funkcji.
Każda metoda która "chce" być obsługiwana przez pluginy powinna być protected lub private i zaczynać się od _ np.:
<?php
class foo extends Matrix
{
//metoda koniecznie protected lub private poprzedzone '_'
protected function _test($val)
{
echo '<br/>Test val:'.$val.'<br/>'; }
}
?>
Potem przy starcie aplikacji poprostu tworzymy obiekt klasy foo, ładujemy (dziedziczoną metodą z Matrix) plugin - można by zeskanować katalog lub konfig na starcie.
<?php
$bar = new foo();
$bar->loadPlugin('test'); // ładujemy plugin, można załadować tylko raz!
$bar->test(123); // wywołanie metody klasy foo, a zarazem odpowiednich metod pluginu
?>
Kod w całości:
http://carbolymer.ovh.org/wp/?p=18
Sedziwoj
12.03.2008, 09:56:37
@specialplan
A dlaczego interfejsu plugin'u nie dasz w jakimś pliku konfiguracyjnym, po co bawić się w Reflection API, niech plugin sam powie co oferuje.
Wtedy obsługa każdej funkcjonalności też jest zawarta w plugin'ie, bo tak na prawdę tylko ten plugin wie co ma zrobić.
Czyli system news'ów wie jak ma dodać nowego, jak wyświetlić lokalizację też sam plugin wie. System nie powinien zajmować się niczym więcej jak umieszczeniem danych z plugin'a w odpowiednim miejscu i przekazywaniu mu tego czego potrzebuje.
specialplan
12.03.2008, 10:19:59
Klasa dziedziczaca po ReflectionClass sluzy jedynie do pobrania metod publicznych z danej klasy pluginu w celach wylistowania ich w panelu administracyjnym, by mozna bylo z poziomu formularza przypisywac dane funkcjonalnosci pluginu do, chociazby, konkretnych stron widoku. W zasadzie mozna by umiescic te same dane w pliku konfiguracyjnym, ale zdecydowalem sie na tworzenie ich "w locie". W zasadzie system "robi" wszystko, co napisales, wiec chyba przekonam mojego PM, ze nie ma sensu sie bawic w dynamizowanie rejestru.
Framework
FLOW3 (który będzie służyć za bazę dla najnowszego TYPO3) poszedł o krok naprzód w "pluginizacji" aplikacji - używa aspektów.
Wydaje mi się, że warto na niego spojrzeć w kontekście tego tematu.
Pozdrawiam.
edit:
Dodam tylko, że FLOW3 nie używa zewnętrznych bibliotek AOP (Aspect Oriented Programming) - wszystko jest oparte o czystą implementację w PHP.
tmgryf
25.08.2009, 12:25:29
Troszke bardzo odkopię

Może zle to wszystko zrozumialem, ale wiekszosc opisanych sposobow wtyczkowania mozna by prosto zastapic prostym wstawieniem
include przed wyświetleniem odpowiedniej trsci...
myslalem sobie zeby podzielic strone na minisekcje (w gruncie rzeczy calkiem sporo ich by musialobyc) - np 'htmlheader', 'pageheader', 'menu', 'leftcolumn', leftcolumncontent' 'rightcolumn'.... 'gallerylist' 'galleryimagelist'... itd i trzymanie ich w zmiennych. Dalej wykorzystujac "hooki" (http://stackoverflow.com/questions/42/best-way-to-allow-plugins-for-a-php-application) dla kazdego z elementow wykonywac odpowiedniego hooka lekko go modyfikujac wzgledem tego artykulu.
I tak mamy atrzymalibysmy tablice sekcji sekcje[sekcja] oraz dwuwymiarowa tablice hookow w postaci plugin[sekcja][funkcja z hooka1,funkcja z hooka2...] no i pozniej cos w rodzaju:
foreach (sekcje => element)
if isset plugin[element]
foreach plugin[element] => funkcja)
funkcja();
Zastanawialem sie rowniez jakby mozna bylo to zoptymalizowac - konieczne byloby "cachowanie kodu wtyczek php" tzn - wtyczki mozna byloby wlaczac i wylaczac - po wlaczeniu wtyczki tworzony bylby plik cacheplugin.php zawierajacy "body" plikow wlaczonych wtyczek - ograniczyloby to zbedne przeszukiwanie katalogow w poszukiwaniu wtyczek do inicjowania i otwierania tych calych mas plikow.
A zeby wtyczki staly sie naprawde wtyczkami uzytkownik dostalby narzedzie do tworzenia wlasnych minisekcji poprzez np dodanie odpowedniego kodu cos ala template {#zrobmigalerie#} i tutaj pojawi sie problem rekurencji bo należałoby po kazdym odpaleniu wtyczki dla danej minisekcji odpalic cala liste od nowa bo moze sie okazac ze ostatnia wtyczka doda sekcje do ktorej dedykowana byla pierwsza opalona funkcja... ale mysle ze to juz bardziej problem implementacji calosci
Chcę to napisac

i dla tego sie chcialem spytac co o tym sadzicie?
tuner
19.01.2010, 14:17:31
Cytat(LBO @ 13.03.2008, 15:27:13 )

Framework
FLOW3 (który będzie służyć za bazę dla najnowszego TYPO3) poszedł o krok naprzód w "pluginizacji" aplikacji - używa aspektów.
Także polecam przyjrzenie się temu rozwiązaniu, niezwykle kompleksowo pozwala zarządzać komponentami aplikacji.
Na swoim blogu zamieściłem
wpis poświęcony pluginizowaniu i jako, że jest bardzo w temacie z przyjemnością linkuję.
wlamywacz
25.01.2010, 12:57:44
Witam!
Chciałbym zasięgnąć waszej rady odnośnie pluginów. Aktualnie tworze własnego cms i mam zamiar oprzeć go o pluginy. W moim systemie występują szablony, moduły i pluginy. Szablony jest to ogólny widok, w odpowiednie miejsca umieszczamy zmienne (zastosowanie smarty). Ważniejszą rolę odgrywają moduły, jest to treść przekazana do szablonu w jedną ze zmiennych. W modułach jest możliwość ustawienia "zaczepu" do plugina
{module name="gallery" action="index"}
W pluginie zwracam treść która ma być wstawiona w to miejsce oraz sam plugin posiada uchwyt do szablony dzięki czemu mogę go dowolnie zmieniać z poziomu pluginu. Wywołanie pluginu następuje przed pasowaniem smarty a sam kod
{module name="gallery" action="index"}
zamieniany jest na zmienną w której jest wynik działania modułu. Czy taki schemat jest dobry, czy macie jakieś porady? Poza tym myślę nad wprowadzeniem kolejki, dzięki czemu mógłbym wykorzystać takie moduły jak autoryzacja wybranych modułów czy pluginów. Z góry dziękuje z pomoc.
P.S. Możecie mi podpowiedzieć gdzie szukać informacji o zastosowaniu pluginów?
marcio
25.01.2010, 19:00:32
Cytat
Poza tym myślę nad wprowadzeniem kolejki, dzięki czemu mógłbym wykorzystać takie moduły jak autoryzacja wybranych modułów czy pluginów
Po co bawic sie w kolejke jak mozna robic tak:
if($auth -> isLogged()) {
}
else {
$this -> forward('Authorization'); // lub $this -> forward('Authorization', 'Index');
}
ja tak to widze chyba ze o czyms nie wiem.
Cytat
Możecie mi podpowiedzieć gdzie szukać informacji o zastosowaniu pluginów?
Zalezy co masz na mysli jako plugin ogolnie szukaj info na temat filtrow,pluginow,modulow,modularnosci,komponentow,widget'ow etc...
Co do reszty twojego dzialania pluginow to u mnie dziala to prawie tak samo mam glowny szablon(view) calej strony np lewe i prawe menu o do tego sordkowy kontent.
Potem mam klase ktora to glownego widoku "wstrzykuje" wynik komponentu/pluginu/widget'u.
Tyle ze w glownym widoku mam tylko:
Itp i tam wrzucam wszystko na podstawie url'a.
wlamywacz
25.01.2010, 19:23:20
Kolejka po to gdyż autoryzacja, logowanie itp. będzie również jako moduł który trzeba wywołać w odpowiednim momencie.
marcio
26.01.2010, 00:13:18
Moze ktos wytlumaczy jaka jest roznica pomiedzy kolejka zadan a robien forward() na dana akcje?
XianN
26.01.2010, 11:57:39
Cytat(marcio @ 26.01.2010, 00:13:18 )

Moze ktos wytlumaczy jaka jest roznica pomiedzy kolejka zadan a robien forward() na dana akcje?
Taka jak miedzy (uporzadkowana) lista rzeczy do zrobienia, a dowiadywaniem sie o nastepnym zadaniu po wykonaniu poprzedniego:)
W przypadku forward() metoda, ktora jest aktualnie wykonywana musi znac nastepna.
Jesli jest to lista, wystarczy, ze sie zajmie swoja robota, a decydowanie o tym 'kto, kiedy i gdzie?' pozostawi komu innemu. Lista daje tez duzo wieksza wygode, np w zmienianiu kolejnosci wykonywania zadan, dodawaniu nowych, etc.
marcio
26.01.2010, 13:55:07
Musialbym to widziec w praktyce bo tak zabardzo nie jestem przekonany.
CHcialem jeszcze poruszyc temat o plugin'ach jako filtry.
Dokladnie do postu:
http://forum.php.pl/index.php?s=&showt...st&p=347026 ktory wydaje sie najbardziej rozwiniety z tego teamtu jesli chodzi o filtry.
Tak jak mowilem wczesniej mam jeden glowny szablon gdzie sa wstrzykiwane wszystkie komponenty/pluginy/widgety i do tego mam klase ktora sprawdza czy dla danego komponentu/pluginu jest jaki filtr powiedzmy ze mamy komponent News a w nim metode ShowLastNews();
public function ShowLastNews() {
//wszystkie operacje pobierania etc....
return $txtNews;
}
Teraz by zalozyc filtr wystarczy w katalogu /plugins/filters/ utworzyc plik PFNews.php o takiej klasie:
<?php
class PFNews {
public $ReturnTrueFunction = false; // wyswietlamy wynik zwracany poprzez metode komponnetu/klasy lub false gdy wynik filtru
public function onLoad() { // Przed zaladowanie komponentu/pluginy
return 'Poczatek<Br>';
}
public function on_News_pre_ShowLastNews() { // przed funckja Index komponentu/pluginy News
return 'Przed funckja index<Br>';
}
public function on_News_post_ShowLastNews($html) { // po wykonaniu funckji Index komponentu/pluginu News tutaj robimy nasz bbcode dla prawdziwej zawartosci news'a
return '<Br><b style="color:#FF0000;">'.$html.'</b>';
}
public function onUnload() { // Przed zakonczeniem dzialania filtru
return '<Br>Koniec<Br>';
}
}
?>
Jak dla mnie pomysl bomba chce zrobic jakis filtr nie musze ingerowac w kod jakiegos komponentu/pluginu tylko pisze do niego filtr.
Oczywiscie nie wszystkie metody musi implementowac filtr bo jego klasa nie uzywa interfejsu ani nic bo moze byc tylko tak ze filtr dla danego komponentu/pluginu bedzie potrzebowal tylko jedna funkcje.
Do tego mam glowny kontroler aplikacji ktora pobiera wszystkie komponentu/pluginy za pomoca modelu i wstawia caly wynik do glownego szablonu do tego jest klasa pomocnicza by sprawdzic filtry.
glowny Kontroler:
<?php
class Home extends Controller implements IController {
public function __construct() {
parent::__construct();
}
public function Index() {
$components = $this -> Home_Model -> getComponents($this -> routing -> getController());
$componentsAction = $this -> routing -> getParams();
$componentsAction = (count($componentsAction) == 0) ?
'Index' : $componentsAction[0
];
$tab = $this -> plugins -> LoadPlugin($components, $componentsAction);
$this -> view -> AddVars($tab);
echo $this -> view -> Layout('Home', 'view');
}
}
?>
jesli ktos chce zobaczyc tez klase pomocnicza prosze mowic.
wlamywacz
26.01.2010, 15:23:39
W serwisie istnieje akcja X oraz plugin Y,Z. Plugin Y odpowiada za autoryzacje (logowanie itp. sprawy), Z odpowiada za wyświetlanie formularza kontaktowe. W pluginie Y ustawiam aby został wywołany przed akcją X. Czy muszę przed każdym wywołaniem akcji ładować kolejki wszystkich pluginów aby sprawdzić czy któryś nie powinien zostać wywołany, oraz jak wygląda sprawa kolejności ich wywoływania ?
marcio
26.01.2010, 15:44:43
EDIT:
Zle zrozumialem o ta kolejke chodzi o to:
http://forum.php.pl/index.php?s=&showt...st&p=194058 czyli lancuchy akcji u mnie dziala to wlasnie mniej wiecej tak sorki ale na poczatu chyba przeczytalem bez zrozumienia.
Dziala to u mnie tak kolejka + filtry dla komponentow/pluginow:
<?php
require_once('libraries/PluginFilter.php');
class Plugin {
private $cfg;
public function __construct() {
$this -> cfg = Loader::load('Cfg');
}
public function LoadPlugin($plugins, $action) {
foreach($plugins as $key => $PluginName) {
require_once(DIR_PLUGINS_CTRL.$PluginName.'.php');
}
else if(file_exists(DIR_COMPONENTS_CTRL
.$PluginName.'.php')) {
require_once(DIR_COMPONENTS_CTRL.$PluginName.'.php');
}
else {
Controller::Error(405);
}
$obj = new $PluginName();
if(PluginFilter::CheckFilter($PluginName)) {
$html[$key] = $obj -> LoadFilter($PluginName);
$PluginAction = (method_exists($obj, $action)) ? '_'.$action : '_'.$this -> cfg -> action;
$html[$key] .= $obj -> $PluginAction();
$html[$key] .= $obj -> RemoveFilter($PluginName);
}
else {
$PluginAction = (method_exists($obj, $action)) ? $action : $this -> cfg -> action;
$html[$key] = $obj -> $PluginAction();
}
}
return $html;
}
}
?>
Co o tym myslicie?
Ormin
28.02.2010, 21:39:07
Wzorzec obserwatora i wszystko jasne
Temat, pluginów zależy od struktury systemu do którego chcemy go zastosować.
Po pierwsze trzeba określić strukturę naszego systemu, i wydzielić obszary na które mogą mieć wpływ pluginy.
Trzeba stworzyć abstrakcyjne klasy (dziedziczącę po abstrakcyjnej klasię np. Plugin), które będą miały wpływ na poszczególne sekcje w naszej aplikacji.
abstract class Plugin { }
abstract class PluginUsers extends Plugin {
public function showUser(UserModel $user, View $view) {}
public function showUserList(UserModel $user, UserList $list, View $view) {}
public function preSaveUser(UserModel $user) {}
public function postSaveUser(UserModel $user) {}
public function preLoginUser(UserModel $user) {}
public function postLoginUser(UserModel $user) {}
public function preLogoutUser(UserModel $user) {}
public function postLogoutUser(UserModel $user) {}
// ... itd
}
Następnie w naszym systemie musi istnieć rejestr, w którym dane pluginy będą dodawane.
Podczas wywołania określonych operacji, system pobierałby odpowiedni plugin np. podczas edycji użytkownika, pobierałby wszystkie pluginy dziedziczące po PluginUsers, i wywoływał kolejno metody z tego pluginu odpowiadające obecnie wykonywanej akcji. np po zapisie zmian wywoływana byłaby metoda postSaveUser.
Tak naprawdę trzeba się zastanowić, co w naszym systemie będzie można za pomocą pluginów wykonać. Kolejny krok to napisanie odpowiednich metod w abstakcyjnym modelu a na końcu wywołanie tych metod i przekazanie odpowiednich argumentów, które dany plugin może miec dostęp.
paxton
25.03.2010, 23:52:48
Cos takiego jest sprytne, moze nie jest to porzadny system pluginow, ale moze ulatwiac sprawe przy pisaniu dodatków.
public function loadInjections($name) {
if(is_dir("injections/$name")) foreach (glob("injections/$name/*.php") as $injection) { include_once($injection);
}
else
throw new exception("Could not load injections! Event Folder not found. ErrCode: 172610032010");
}
Używam tego w mojej aplikacji, domyślam się ze szybkość skanownia nie jest najlepsza, ale nie narzekam. Tam gdzie chce aby były wprowadzane pluginy tam używam tej metody.
Innym rozwiązaniem są hooki.
Psychopath
11.04.2010, 16:35:33
Ja robię to nieco inaczej. Dodatki dzielę na "Language Pack", "Blocks" i "Modules".
Sprawa z "Language Pack" jest jasna (includuje plik z tłumaczeniem, które jest zawarte w tablicy).
"Blocks" to w moim przypadku bloki w menu, wygląda to tak, że folder z blokiem zawiera jeden plik z "kodem", a drugi, co ma wypisywać na stronie, to coś w stylu np: code.php zawiera klasę kalendarza, a index.php (w katalogu z blokiem ją inicjuję. Cały system jest bardzo prosty, funkcja obsługująca po prostu za każdym razem robi funkcję blockopen($tytuł_bloku_podany_w_PA), potem następuje zincludowanie index.php, a na końcu blockclose(). W panelu admina można dowolnie tworzyć bloki, nawet takie, które nie mają pliku code.php, bo zawierają np tylko informację typu "Dziś jest głosowanie...". Każdemu blokowi przydziela się id na podstawie którego jest pozycjonowany wyżej lub niżej innych bloków. Z poziomu panelu jest też możliwość dowolnej edycji kodu, jakby ktoś nie chciał się bawić w wrzucanie przez ftpa.
Z "Modules" sprawa jest troche bardziej skomplikowana. W kodzie modułu określone jest jakiego "typu" on jest, czy to plik zincludowany, który wykonuje tylko jakiś kod (np tworzenie logów i statystyk), czy też np. skrypt, który ma być umieszczony np nad stroną główną (pod logo strony, np losowanie cytatów), pod stroną, czy też jako strona inicjowana zmienną "modid", który po wpisaniu index.php?modid=3 przejdzie na wybraną stronę. Linki typu "modid" trzeba dodać samodzielnie, ale myślę, że jak się już dokończę moje wstępne kodzenie core.php to zrobię jakąś większą klasę z mini-api, które będzie mogło też dodawać linki do menu, a może nawet ingerować w inne bloki i moduły.
marcio
22.03.2012, 14:47:38
Witam czy ktos z was na dzien dzisiejszy zaimplementowal w pelni dzialajace pluginy w swoim systemie?
Poki co mam zaimplementowane komponenty i widget'y w pelni dzialajace razem z obsluga gosci czy cache'm calych ich ackji/blokow.
Zastanawiam sie nad pluginami(jako wtyczki do komponentow) czyli taki plugin komentarzy ktory mozna podpiac pod komponent News/Article/ForumPost o ile tego typu plugin nie sprawia mi raczej klopotow w jego implementacji to mam problem np z plugin'em Ankiety np.
Jak podpiac taki plugin ankiety pod news podczas pisania/edytowania danego wpisu?
Na jakiej zasadzie mam obsluzyc 2 formularze(1 do napisania/edycji news, 2 do ankiety)?
Samo "wstrzykniecie" takiego formualrza tez nie sprawia mi klopotu jednak nie wiem zbytnio jak obsluzyc 2 akcje naraz.
W przypadku komentarzy nie ma takiego problemu bo czytajac news dodajemy sam komentarz do niego i jest ok, jednak dodac news'a jak do niego dodac ankiete lub inny plugin?
hind
23.03.2012, 11:03:26
Dla kazdego pluginu wydzieliłbym przestrzeń danych (tak żeby dane z POST/REQUEST nie nachodził na siebie).
np żeby plugin "a" miał nienachodzące się nazwy z pluginem "b" czy też samym głównym procesem -> $_POST['plugin_a']['nazwa_ankiety'], $_POST['main']['nazwa_newsa']
Dodać akcje przygotowawcze (pre) i wykończeniowe (post) tak, aby wywalić błędy i przerwać główny proces (jw. dodać newsa/komentarz), a potem przesłać pełny kontekst głównego procesu do pluginu aby dalej obsłużyć żądania (post).
Problemem jest sam moment uruchomienia pluginu, czy ma być wczytywany zawsze (z konfiguracji), czy też doczytany w pewnym konkretnym momencie (uzupełnienie strony przez XHR?)
W tym wypadku, główny proces nawet nie musi wiedzieć że będą uruchamiane jakieś pluginy, bo będą to akcje poboczne (tak jak w obserwatorze, podpiętym do danego typu zdażenia).
marcio
23.03.2012, 13:52:06
Cytat
Dla kazdego pluginu wydzieliłbym przestrzeń danych (tak żeby dane z POST/REQUEST nie nachodził na siebie).
np żeby plugin "a" miał nienachodzące się nazwy z pluginem "b" czy też samym głównym procesem -> $_POST['plugin_a']['nazwa_ankiety'], $_POST['main']['nazwa_newsa']
Stosuje konwencje ze w pluginach przed nazwami zmiennych daje "p" zeby nie kolidowaly ze soba.
Cytat
Dodać akcje przygotowawcze (pre) i wykończeniowe (post) tak, aby wywalić błędy i przerwać główny proces (jw. dodać newsa/komentarz), a potem przesłać pełny kontekst głównego procesu do pluginu aby dalej obsłużyć żądania (post)
Cytat
Problemem jest sam moment uruchomienia pluginu, czy ma być wczytywany zawsze (z konfiguracji), czy też doczytany w pewnym konkretnym momencie (uzupełnienie strony przez XHR?)
Ja to robie tak ze plugin moze byc ladowany przed lub po komponencie, gdzie do akcji komponentu dolaczam akcje pluginu.
Np majac akcje "readNews" do ktorej chce podczepic plugin comment mam taki config komponentu News, aktywuje plugin w bazie a config sprawdza tylko czy w ogole obiekt(w tym przypadku news) moze posiadac w ogole plugin comment:
<?php
/**
*Volta framework
*@author marcio <opi14@op.pl>, <polishvodka7@gmail.com>
*@copyright Copyright (c) 2012, marcio
*@version 1.0
*/
$configs['guest'] = 1;//1 - on / 0 - off
$configs['cache'] = 0;// 1 - on / 0 - off
$configs['cached_action'] = array('Index'); $configs['lifetime'] = 10800;//time in sec
$configs['admin_panel'] = 1;//1 - on / 0 - off
$configs['plugins_settings'] = array( 'segment_ref' => 0,
'actions' => array('submit', 'delete') )
)
)
);
return $configs;
?>
Cytat
W tym wypadku, główny proces nawet nie musi wiedzieć że będą uruchamiane jakieś pluginy, bo będą to akcje poboczne (tak jak w obserwatorze, podpiętym do danego typu zdażenia)
Dokladnie akcje pluginu sa podpinane pod akcje komponentu i komponent do ktorego sa podpinane nie ma z plugin'em nic wspolnego
mrWodoo
7.09.2012, 16:40:20
generalnie pluginy opiera się na tzw hookach (tak mi się zdaje), ale jak rozwiązać problem zapytań sql, np jakiś plugin chce pobrać dodatkowe dwa pola w zapytaniu, bo nie zawsze używa się SELECT * tylko zamiast * daje się wyliczenie pól
marcio
8.09.2012, 15:13:32
Hooki/Eventy uzywam do innych czynnosci, choc np 4programmers stoi na coyote mam jego kod zrodlowy i tam uzywaja hooki do odpalania wszystkiego o ile sie nie myle.
Moj blog ktory mam w stopce ma zaimplementowane widget-y, komponenty i plugin-y dla nich.
Sa one wpelni dzialajace, z powodu braku czasu bo teraz mam praktyki w firmie jako programista projekt porzucilem jednak mam napisanych kilka komponentow i 2 plugin-y dla nich.
I rozwiazanie dziala.Moze na dniach tam to do oceny tez jestem ciekawy co inni powiedza na moje rozwiazanie, nawet ze mam liste ToDo co jest do zmiany/poprawy jednak wiekszosc funkcjonalnosci juz jest wiec mysle ze pokazac mozna.
mrWodoo
8.09.2012, 17:56:42
Chętnie bym zobaczył
marcio
14.09.2012, 23:43:31
Poczekaj jeszcze miesiac, postaram sie dokonczyc projekt jesli chodzi o backend i funkcjonalnosc.
mrWodoo
9.09.2013, 15:11:36
a jak wpływać na metody klas, np załóżmy, że mamy model User, w nim metodę addUser, jak zaprojektować pluginizację i modele tak aby plugin mógł wpływać na dane wpisywane do bazy, np podczas dodawania użytkownika dopisać jakieś do zapytanie INSERT
hind
16.09.2013, 10:10:42
@mrWodoo: to chyba tylko przez hooki, i przed wrzuceniem do bazy, wywołać wszystkie podpięte akcje podpięte do zdarzenia dodania użytkownika, i tak obrobione dane dopiero zapisać
function addUser($dane) {
foreach($this->_AutomatyczniePobaranListaAkcjiDoDodaniaUsera as $akcja)
$dane = call_user_func($akcja,$dane);
return $this->insert($dane);
}
Crozin
16.09.2013, 11:31:38
@mrWodoo: Zdarzenia i jakiś sensowny
event dispatcher z obsługą priorytetów:
public function addUser(UserInterface $user) {
...
$event = new Event($user);
$this->eventDispatcher->dispatch('costam.pre_add_user', $event);
$user = $event->getData();
...
$event = new Event($user);
$this->eventDispatcher->dispatch('costam.post_add_user', $event);
...
}
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę
kliknij tutaj.