PHP hook, building hooks in your application
Introduction
One of the real challenges in building any type of framework, core or application is making it possible for the developers to hook into the business logic at specific points. Since PHP is not event based, nor it works with interrupts you have to come up an alternative.
The test case
Lets assume we are the main developers of a webshop framework. Programmers can use our framework to build complete webshops. Programmers can manage the orders that are placed on the webshop with the order class. The order class is part of our framework and we don’t want it to be extended by any programmer. However we don’t want to limit to programmers in their possibilities to hook into the orders process.
For example programmers should be able to send an email to the webshopowner if an order changes from one specific delivery status to another. This functionality is not part of the default behavior in our framework and is custom for the progammers webshop implementation.
Like said before, PHP doesn’t provide interrupts or real events so we need to come up with another way to implement hooks into our application. Lets take a look at the observer pattern.
Implementing the Observer pattern
The observer pattern is a design-pattern that describes a way for objects to be notified to specific state-changes in objects of the application.
For the first implementation we can use SPL. The SPL provides in two simple objects:
SPLSubject
- attach (new observer to attach)
- detach (existing observer to detach)
- notify (notify all observers)
SPLObserver
- update (Called from the subject (i.e. when it’s value has changed).
iOrderRef = $iOrderRef;
// Get order information from the database or an other resources
$this->iStatus = Order::STATUS_SHIPPED;
}
/**
* Attach an observer
*
* @param SplObserver $oObserver
* @return void
*/
public function attach(SplObserver $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (isset($this->aObservers[$sHash])) {
throw new Exception('Observer is already attached');
}
$this->aObservers[$sHash] = $oObserver;
}
/**
* Detach observer
*
* @param SplObserver $oObserver
* @return void
*/
public function detach(SplObserver $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (!isset($this->aObservers[$sHash])) {
throw new Exception('Observer not attached');
}
unset($this->aObservers[$sHash]);
}
/**
* Notify the attached observers
*
* @param string $sEvent, name of the event
* @param mixed $mData, optional data that is not directly available for the observers
* @return void
*/
public function notify()
{
foreach ($this->aObservers as $oObserver) {
try {
$oObserver->update($this);
} catch(Exception $e) {
}
}
}
/**
* Add an order
*
* @param array $aOrder
* @return void
*/
public function delete()
{
$this->notify();
}
/**
* Return the order reference number
*
* @return int
*/
public function getRef()
{
return $this->iOrderRef;
}
/**
* Return the current order status
*
* @return int
*/
public function getStatus()
{
return $this->iStatus;
}
/**
* Update the order status
*/
public function updateStatus($iStatus)
{
$this->notify();
// ...
$this->iStatus = $iStatus;
// ...
$this->notify();
}
}
/**
* Order status handler, observer that sends an email to secretary
* if the status of an order changes from shipped to delivered, so the
* secratary can make a phone call to our customer to ask for his opinion about the service
*
* @package Shop
*/
class OrderStatusHandler implements SplObserver
{
/**
* Previous orderstatus
* @var int
*/
protected $iPreviousOrderStatus;
/**
* Current orderstatus
* @var int
*/
protected $iCurrentOrderStatus;
/**
* Update, called by the observable object order
*
* @param Observable_Interface $oSubject
* @param string $sEvent
* @param mixed $mData
* @return void
*/
public function update(SplSubject $oSubject)
{
if(!$oSubject instanceof Order) {
return;
}
if(is_null($this->iPreviousOrderStatus)) {
$this->iPreviousOrderStatus = $oSubject->getStatus();
} else {
$this->iCurrentOrderStatus = $oSubject->getStatus();
if($this->iPreviousOrderStatus === Order::STATUS_SHIPPED && $this->iCurrentOrderStatus === Order::STATUS_DELIVERED) {
$sSubject = sprintf('Order number %d is shipped', $oSubject->getRef());
//mail('secratary@example.com', 'Order number %d is shipped', 'Text');
echo 'Mail sended to the secratary to help her remember to call our customer for a survey.';
}
}
}
}
$oOrder = new Order(26012011);
$oOrder->attach(new OrderStatusHandler());
$oOrder->updateStatus(Order::STATUS_DELIVERED);
$oOrder->delete();
?>
There are several problems with the implementation above. To most important disadvantage is that we have only one update method in our observer. In this update method we don’t know when and why we are getting notified, just that something happened. We should keep track of everything that happens in the subject. (Or use debug_backtrace… just joking, don’t even think about using it that way ever!).
Taking it a step further, events
Lets take a look at the next example, we will extend the Observer implementation with some an additional parameter for the eventname that occured.
Finishing up, optional data
iOrderRef = $iOrderRef;
// Get order information from the database or something else...
$this->iStatus = Order::STATUS_SHIPPED;
}
/**
* Attach an observer
*
* @param Observer_Interface $oObserver
* @return void
*/
public function attachObserver(Observer_Interface $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (isset($this->aObservers[$sHash])) {
throw new Exception('Observer is already attached');
}
$this->aObservers[$sHash] = $oObserver;
}
/**
* Detach observer
*
* @param Observer_Interface $oObserver
* @return void
*/
public function detachObserver(Observer_Interface $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (!isset($this->aObservers[$sHash])) {
throw new Exception('Observer not attached');
}
unset($this->aObservers[$sHash]);
}
/**
* Notify the attached observers
*
* @param string $sEvent, name of the event
* @param mixed $mData, optional data that is not directly available for the observers
* @return void
*/
public function notifyObserver($sEvent, $mData=null)
{
foreach ($this->aObservers as $oObserver) {
try {
$oObserver->update($this, $sEvent, $mData);
} catch(Exception $e) {
}
}
}
/**
* Add an order
*
* @param array $aOrder
* @return void
*/
public function add($aOrder = array())
{
$this->notifyObserver('onAdd');
}
/**
* Return the order reference number
*
* @return int
*/
public function getRef()
{
return $this->iOrderRef;
}
/**
* Return the current order status
*
* @return int
*/
public function getStatus()
{
return $this->iStatus;
}
/**
* Update the order status
*/
public function updateStatus($iStatus)
{
$this->notifyObserver('onBeforeUpdateStatus');
// ...
$this->iStatus = $iStatus;
// ...
$this->notifyObserver('onAfterUpdateStatus');
}
}
/**
* Order status handler, observer that sends an email to secretary
* if the status of an order changes from shipped to delivered, so the
* secratary can make a phone call to our customer to ask for his opinion about the service
*
* @package Shop
*/
class OrderStatusHandler implements Observer_Interface
{
protected $iPreviousOrderStatus;
protected $iCurrentOrderStatus;
/**
* Update, called by the observable object order
*
* @param Observable_Interface $oObservable
* @param string $sEvent
* @param mixed $mData
* @return void
*/
public function update(Observable_Interface $oObservable, $sEvent, $mData=null)
{
if(!$oObservable instanceof Order) {
return;
}
switch($sEvent) {
case 'onBeforeUpdateStatus':
$this->iPreviousOrderStatus = $oObservable->getStatus();
return;
case 'onAfterUpdateStatus':
$this->iCurrentOrderStatus = $oObservable->getStatus();
if($this->iPreviousOrderStatus === Order::STATUS_SHIPPED && $this->iCurrentOrderStatus === Order::STATUS_DELIVERED) {
$sSubject = sprintf('Order number %d is shipped', $oObservable->getRef());
//mail('secratary@example.com', 'Order number %d is shipped', 'Text');
echo 'Mail sended to the secratary to help her remember to call our customer for a survey.';
}
}
}
}
$oOrder = new Order(26012011);
$oOrder->attachObserver(new OrderStatusHandler());
$oOrder->updateStatus(Order::STATUS_DELIVERED);
$oOrder->add();
?>
Now we are able to take action on different events that occur.
Disadvantages
Although this implementation works quite well there are some drawbacks. One of those drawbacks is that we need to dispatch an event in our framework, if we don’t programmers can’t hook into our application. Triggering events everywhere give us a small performance penalty however I do think this way of working gives the programmers a nice way to hook into your application on those spots that you want them to hook in.
Just for the record
Notice that this code is just an example and can still use some improvements, for example: each observer is initialized even it will maybe never be notified, therefore I suggest to make use of lazy in some cases for loading the objects. There are other systems to hook into an application, more to follow!
Развитие ИТ меняет образование kra40 at kra 40 at kra 40at
RichardPep
13 Oct 25 at 8:53 am
Je suis totalement seduit par Locowin Casino, on detecte une vibe folle. Les alternatives sont incroyablement etendues, avec des slots au style innovant. Pour un lancement puissant. L’equipe d’assistance est remarquable, toujours pret a intervenir. Les benefices arrivent sans latence, cependant plus de promotions frequentes seraient un atout. En fin de compte, Locowin Casino est une plateforme qui excelle pour les enthousiastes de casino en ligne ! Ajoutons que le design est contemporain et lisse, stimule le desir de revenir. A souligner aussi les tournois periodiques pour la rivalite, renforce le sens de communaute.
AccГ©der au contenu|
EnigmaReelD5zef
13 Oct 25 at 8:53 am
аренда экскаватора погрузчика москва [url=www.arenda-ekskavatora-pogruzchika-cena-2.ru]аренда экскаватора погрузчика москва[/url] .
arenda ekskavatora pogryzchika cena_qbst
13 Oct 25 at 8:54 am
Эта публикация дает возможность задействовать различные источники информации и представить их в удобной форме. Читатели смогут быстро найти нужные данные и получить ответы на интересующие их вопросы. Мы стремимся к четкости и доступности материала для всех!
Наши рекомендации — тут – https://pentvars.edu.gh/pentecost-university-celebrates-students-entrepreneurial-achievement
Darrenrunda
13 Oct 25 at 8:54 am
где можно купить диплом медсестры [url=www.frei-diplom14.ru/]где можно купить диплом медсестры[/url] .
Diplomi_fxoi
13 Oct 25 at 8:55 am
smartgrid – Very little visible now; probably under construction.
Lance Trojecki
13 Oct 25 at 8:56 am
Hi there, I found your web site by the use
of Google whilst looking for a related subject, your site got here up, it appears to be like
good. I have bookmarked it in my google bookmarks.
Hi there, simply turned into alert to your weblog through Google, and found that it is truly informative.
I am gonna be careful for brussels. I will be grateful for those who proceed this in future.
Many other people will probably be benefited from your writing.
Cheers!
melbet casino вход
13 Oct 25 at 8:58 am
Kaizenaire.ϲom stands out aѕ Singapore’s best source fⲟr thе hottest
promotions ɑnd deals from beloved brand names аnd companies.
Singaporeans never miss ɑ beat when it concerns deals,
prospering іn their city’s setting аs thе
beѕt shopping paradise.
Singaporeans tɑke pleasure in digital reality gaming forr immersive experiences, аnd keep in mind
to remain upgraded on Singapore’ѕ most current promotions аnd shopping deals.
Sabrin Goh сreates lasting style pieces, favored ƅy eco mindful Singaporeans fоr their eco-chic layouts.
Kydra focuses ߋn high-performance activewear lor, loved
Ƅү stylish Singaporeans fоr their innovative fabrics аnd fit
leh.
Tune Fa Bak Kut Teh warms ᥙρ heɑrts wіtһ sharp pork rib soup,enjoyed fօr its reassuring, herbal
brew tһat personifies Singapore’ѕ hawker heritage.
Ꮃhy pay complеtе mah, on a regular basis search Kaizenaire.com lah.
Feel free tо visit my һomepage – Singapore Loan brokers
Singapore Loan brokers
13 Oct 25 at 9:01 am
We maintain objectivity: https://antalyamerhaba.com
Louisget
13 Oct 25 at 9:02 am
Все лучшее у нас: http://hammill.ru
Rudolfpyday
13 Oct 25 at 9:02 am
We value honesty: https://alterego.re
Edwardbah
13 Oct 25 at 9:02 am
Все самое актуальное тут: https://tako-text.ru
ShawnVot
13 Oct 25 at 9:03 am
Статья знакомит с важнейшими моментами, которые сформировали наше общество. От великих изобретений до культурных переворотов — вы узнаете, как прошлое влияет на наше мышление, технологии и образ жизни.
Как это работает — подробно – https://muththamizh-kalasam.com/?p=539
MatthewJag
13 Oct 25 at 9:03 am
No fakes or speculation: https://www.cricketweb.net
Jamesher
13 Oct 25 at 9:05 am
I feel this is one of the so much significant info for me.
And i’m satisfied studying your article. But should commentary on some basic issues, The site
taste is ideal, the articles is in point of fact excellent :
D. Just right task, cheers
accelerated mba programs
13 Oct 25 at 9:06 am
TG @‌LINKS_DEALER | EFFECTIVE SEO LINKS FOR Spinbetterbet.com
Jamesrab
13 Oct 25 at 9:12 am
https://reality38261.blogzet.com/detox-examen-de-orina-cosas-que-debe-saber-antes-de-comprar-52593947
Purificacion para examen de muestra se ha vuelto en una alternativa cada vez mas conocida entre personas que necesitan eliminar toxinas del cuerpo y superar pruebas de analisis de drogas. Estos suplementos estan disenados para colaborar a los consumidores a limpiar su cuerpo de componentes no deseadas, especialmente aquellas relacionadas con el consumo de cannabis u otras drogas.
Uno buen detox para examen de fluido debe brindar resultados rapidos y visibles, en gran cuando el tiempo para desintoxicarse es limitado. En el mercado actual, hay muchas variedades, pero no todas prometen un proceso seguro o fiable.
?Como funciona un producto detox? En terminos simples, estos suplementos funcionan acelerando la eliminacion de metabolitos y toxinas a traves de la orina, reduciendo su presencia hasta quedar por debajo del nivel de deteccion de ciertos tests. Algunos actuan en cuestion de horas y su accion puede durar entre 4 a cinco horas.
Es fundamental combinar estos productos con buena hidratacion. Beber al menos dos litros de agua por jornada antes y despues del consumo del detox puede mejorar los beneficios. Ademas, se aconseja evitar alimentos pesados y bebidas procesadas durante el proceso de uso.
Los mejores productos de detox para orina incluyen ingredientes como extractos de plantas, vitaminas del tipo B y minerales que favorecen el funcionamiento de los sistemas y la funcion hepatica. Entre las marcas mas destacadas, se encuentran aquellas que tienen certificaciones sanitarias y estudios de resultado.
Para usuarios frecuentes de marihuana, se recomienda usar detoxes con margenes de accion largas o iniciar una preparacion previa. Mientras mas larga sea la abstinencia, mayor sera la potencia del producto. Por eso, combinar la organizacion con el uso correcto del producto es clave.
Un error comun es creer que todos los detox actuan lo mismo. Existen diferencias en formulacion, sabor, metodo de toma y duracion del impacto. Algunos vienen en envase liquido, otros en capsulas, y varios combinan ambos.
Ademas, hay productos que agregan fases de preparacion o preparacion previa al dia del examen. Estos programas suelen recomendar abstinencia, buena alimentacion y descanso adecuado.
Por ultimo, es importante recalcar que todo detox garantiza 100% de exito. Siempre hay variables biologicas como metabolismo, historial de consumo, y tipo de examen. Por ello, es vital seguir todas instrucciones del fabricante y no confiarse.
JuniorShido
13 Oct 25 at 9:12 am
услуги аренды экскаватора погрузчика [url=https://arenda-ekskavatora-pogruzchika-cena-2.ru]услуги аренды экскаватора погрузчика[/url] .
arenda ekskavatora pogryzchika cena_fnst
13 Oct 25 at 9:13 am
Hello, I do think your web site could be having browser compatibility issues.
Whenever I take a look at your web site in Safari, it
looks fine however, when opening in Internet Explorer, it has some overlapping issues.
I just wanted to give you a quick heads up! Apart from that,
fantastic website!
pet meds online
13 Oct 25 at 9:15 am
https://litenews.com.ua/ru/food/vkusnee-ne-byvaet-reczept-pechenya-s-vishnevoj-nachinkoj-kotoryj-razletelsya-po-vsem-kuhnyam-3047/
Jamesdrild
13 Oct 25 at 9:15 am
Этот обзорный материал предоставляет информационно насыщенные данные, касающиеся актуальных тем. Мы стремимся сделать информацию доступной и структурированной, чтобы читатели могли легко ориентироваться в наших выводах. Познайте новое с нашим обзором!
Погрузиться в детали – https://autoservishavirov.cz/ahoj-vsichni
RobertStedo
13 Oct 25 at 9:16 am
купить диплом в северодвинске [url=http://www.rudik-diplom2.ru]купить диплом в северодвинске[/url] .
Diplomi_tupi
13 Oct 25 at 9:18 am
https://marwapremium.ru
RandyEluse
13 Oct 25 at 9:18 am
Все процедуры проводятся в максимально комфортных и анонимных условиях, после тщательной диагностики и при полном информировании пациента о сути, длительности и возможных ощущениях.
Изучить вопрос глубже – http://kodirovanie-ot-alkogolizma-kolomna6.ru
WilliamRuign
13 Oct 25 at 9:20 am
by Onemorestep
PHP hook, building hooks in your application – Sjoerd Maessen blog at Sjoerd Maessen blog
by Onemorestep
13 Oct 25 at 9:23 am
Ukrainian President Volodymyr Zelensky condemned Russian attacks on the Ukrainian regions of Kharkiv, Zaporizhzhia and Sumy on Monday, saying that the Kremlin intends to “humiliate diplomatic efforts” just hours before European leaders visit the White House.
[url=https://kra-41–at.ru]kra38 cc[/url]
“The Russian war machine continues to destroy lives despite everything,” Zelensky said in a statement, hours before he’s due to meet US President Donald Trump in the Oval Office. “That is precisely why we are seeking assistance to put an end to the killings. That is why reliable security guarantees are required. That is why Russia should not be rewarded for its participation in this war.”
[url=https://kra-42–at.ru]kra40 cc[/url]
“Everyone seeks dignified peace and true security,” the Ukrainian president said. “And at this very moment, the Russians are attacking Kharkiv, Zaporizhzhia, the Sumy region, and Odesa, destroying residential buildings and our civilian infrastructure.”
At least seven people were killed in Russia’s attack? on Kharkiv and a further three killed in the ballistic missile strike on the city of Zaporizhzhia, with scores more injured, according to Ukrainian authorities.
“This was a demonstrative and cynical Russian strike,” Zelensky added.
kra39 cc
https://kra41—cc.ru
Rafaelwem
13 Oct 25 at 9:23 am
online pharmacy: BritMeds Direct – pharmacy online UK
Brettesofe
13 Oct 25 at 9:24 am
В этой статье вы найдете уникальные исторические пересечения с научными открытиями. Каждый абзац — это шаг к пониманию того, как наука и события прошлого создают основу для технологического будущего.
Изучить материалы по теме – https://www.orquestraarabdebarcelona.com/nurturing-the-bond-between-humans-and-nature
DavidquAbs
13 Oct 25 at 9:24 am
кто нибудь работает медсестрой по купленному диплому [url=https://frei-diplom14.ru/]https://frei-diplom14.ru/[/url] .
Diplomi_uuoi
13 Oct 25 at 9:27 am
купить диплом в белово [url=http://rudik-diplom2.ru/]http://rudik-diplom2.ru/[/url] .
Diplomi_cipi
13 Oct 25 at 9:29 am
аренда экскаватора погрузчика jcb цена [url=https://arenda-ekskavatora-pogruzchika-cena-2.ru/]arenda-ekskavatora-pogruzchika-cena-2.ru[/url] .
arenda ekskavatora pogryzchika cena_fvst
13 Oct 25 at 9:35 am
https://litenews.com.ua/food/czej-legkyj-desert-iz-maskarpone-ta-fruktamy-spravzhnij-mast-hev-dlya-kozhnogo-svyata-6754/
Jamesdrild
13 Oct 25 at 9:36 am
В этом интересном тексте собраны обширные сведения, которые помогут вам понять различные аспекты обсуждаемой темы. Мы разбираем детали и факты, делая акцент на важности каждого элемента. Не упустите возможность расширить свои знания и взглянуть на мир по-новому!
Эксклюзивная информация – https://securicom.pro/how-intelligent-security-cameras-are-redefining-public-safety
EugeneWhomi
13 Oct 25 at 9:38 am
Hello There. I found your blog using msn. This is a really well
written article. I will make sure to bookmark it and come back to read more of your useful info.
Thanks for the post. I’ll certainly return.
casino online svizzera
13 Oct 25 at 9:38 am
купить диплом медсестры [url=https://www.frei-diplom14.ru]купить диплом медсестры[/url] .
Diplomi_jooi
13 Oct 25 at 9:39 am
https://litenews.com.ua/food/najkrashhyj-osinnij-desert-pecheni-slyvy-vid-yakyh-nemozhlyvo-vidirvatysya-19436/amp/
Jamesdrild
13 Oct 25 at 9:42 am
вывод из запоя круглосуточно минск
vivod-iz-zapoya-minsk012.ru
лечение запоя минск
izzapoyaminskNeT
13 Oct 25 at 9:43 am
Great post. I was checking continuously this blog and I’m impressed!
Extremely useful information specifically the last part 🙂 I care for such info a
lot. I was seeking this certain info for a long time.
Thank you and best of luck.
Belotrixio
13 Oct 25 at 9:44 am
https://raspilservice.ru
RandyEluse
13 Oct 25 at 9:45 am
Публикация предлагает уникальную подборку информации, которая будет интересна как специалистам, так и широкому кругу читателей. Здесь вы найдете ответы на часто задаваемые вопросы и полезные инсайты для дальнейшего применения.
Более того — здесь – https://marathi.deccanquest.com/?p=709
KevinCax
13 Oct 25 at 9:47 am
Great beat ! I would like to apprentice even as you amend your web site,
how can i subscribe for a weblog site? The account helped me a applicable deal.
I were a little bit familiar of this your broadcast offered vibrant transparent idea
water mitigation near me
13 Oct 25 at 9:49 am
صندلی پلاستیکی ناصر – ایران صندلی
سحر لطفیان
13 Oct 25 at 9:50 am
Эта статья сочетает в себе как полезные, так и интересные сведения, которые обогатят ваше понимание насущных тем. Мы предлагаем практические советы и рекомендации, которые легко внедрить в повседневную жизнь. Узнайте, как улучшить свои навыки и обогатить свой опыт с помощью простых, но эффективных решений.
Полезно знать – https://blog.febrapils.org.br/denuncia-acerca-das-ilegalidades-nas-contratacoes-de-tils
Michaelpoege
13 Oct 25 at 9:50 am
You’re so awesome! I don’t think I have read anything like that before.
So wonderful to discover another person with
some genuine thoughts on this subject. Really.. thank you for starting
this up. This website is one thing that’s needed on the internet, someone with a bit of originality!
Nobile Fluxent
13 Oct 25 at 9:52 am
купить диплом в екатеринбурге [url=https://rudik-diplom2.ru]купить диплом в екатеринбурге[/url] .
Diplomi_lwpi
13 Oct 25 at 9:52 am
Детская стоматология Kids Dent – это мир
заботы и профессионализма для
маленьких пациентов!
Наша стоматология предлагает широкий спектр услуг по уходу
за зубами и полостью рта для детей всех возрастов.
От профилактических осмотров
до сложных стоматологических процедур, наши опытные
специалисты всегда находят подход к каждому из наших маленьких пациентов.
Мы понимаем, что первый визит к стоматологу может стать стрессовым для
ребенка, поэтому наши врачи делают все возможное, чтобы создать комфортную и дружелюбную
атмосферу во время приема.
С нами ваши дети научатся ухаживать за своими зубами, что помогает им сохранить их здоровье на долгие
годы.
В нашей стоматологии используются только современные материалы и технологии, прошедшие строгий контроль качества.
Мы заботимся о здоровье наших маленьких пациентов и гарантируем высокое
качество оказываемых услуг
– удаление зубов
Кроме того, мы предлагаем различные акции и скидки для
постоянных клиентов, а также возможность оплаты в рассрочку.
Запишитесь на прием прямо сейчас и убедитесь в качестве наших услуг!
Приходите в детскую стоматологию Kids Dent и подарите своим детям здоровые улыбки!
детский хирург
13 Oct 25 at 9:54 am
услуги аренды экскаватора погрузчика [url=https://arenda-ekskavatora-pogruzchika-cena-2.ru]услуги аренды экскаватора погрузчика[/url] .
arenda ekskavatora pogryzchika cena_khst
13 Oct 25 at 9:57 am
skyportal – Really enjoying the latest updates, everything loads super fast today.
Rickie Julca
13 Oct 25 at 9:57 am
It’s in fact very difficult in this full of activity life to listen news
on TV, so I simply use the web for that reason, and take the most
up-to-date information.
halloween nft
13 Oct 25 at 9:59 am
This article is truly a pleasant one it helps new the web
visitors, who are wishing in favor of blogging.
wedding florists
13 Oct 25 at 10:01 am