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!
https://www.lenotoplenie.ru узнайте больше о возможностях бонусных предложений
Aaronawads
23 Oct 25 at 12:15 am
changetheworld – Really interesting content—keeps me coming back each every day.
Antonia Arenos
23 Oct 25 at 12:17 am
где купить диплом медицинского колледжа [url=https://www.frei-diplom7.ru]https://www.frei-diplom7.ru[/url] .
Diplomi_ilei
23 Oct 25 at 12:17 am
exploreopportunitiesnow.click – Website layout is smooth and user-friendly, browsing felt effortless today.
Allan Rogness
23 Oct 25 at 12:19 am
Дизайнерский ремонт: искусство преображения пространства
Дизайн интерьера играет важную роль в создании комфортной и уютной атмосферы в доме. Сегодня мы поговорим о таком понятии, как дизайнерский ремонт, который позволяет превратить обычное жилье в уникальное пространство, отражающее индивидуальность владельца.
[url=https://designapartment.ru ]дизайнерский ремонт коттеджа под ключ[/url]
Что такое дизайнерский ремонт?
Дизайнерский ремонт — это комплекс работ, направленных на создание оригинального дизайна помещения. Это не просто обновление отделки, а полноценный творческий процесс, включающий разработку концепции, подбор материалов и мебели, а также реализацию проекта.
Ключевые особенности дизайнерского ремонта:
– Индивидуальный подход к каждому проекту.
– Использование качественных материалов и современных технологий.
– Создание уникального стиля, соответствующего вкусам заказчика.
– Оптимизация пространства для максимального комфорта и функциональности.
Виды дизайнерских ремонтов
[url=https://designapartment.ru ]дизайнерский ремонт с мебелью москва[/url]
Существует несколько видов дизайнерских ремонтов, каждый из которых имеет свои особенности и преимущества.
#1 Дизайнерский ремонт квартиры
Это наиболее распространенный вид ремонта, подходящий для тех, кто хочет обновить интерьер своей городской квартиры. Специалисты разрабатывают проект, учитывая размеры помещений, пожелания клиента и бюджет. Такой ремонт включает перепланировку, замену коммуникаций, отделочные работы и декорирование.
Пример дизайна: светлая гостиная с панорамными окнами, минималистичный дизайн кухни и спальни в стиле лофт.
#2 Дизайнерский ремонт дома
Такой ремонт предполагает полное преобразование жилого дома, начиная от фундамента и заканчивая крышей. Здесь важно учитывать архитектурные особенности здания, климатические условия региона и предпочтения владельцев. Часто используется экодизайн, натуральные материалы и энергосберегающие технологии.
Пример дизайна: просторный холл с камином, стеклянная веранда с видом на сад, спальня в пастельных тонах.
[url=https://designapartment.ru]дизайнерский ремонт коттеджа под ключ[/url]
#3 Дизайнерский ремонт виллы
Ремонт вилл требует особого подхода, поскольку такие объекты часто расположены в живописных местах и имеют большую площадь. Важно сохранить гармонию с окружающей средой, используя природные материалы и цвета. Особое внимание уделяется созданию зон отдыха, бассейнов и садов.
Пример дизайна: роскошная вилла с бассейном, открытая терраса с видами на море, спальная зона в тропическом стиле.
#4 Дизайнерский ремонт коттеджа
Коттедж отличается от обычного дома наличием придомового участка и возможностью организации дополнительных функциональных зон. Ремонт коттеджей включает работу над фасадом, ландшафтом и внутренним пространством. Стили могут варьироваться от классики до хай-тека.
Пример дизайна: двухэтажный коттедж с мансардой, гостиная-столовая в скандинавском стиле, детская комната с игровой зоной.
#5 Дизайнерский ремонт пентхауса
Пентхаус — это элитное жилье, расположенное на верхних этажах зданий с панорамными видами. Для такого типа недвижимости характерны высокие потолки, большие окна и эксклюзивные элементы декора. Проектирование пентхауса требует учета особенностей конструкции здания и пожеланий клиентов относительно приватности и удобства.
Пример дизайна: современный пентхаус с открытой планировкой, кабинет с видом на город, зона отдыха с джакузи.
Заключение
Дизайнерский ремонт — это возможность создать идеальное пространство для жизни и отдыха. Независимо от того, хотите ли вы обновить квартиру, дом, виллу, коттедж или пентхаус, профессиональный подход гарантирует вам комфорт и эстетическое удовольствие на долгие годы.
https://designapartment.ru
дизайнерский ремонт квартиры под ключ москва
StevenKeype
23 Oct 25 at 12:21 am
I really love your blog.. Great colors & theme. Did you create this site yourself?
Please reply back as I’m hoping to create my own personal site and would like to learn where
you got this from or what the theme is named. Thank you!
LarevixInvest Erfahrungen
23 Oct 25 at 12:23 am
В Краснодаре клиника «Детокс» проводит выезд нарколога на дом для безопасного вывода из запоя.
Исследовать вопрос подробнее – [url=https://narkolog-na-dom-krasnodar26.ru/]вызвать врача нарколога на дом в краснодаре[/url]
Victorplaus
23 Oct 25 at 12:23 am
discoverendlessideas – Comments seem authentic, community is interactive, feels like a real hub.
Monserrate Loegering
23 Oct 25 at 12:24 am
юридический перевод [url=www.teletype.in/@alexd78/HN462R01hzy/]www.teletype.in/@alexd78/HN462R01hzy/[/url] .
Vidi perevodov v buro Perevod i Pravo_fest
23 Oct 25 at 12:24 am
купить диплом в прокопьевске [url=http://rudik-diplom12.ru]купить диплом в прокопьевске[/url] .
Diplomi_hwPi
23 Oct 25 at 12:24 am
Клиника «Похмельная служба» в Нижнем Новгороде предлагает капельницу от запоя с выездом на дом. Наши специалисты обеспечат вам комфортное и безопасное лечение в привычной обстановке.
Разобраться лучше – [url=https://vyvod-iz-zapoya-nizhnij-novgorod11.ru/]анонимный вывод из запоя в нижний новгороде[/url]
JessiesoYmn
23 Oct 25 at 12:26 am
ПО ВРЕМЕНИ СКОЛЬКО?
Приобрести MEF GASH SHIHSKI ALFA – ОТЗЫВЫ, ГАРАНТИИ, КАЧЕСТВО
Всем привет !!!
Thomasneump
23 Oct 25 at 12:27 am
Minotaurus coin’s utility in boosts and customizations is practical. ICO’s community building events foster loyalty. Early stage feels opportunistic.
minotaurus presale
WilliamPargy
23 Oct 25 at 12:27 am
was ist handicap beim wetten
My webpage – wettbüro quoten – Judy –
Judy
23 Oct 25 at 12:28 am
Hi there to every one, for the reason that I am truly
eager of reading this website’s post to be updated daily. It carries good data.
spam
23 Oct 25 at 12:28 am
медицинский перевод заключений [url=www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16/]www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16/[/url] .
Medicinskii perevod_ziEr
23 Oct 25 at 12:30 am
что такое технические перевод [url=http://dzen.ru/a/aPFFa3ZMdGVq1wVQ/]http://dzen.ru/a/aPFFa3ZMdGVq1wVQ/[/url] .
Tehnicheskii perevod_suml
23 Oct 25 at 12:30 am
Sildenafil ohne Rezept: Sildenafil 100 mg bestellen – MediVertraut
WilliamUnjup
23 Oct 25 at 12:32 am
медицинский перевод выписок [url=https://www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16]https://www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16[/url] .
Medicinskii perevod_ngEr
23 Oct 25 at 12:32 am
Технический перевод [url=https://dzen.ru/a/aPFFa3ZMdGVq1wVQ/]dzen.ru/a/aPFFa3ZMdGVq1wVQ[/url] .
Tehnicheskii perevod_elml
23 Oct 25 at 12:32 am
I appreciate, result in I found exactly what I was having a look for.
You have ended my four day long hunt! God Bless you man. Have a great day.
Bye
web site
23 Oct 25 at 12:33 am
Вызов нарколога на дом в Краснодаре — услуга клиники «Детокс». Специалисты оказывают квалифицированную помощь прямо у вас дома.
Подробнее – [url=https://narkolog-na-dom-krasnodar27.ru/]вызвать нарколога на дом срочно краснодар[/url]
Davidles
23 Oct 25 at 12:33 am
I visit every day a few web pages and information sites to read articles, but this website offers quality
based content. https://lombokprimeland.com/author/desiree4917416/
купить аттестат 11 класс
23 Oct 25 at 12:34 am
В Краснодаре клиника «Детокс» предлагает услугу выезда нарколога на дом. Быстро, безопасно, анонимно.
Подробнее можно узнать тут – [url=https://narkolog-na-dom-krasnodar29.ru/]www.narkolog-na-dom-krasnodar29.ru[/url]
BrianDrura
23 Oct 25 at 12:37 am
медицинский перевод [url=http://teletype.in/@alexd78/HN462R01hzy/]http://teletype.in/@alexd78/HN462R01hzy/[/url] .
Vidi perevodov v buro Perevod i Pravo_hvst
23 Oct 25 at 12:39 am
вірші на відкриття меморіальної дошки
JessieVinge
23 Oct 25 at 12:41 am
SanteHommeFrance [url=http://santehommefrance.com/#]sildenafil 50 mg ou 100 mg posologie[/url] pharmacie en ligne fiable France
CharlesNeono
23 Oct 25 at 12:41 am
Estas tareas generalmente consumen el tiempo del creador de
videos y a menudo no son posibles en software de edición básico.
descargar videos de youtube zeemo
23 Oct 25 at 12:43 am
технический перевод в металлургии [url=https://dzen.ru/a/aPFFa3ZMdGVq1wVQ]https://dzen.ru/a/aPFFa3ZMdGVq1wVQ[/url] .
Tehnicheskii perevod_rjml
23 Oct 25 at 12:44 am
ошибки медицинского перевода [url=https://www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16]https://www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16[/url] .
Medicinskii perevod_rpEr
23 Oct 25 at 12:44 am
купить диплом техникума образец в спб [url=https://frei-diplom7.ru]купить диплом техникума образец в спб[/url] .
Diplomi_wnei
23 Oct 25 at 12:48 am
you are in point of fact a excellent webmaster.
The site loading speed is incredible. It seems that you
are doing any unique trick. Moreover, The contents are masterwork.
you have performed a great activity on this subject!
helpful
23 Oct 25 at 12:49 am
http://lenotoplenie.ru/ сайт, где собраны инструкции по получению фрибетов и бонусов
Aaronawads
23 Oct 25 at 12:52 am
перевод медицинских документов [url=https://teletype.in/@alexd78/HN462R01hzy]https://teletype.in/@alexd78/HN462R01hzy[/url] .
Vidi perevodov v buro Perevod i Pravo_xyst
23 Oct 25 at 12:52 am
The upcoming new physical гoom аt OMT assures immersive math experiences, stimulating lifelong love fоr the subject and
inspiration for examination accomplishments.
Experience versatile learning anytime, ɑnywhere tһrough
OMT’s tһorough online e-learning platform, including unlimited access tⲟ
video lessons ɑnd interactive quizzes.
Singapore’ѕ worⅼd-renowned math curriculum highlights conceptual understanding ߋver simple computation,
makіng math tuition crucial fօr students to understand deep concepts ɑnd stand out in national exams lіke PSLE ɑnd O-Levels.
With PSLE math contributing considerably tо total scores, tuition рrovides additional resources ⅼike model responses fօr pattern recognition ɑnd algebraic thinking.
Introducing heuristic techniques early in secondary tuition prepares trainees fοr the non-routine troubles thаt typically ɑppear іn O
Level analyses.
With routine simulated exams ɑnd in-depth comments, tuition aids junior
college trainees identify аnd correct weaknesses prior tⲟ
the actual A Levels.
OMT’s custom-maԁe curriculum uniquely straightens wіtһ MOE structure by offering linking modules fоr
smooth ⅽhanges between primary, secondary, andd JC
math.
Flexible scheduling mеans no encountering
CCAs ⲟne, mаking certain balanced life and increasing math scores.
Singapore’ѕ emphasis on analytic in math exams makeѕ tuition crucial f᧐r
creating crucial assuming skills pasxt school һours.
Ηere iѕ mу web page; math tuition singapore (Laura)
Laura
23 Oct 25 at 12:52 am
You’ve made some really good points there.
I looked on the internet for more info about the issue and found most individuals
will go along with your views on this website.
beginner sports guide
23 Oct 25 at 12:55 am
Термальный комплекс Термбург — это место, где можно восстановиться телом и умом. Всё продумано для релакса и заботы о теле: современные бани и сауны, бассейны с кристально чистой водой, термы и залы для массажа. Атмосфера спокойствия и уюта помогает перезагрузить мысли и наполниться силами уже после первых минут пребывания.
Особого внимания заслуживает [url=https://termburg.ru/news/kollektivnye-pareniya-v-komplekse-termburg/]коллективные парения термы[/url] — это не просто эстетический ритуал, а способ улучшить тонус, улучшить питание тканей и вернуть лицу естественное сияние. Опытные мастера работают по авторским методикам — от расслабляющего до тканевого массажа. Результат виден уже после первого сеанса — лёгкость, свежесть и ровный тон кожи.
Для тех, кто предпочитает активный отдых, работает [url=https://termburg.ru/]термбург термальный комплекс москва[/url] и массаж спины и шеи. Занятия проходят под руководством сертифицированных специалистов, программы разработаны для всех уровней подготовки. Здесь формируют правильную технику плавания, повышают выносливость и дарят удовольствие от каждого движения. Баланс тела и разума — всё, что нужно, чтобы вернуться к себе обновлённым.
Leviomaza
23 Oct 25 at 12:56 am
0pdpof.xyz – Pages load instantly, no lag anywhere while exploring the content.
Lavinia Innes
23 Oct 25 at 12:56 am
диплом юридического колледжа купить [url=http://www.frei-diplom7.ru]http://www.frei-diplom7.ru[/url] .
Diplomi_laei
23 Oct 25 at 12:58 am
The Inheritance Games Canada: A thrilling mystery game where players unravel secrets, solve puzzles, and compete for a billionaire’s fortune. Perfect for fans of strategy and suspense: Jennifer Lynn Barnes author site
GabrielLyday
23 Oct 25 at 12:59 am
https://www.lenotoplenie.ru официальный источник актуальных бонусных предложений
Aaronawads
23 Oct 25 at 12:59 am
Если вы ищете надежную клинику для вывода из запоя, обратитесь в «Детокс» в Краснодаре. Услуга вызова нарколога на дом доступна круглосуточно. Врачи приедут к вам в течение 1–2 часов и окажут необходимую помощь.
Ознакомиться с деталями – [url=https://narkolog-na-dom-krasnodar29.ru/]www.narkolog-na-dom-krasnodar29.ru[/url]
BrianDrura
23 Oct 25 at 1:04 am
перевод медицинских документов [url=www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16]www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16[/url] .
Medicinskii perevod_foEr
23 Oct 25 at 1:06 am
J’adore l’aura divine d’ Olympe Casino, c’est une plateforme qui evoque l’Olympe. Les options sont vastes comme un pantheon, incluant des paris sportifs epiques. Amplifiant l’aventure de jeu. Le service est disponible 24/7, joignable a toute heure. Les retraits sont rapides comme un eclair de Zeus, cependant des offres plus genereuses seraient olympiennes. Dans l’ensemble, Olympe Casino est un incontournable pour les joueurs pour les joueurs en quete d’epopee ! En bonus le site est rapide et glorieux, amplifie le plaisir de jouer. Un plus divin le programme VIP avec des niveaux exclusifs, qui booste l’engagement.
olympefr.com|
ZeusThunderA4zef
23 Oct 25 at 1:06 am
Технический перевод [url=https://dzen.ru/a/aPFFa3ZMdGVq1wVQ/]dzen.ru/a/aPFFa3ZMdGVq1wVQ[/url] .
Tehnicheskii perevod_lyml
23 Oct 25 at 1:06 am
где купить дипломы медсестры [url=http://frei-diplom14.ru]где купить дипломы медсестры[/url] .
Diplomi_vroi
23 Oct 25 at 1:07 am
Вызов нарколога на дом через «Stop-Alko» в Екатеринбурге — это помощь, когда вы не можете самостоятельно добраться до клиники. Первая помощь сразу у вас дома.
Получить дополнительную информацию – [url=https://vyvod-iz-zapoya-ekaterinburg26.ru/]вывод из запоя вызов на дом[/url]
ClydeLak
23 Oct 25 at 1:08 am
каталог seo агентств [url=http://reiting-seo-kompaniy.ru/]http://reiting-seo-kompaniy.ru/[/url] .
reiting seo kompanii_hlon
23 Oct 25 at 1:08 am
74364.pw – Bookmarking this site; updates seem frequent, insightful, and genuinely practical.
Isiah Gerdel
23 Oct 25 at 1:09 am
медицинский перевод справок [url=www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16]www.telegra.ph/Medicinskij-perevod-tochnost-kak-vopros-zhizni-i-zdorovya-10-16[/url] .
Medicinskii perevod_byEr
23 Oct 25 at 1:09 am