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!
перепланировка квартиры дизайн проект [url=https://proekt-pereplanirovki-kvartiry9.ru/]proekt-pereplanirovki-kvartiry9.ru[/url] .
proekt pereplanirovki kvartiri_cupa
11 Sep 25 at 5:02 am
*Диапазоны «зелёной зоны» назначаются индивидуально по возрасту, фоновым заболеваниям и исходным показателям.
Ознакомиться с деталями – [url=https://narkologicheskaya-klinika-ryazan14.ru/]анонимная наркологическая клиника в рязани[/url]
Kennethpsype
11 Sep 25 at 5:06 am
согласование. [url=http://www.soglasovanie-pereplanirovki-kvartiry17.ru]http://www.soglasovanie-pereplanirovki-kvartiry17.ru[/url] .
soglasovanie pereplanirovki kvartiri _czol
11 Sep 25 at 5:06 am
https://replit.com/@candetoxblend
Afrontar una prueba de orina ya no tiene que ser una pesadilla. Existe un suplemento de última generación que funciona en el momento crítico.
El secreto está en su mezcla, que sobrecarga el cuerpo con vitaminas, provocando que la orina oculte los metabolitos de toxinas. Esto asegura una muestra limpia en menos de lo que imaginas, con efectividad durante 4 a 5 horas.
Lo mejor: es un plan de emergencia, diseñado para trabajadores en evaluaciones.
Miles de personas en Chile confirman su seguridad. Los paquetes llegan sin logos, lo que refuerza la confianza.
Cuando el examen no admite errores, esta solución es la herramienta clave.
JuniorShido
11 Sep 25 at 5:06 am
I know this web site presents quality dependent content and additional data, is
there any other web site which provides these kinds of
information in quality?
Quantum AI
11 Sep 25 at 5:07 am
проект перепланировки стоимость [url=www.proekt-pereplanirovki-kvartiry9.ru/]www.proekt-pereplanirovki-kvartiry9.ru/[/url] .
proekt pereplanirovki kvartiri_fopa
11 Sep 25 at 5:07 am
I’d like to find out more? I’d love to find out some additional information.
Pink Himalayan Salt
11 Sep 25 at 5:07 am
Анонимная помощь при запое — врачи «Alco.Rehab» (Москва) приедут к вам в течение часа.
Подробнее тут – [url=https://vyvod-iz-zapoya-moskva13.ru/]нарколог на дом вывод из запоя[/url]
Williamvaw
11 Sep 25 at 5:08 am
confidential delivery pharmacy UK: pharmacy online fast delivery UK – online pharmacy UK no prescription
Jamesmit
11 Sep 25 at 5:10 am
Woah! I’m really digging the template/theme of this site.
It’s simple, yet effective. A lot of times it’s tough to get that “perfect balance” between user friendliness and visual appearance.
I must say you’ve done a amazing job with this.
Also, the blog loads very quick for me on Internet explorer.
Exceptional Blog!
Jaqueline
11 Sep 25 at 5:10 am
купить диплом института высшего образования [url=www.educ-ua16.ru]купить диплом института высшего образования[/url] .
Diplomi_cami
11 Sep 25 at 5:10 am
Yesterday, while I was at work, my sister stole my iphone
and tested to see if it can survive a 40 foot drop, just so she can be a
youtube sensation. My iPad is now destroyed and she has 83 views.
I know this is completely off topic but I had
to share it with someone!
소액결제
11 Sep 25 at 5:13 am
перепланировка услуги [url=https://soglasovanie-pereplanirovki-kvartiry17.ru/]https://soglasovanie-pereplanirovki-kvartiry17.ru/[/url] .
soglasovanie pereplanirovki kvartiri _avol
11 Sep 25 at 5:17 am
This website was… how do I say it? Relevant!! Finally I have
found something which helped me. Thanks a lot!
traducciones oficiales
11 Sep 25 at 5:21 am
электрокарнизы для штор цена [url=http://elektrokarnizy5.ru/]http://elektrokarnizy5.ru/[/url] .
elektrokarnizi_jyol
11 Sep 25 at 5:21 am
Visit the website https://mlbet-mbet.com/ and you will learn everything about the Melbet bookmaker, with which you can bet on sports and play in an online casino. Find out basic information, how to register, how to top up your balance and withdraw funds, everything about the mobile application and much more. Do not forget to use a profitable promo code on the website, which will give a number of advantages!
wuxurrdTUT
11 Sep 25 at 5:22 am
“Решил попробовать курнуть через фольгу , Насыпаю нажигаю бля чуть кишки не выпленул”
https://ilm.iou.edu.gm/members/ybajuwexanonuv/
Вот уже Артем хохочет,
RogerCer
11 Sep 25 at 5:24 am
электрокарнизы для штор купить в москве [url=https://elektrokarnizy5.ru]https://elektrokarnizy5.ru[/url] .
elektrokarnizi_ajol
11 Sep 25 at 5:24 am
Listen ᥙp, Singapore parents, math remains peгhaps the extremely imрortant primary topic,
encouraging imagination tһrough proЬlem-solving tߋ groundbreaking careers.
Ⅾо not play play lah, pair a reputable Junior College ρlus mathematics proficiency fⲟr ensure high Ꭺ Levels marks
as well as seamless chɑnges.
Mums and Dads, dread tһe gap hor, math base іѕ criticsl at Junior College for understanding figures, essential
fοr modern online ѕystem.
Anglo-Chinese School (Independent) Junior College սѕes a faith-inspired education tһat
balances intellectual pursuits ѡith ethical worths, empowering students tо еnd up
being thoughtful global citizens. Ӏtѕ International Baccalaureate
program motivates іmportant thinking aand questions, supported bү first-rate resources ɑnd dedicated
educators. Trainees master ɑ wide array оf co-curricular activities, fгom robotics to music, constructing versatility аnd
creativity. The school’s focus оn service learning instills а sense of obligation аnd community engagement fгom an eɑrly phase.
Graduates аre welⅼ-preparedfor prominent universities, carrying forward ɑ tradition ߋf excellence
and integrity.
Jurong Pioneer Junior College, developed tһrough tһe thoughtful
merger of Jurong Junior College аnd Pioneer Junior College, ρrovides a progressive аnd
future-oriented education tһat positions ɑ unique focus ᧐n China preparedness, global company acumen, ɑnd cross-cultural engagement tо prepare students for thriving in Asia’s
vibrant financial landscape. Тһe college’ѕ dual schools
ɑre equipped ᴡith modern, flexible facilities including specialized
commerce simulation гooms, science innovation laboratories, ɑnd arts ateliers, all designed tо promote practical skills, creativity, ɑnd interdisciplinary knowing.
Improving academic programs ɑrе matched Ьy global
cooperations, sᥙch аs joint jobs woth Chinese
universities аnd cultural immersion journeys, ѡhich
improve students’ linguistic efficiency аnd worldwide outlook.
А helpful ɑnd inclusive neighborhood atmosphere motivates resilience ɑnd leadership development tһrough а
vast array of co-curricular activities, fгom entrepreneurship clubs to sports ցroups that promote
teamwork ɑnd perseverance. Graduates оf Jurong Pioneer Junior
College ɑre extremely ԝell-prepared for competitive professions, embodying tһe worths оf care, constant improvement, and innovation tһat
specify tһe organization’s forward-looking
principles.
Aiyah, primary mathematics teaches real-ᴡorld uses including financial
planning, therеfore makе sᥙre your kid grasps this right starting
early.
Listen up, calm pom рi pi, math remains рart ߋf tһe leading disciplines іn Junior College, building base tо
A-Level calculus.
Aiyah, primary maths instructs practical applications ⅼike budgeting, tһerefore guarantee үour child ɡets
this properly starting young.
Eh eh, composed pom pii рi, maths remains amߋng of
thе leading disciplines in Junior College, building foundation tօ A-Level advanced
math.
Folks, fearful оf losing mode engaged lah, solid primary math guides іn Ьetter STEM comprehension ρlus construction dreams.
Wah, math іs the base pillar fⲟr primary schooling, aiding kids іn dimensional thinking for building routes.
Scoring Аѕ in A-levels boosts your resume for part-time jobs dսring
uni.
Apart to establishment amenities, focus ԝith mathematics іn order to st᧐p
typical mistakes ⅼike careless blunders ⅾuring assessments.
Feel free tо visit mү website junior Colleges singapore
junior Colleges singapore
11 Sep 25 at 5:27 am
электронный карниз для штор [url=http://elektrokarnizy5.ru/]http://elektrokarnizy5.ru/[/url] .
elektrokarnizi_ktol
11 Sep 25 at 5:27 am
перепланировка проект [url=http://www.proekt-pereplanirovki-kvartiry9.ru]http://www.proekt-pereplanirovki-kvartiry9.ru[/url] .
proekt pereplanirovki kvartiri_cupa
11 Sep 25 at 5:27 am
Казино Вавада
AndrewSeave
11 Sep 25 at 5:27 am
Je suis envoute par MrXBet Casino, ca vibre avec une energie de casino enigmatique. L’assortiment de jeux du casino est un coffre-fort de plaisirs, avec des machines a sous de casino modernes et captivantes. Le support du casino est disponible 24/7, repondant en un eclair mysterieux. Les gains du casino arrivent a une vitesse fulgurante, mais des recompenses de casino supplementaires feraient frissonner. Dans l’ensemble, MrXBet Casino est un joyau pour les fans de casino pour les amoureux des slots modernes de casino ! De surcroit le site du casino est une merveille graphique enigmatique, facilite une experience de casino mysterieuse.
avis mrxbet casino|
whimsyturtle6zef
11 Sep 25 at 5:27 am
IntimaCare [url=https://intimacareuk.com/#]IntimaCare[/url] weekend pill UK online pharmacy
Albertmoone
11 Sep 25 at 5:29 am
nexus url dark markets 2025 nexus dark [url=https://darkmarketgate.com/ ]dark markets 2025 [/url]
Donaldfup
11 Sep 25 at 5:30 am
Its like you read my mind! You seem to know a lot about this, like you
wrote the book in it or something. I think that you can do with some pics to drive
the message home a bit, but instead of that, this is excellent
blog. A fantastic read. I will certainly be back.
lanyard printing
11 Sep 25 at 5:31 am
мелбет kg [url=https://mostbet12004.ru]https://mostbet12004.ru[/url]
mostbet_bzOt
11 Sep 25 at 5:31 am
где заказать проект перепланировки квартиры в москве [url=www.proekt-pereplanirovki-kvartiry9.ru/]www.proekt-pereplanirovki-kvartiry9.ru/[/url] .
proekt pereplanirovki kvartiri_depa
11 Sep 25 at 5:31 am
В условиях медицинского контроля специалисты выполняют последовательные действия, направленные на стабилизацию состояния пациента.
Детальнее – [url=https://vyvod-iz-zapoya-ryazan14.ru/]срочный вывод из запоя рязань[/url]
Douglasbeind
11 Sep 25 at 5:31 am
https://armand-parts.ru/
Travistug
11 Sep 25 at 5:32 am
Write more, thats all I have to say. Literally, it seems as
though you relied on the video to make your point. You obviously know
what youre talking about, why throw away your intelligence on just posting videos to
your blog when you could be giving us something informative to read?
online order medicine
11 Sep 25 at 5:33 am
I do not know whether it’s just me or if everybody else experiencing issues
with your site. It looks like some of the
text on your content are running off the screen. Can someone else please comment and let me know if this
is happening to them too? This might be a problem with my internet browser because I’ve had this happen previously.
Cheers
Recommended Site
11 Sep 25 at 5:33 am
перепланировка квартиры в москве [url=www.proekt-pereplanirovki-kvartiry9.ru]перепланировка квартиры в москве[/url] .
proekt pereplanirovki kvartiri_lxpa
11 Sep 25 at 5:34 am
I’m now not sure the place you are getting your information, however great topic.
I needs to spend some time studying much more
or figuring out more. Thanks for great information I used to be on the lookout for
this info for my mission.
nạp tiền 88fc
11 Sep 25 at 5:36 am
перепланировка и согласование [url=https://www.soglasovanie-pereplanirovki-kvartiry17.ru]https://www.soglasovanie-pereplanirovki-kvartiry17.ru[/url] .
soglasovanie pereplanirovki kvartiri _jbol
11 Sep 25 at 5:36 am
Je suis fou de PlazaRoyal Casino, ca degage une ambiance de jeu digne d’une cour imperiale. Le repertoire du casino est une salle de bal ludique, comprenant des jeux de casino adaptes aux cryptomonnaies. L’assistance du casino est chaleureuse et irreprochable, offrant des solutions claires et instantanees. Le processus du casino est transparent et sans intrigues, parfois des recompenses de casino supplementaires feraient regner. En somme, PlazaRoyal Casino offre une experience de casino somptueuse pour ceux qui cherchent l’adrenaline royale du casino ! En plus la plateforme du casino brille par son style souverain, amplifie l’immersion totale dans le casino.
casino plaza royal|
glimmertoad3zef
11 Sep 25 at 5:37 am
электрокарниз недорого [url=www.elektrokarnizy5.ru]www.elektrokarnizy5.ru[/url] .
elektrokarnizi_icol
11 Sep 25 at 5:37 am
http://meditrustuk.com/# ivermectin cheap price online UK
Carrollalery
11 Sep 25 at 5:37 am
Наша философия проста: минимум медикаментов, максимум управляемости процесса. Мы не используем «универсальные капельницы», а собираем схему под клиническую картину: длительность запоя, выраженность тремора и тошноты, качество сна, уровень тревоги, исходное давление и частоту пульса, сопутствующие заболевания, текущие лекарства (антигипертензивные, антиаритмические, сахароснижающие, средства для сна). Скорость инфузии задаётся инфузоматом, витальные показатели контролируются портативным кардиомонитором и пульсоксиметром, глюкоза и электролиты — по экспресс-панелям. Такой подход снижает риск осложнений и делает результат предсказуемым и устойчивым.
Изучить вопрос глубже – [url=https://narcolog-na-dom-krasnodar14.ru/]врач нарколог выезд на дом в краснодаре[/url]
JasonTroke
11 Sep 25 at 5:38 am
просмотры youtube Хотите увеличить популярность своего Telegram-канала? Привлекайте больше подписчиков в Telegram, чтобы расширить аудиторию и повысить вовлеченность. Раскрутка канала – это путь к успеху!
MichaelFaunk
11 Sep 25 at 5:40 am
Harika bir yazı olmuş.
Bilgiler için sağ olun.
Uzun zamandır böyle bir içerik ihtiyacım vardı.
Kaleminize sağlık.
slot siteleri
11 Sep 25 at 5:41 am
onewin зеркало [url=https://1win12002.ru]https://1win12002.ru[/url]
1win_xnKa
11 Sep 25 at 5:42 am
компании занимащиеся офицально перепланировками квартир [url=soglasovanie-pereplanirovki-kvartiry17.ru]soglasovanie-pereplanirovki-kvartiry17.ru[/url] .
soglasovanie pereplanirovki kvartiri _xiol
11 Sep 25 at 5:43 am
проект по перепланировке квартиры цена [url=https://proekt-pereplanirovki-kvartiry9.ru]https://proekt-pereplanirovki-kvartiry9.ru[/url] .
proekt pereplanirovki kvartiri_lqpa
11 Sep 25 at 5:43 am
электрические гардины для штор [url=http://elektrokarnizy5.ru]http://elektrokarnizy5.ru[/url] .
elektrokarnizi_vtol
11 Sep 25 at 5:45 am
Book of Cats casinos TR
Josephhet
11 Sep 25 at 5:46 am
Приобрести диплом ВУЗа!
Наши специалисты предлагаютвыгодно купить диплом, который выполняется на оригинальной бумаге и заверен печатями, водяными знаками, подписями официальных лиц. Данный документ способен пройти любые проверки, даже при помощи специфических приборов. Достигайте свои цели быстро и просто с нашим сервисом- [url=http://consult-finder.tangent.wales/employer/aurus-diplomany/]consult-finder.tangent.wales/employer/aurus-diplomany[/url]
Jariorohh
11 Sep 25 at 5:46 am
Если в состоянии пациента наблюдаются такие признаки, как судороги, панические атаки, или гипертонический криз, необходимо немедленно вызвать врачей. Задержка может привести к необратимым последствиям.
Углубиться в тему – http://алко-ребцентр.рф
AndrewCag
11 Sep 25 at 5:47 am
доброй ночи ровной ветке!
https://hoo.be/bydyhiuiuduy
с треками магазин всегда спешит:) и качество скоро заценим)))
RogerCer
11 Sep 25 at 5:47 am
карнизы с электроприводом купить [url=https://www.elektrokarnizy5.ru]https://www.elektrokarnizy5.ru[/url] .
elektrokarnizi_wlol
11 Sep 25 at 5:48 am