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://vyvod-iz-zapoya-yaroslavl0.ru/]вывод из запоя анонимно ярославль[/url]
Walterionib
15 Oct 25 at 4:42 pm
crypto exchange reviews
Williameleri
15 Oct 25 at 4:44 pm
https://telegra.ph/Kupit-nedorogoj-horoshij-benzogenerator-10-13-3
FrankieBat
15 Oct 25 at 4:46 pm
Прежде чем принимать решение, важно изучить сайт клиники. В надёжных учреждениях размещена полная информация о врачах, их образовании и опыте работы. Кроме того, пациентам предлагается пройти предварительную консультацию — чаще всего она проводится анонимно и включает первичную диагностику. Это позволяет оценить профессионализм команды ещё до начала терапии.
Ознакомиться с деталями – [url=https://narkologicheskaya-klinika-yaroslavl0.ru/]наркологическая клиника цены[/url]
ChrisWeall
15 Oct 25 at 4:47 pm
Автоюрист — это специалист в области
права, который занимается вопросами, связанными
с автомобилями и дорожным
движением.
Когда стоит обратиться к автоюристу?
Существует множество ситуаций, когда услуги
автоюриста могут оказаться полезными:
Дорожно-транспортные происшествия и их последствия.
Споры по поводу штрафов за нарушения
правил дорожного движения.
Формирование исковых документов и жалоб.
Защита интересов клиента в судебных инстанциях.
Автоюрист и помощь при ДТП
При ДТП водители часто оказываются в ситуации, требующей защиты
своих прав. Автоюрист поможет:
Собрать необходимые документы.
Детально изложить обстоятельства
происшествия.
Выступить от имени клиента в судебных и административных органах.
Оспаривание штрафов и юридическая помощь
После получения штрафа у многих владельцев
автомобилей возникают сомнения
в его законности. Автоюрист
может:
Провести анализ данных о правонарушении.
Составить апелляцию на решение о штрафе.
Разъяснить особенности административного разбирательства.
Критерии выбора автоюриста в Москве
При выборе автоюриста в Москве важно учитывать несколько
факторов:
Практический опыт работы юриста.
Высокий уровень профессионализма юриста достигается
с увеличением его практического опыта.
Репутация компании по отзывам клиентов.
Изучите отзывы о компании.
Ценовая политика услуг.
Обсудите предварительные расценки и условия
оплаты.
Как связаться с автоюристом
Не упускайте возможность связаться с автоюристом, чтобы
обсудить интересующие вас вопросы.
Квалифицированный специалист всегда готов предоставить консультацию и обсудить
детали вашей ситуации.
Заключение
Консультация с автоюристом — это необходимый шаг для защиты прав владельца автомобиля.
Не стоит забывать, что в сфере автомобильного
права лучше заранее позаботиться
о своих интересах, чем позднее решать возникшие проблемы.
Доверьте свои интересы специалистам! осаго дтп Заключение
Сегодня правовые навыки и способность их
использовать приобретают особую ценность для владельцев автомобилей.
Если у вас возникли вопросы, касающиеся вашего автомобиля, будь то административные проблемы или участие в дорожно-транспортных происшествиях,
вам явно понадобятся услуги автоюриста.
Хорошая юридическая поддержка не только поможет
сохранить ваши деньги, но и защитит ваши права.
Зачем нужно обращаться к автоюристу?
Автоюрист — это специалист, который обладает
знаниями и опытом в области автомобильного права.
Специалист сможет предложить вам следующие услуги:
Подготовить юридически корректные документы для судебного разбирательства;
Успешно оспорить штрафы и другие наказания;
Обеспечить получение компенсации за ущерб,
причиненный в результате ДТП;
Консультироваться по правам и обязанностям водителей;
Разобраться в сложных ситуациях, связанных с вашим автомобилем.
Рекомендации по выбору автоюриста
Выбирая автоюриста в Москве или любом другом городе, следует обращать
внимание на такие аспекты:
Опыт работы в сфере автомобильного права;
Мнения клиентов и имидж компании;
Специализация на различных аспектах автоюриспруденции;
Доступность связи (например, по телефону) и
готовность к сотрудничеству;
Итог по вопросу автоюристов
В условиях постоянных изменений правил и законодательства
в России, поддержка профессионала в области автоюриспруденции становится необходимостью.
Не оставляйте свои права без надлежащей
защиты — опытный автоюрист способен помочь вам
разобраться с любыми вопросами касательно вашего автомобиля.
Помните, что своевременная консультация может существенно
облегчить вашу жизнь и помочь избежать лишних денежных затрат.
При возникновении проблем на дороге, не бойтесь обратиться
к автоюристу. Это верный
шаг к защите ваших прав и интересов!
https://r12imob.store/index.php?page=user&action=pub_profile&id=743006
15 Oct 25 at 4:47 pm
где купить диплом техникума старого образца [url=http://www.frei-diplom12.ru]где купить диплом техникума старого образца[/url] .
Diplomi_mnPt
15 Oct 25 at 4:48 pm
натяжные потолки нижний новгород [url=www.natyazhnye-potolki-nizhniy-novgorod.ru]www.natyazhnye-potolki-nizhniy-novgorod.ru[/url] .
natyajnie potolki nijnii novgorod_trOt
15 Oct 25 at 4:48 pm
buy clomid: buy propecia – online pharmacy 365 pills
Andresstold
15 Oct 25 at 4:49 pm
купить диплом в анжеро-судженске [url=https://rudik-diplom6.ru/]https://rudik-diplom6.ru/[/url] .
Diplomi_sbKr
15 Oct 25 at 4:50 pm
PIDORCAM
PIDORCAM
15 Oct 25 at 4:51 pm
все онлайн займы [url=zaimy-28.ru]все онлайн займы[/url] .
zaimi_ggKa
15 Oct 25 at 4:52 pm
Хочешь пиццу? доставка пиццы в Туле быстро, вкусно и горячо! Заказывайте пиццу с доставкой на дом или в офис. Большой выбор начинок, свежие ингредиенты, акции и бесплатная доставка по городу.
tula.pizzeria-583
15 Oct 25 at 4:52 pm
Spin Rise Casino
FrankAmoum
15 Oct 25 at 4:56 pm
When I initially commented I clicked the “Notify me when new comments are added” checkbox and
now each time a comment is added I get three e-mails with the same comment.
Is there any way you can remove me from that service?
Thanks a lot!
Vibrating sleeve rating
15 Oct 25 at 4:57 pm
Appreciate this post. Let me try it out.
make money online
15 Oct 25 at 4:59 pm
Its not my first time to go to see this web page, i am visiting this site dailly and obtain nice facts from
here everyday.
Paito Warna Cambodia Bom
15 Oct 25 at 4:59 pm
Secondary school math tuition іs vital in Singapore, helping ʏouг Secondary 1 student overcome transitional challenges аnd achieve consistent academic progress.
Steady оnly, Singapore students shine аt tһe toⲣ
of worⅼd math leagues!
As moms and dads іn Singapore, stay ahead ѡith evolving Singapore math tuition.
Secondary math tuition adapts rapidly t᧐ ϲhanges.
Throսgh secondary 1 math tuition, exponential notations cliϲk early.
Secondary 2 math tuition encourages exploration of math history.
Secondary 2 math tuition shares stories ƅehind theorems.
Τhіs enriching secondary 2 math tuition аdds depth to lessons.
Secondary 2 math tuition inspires curiosity.
Ꭲһe impօrtance оf secondary 3 math exams cɑn not be overstated, aѕ O-Levels follow in fast succession, screening deepened applications.
Quality һere enables participation in math olympiads, improving
resumes fօr post-secondary applications. It
develops analytical skills essential fⲟr Singapore’s tech
economy.
Secondary 4 exams honor timelessly іn Singapore.
Secondary 4 math tuition archives access. Ƭhis context enhances O-Level.
Secondary 4 math tuition honors.
Ꭰоn’t ѵiew math ѕolely for exams; it’s a cornerstone skill іn exploding AӀ, enabling fraud
detection іn e-commerce.
To excel in mathematics, develop love аnd usе math іn real-world daily.
To prepare holistically, ⲣast papers fгom dіfferent Singapore secondary schools һelp in integrating cross-topic knowledge for math tests.
Ᏼy engaging ѡith online math tuition e-learning systems, learners іn Singapore gain personalized
feedback, leading tⲟ betteг performance in secondary math assessments.
Wah lao аh, don’t worry lor, your child strong for secondary
school, support gently.
Individualized guidance from OMT’s seasoned tutors assists
students conquer math hurdles, fostering а heartfelt connection tο the
subject and iceas fоr tests.
Broaden youг horizons ᴡith OMT’ѕ upcoming
new physical space ⲟpening in Ѕeptember 2025,
providing еνen mοre chances for hands-on math expedition.
As math forms tһe bedrock оf rational thinking aand vital analytical іn Singapore’ѕ education system,
expert math tuition οffers the customized guidance required
t᧐ tսrn difficulties іnto accomplishments.
Tuition programs fоr primary school math concentrate ⲟn error analysis frօm previous
PSLE papers, teaching trainees tо аvoid repeating mistakes in estimations.
Вy սsing extensive exercise ԝith previous O Level papers, tuition furnishes
pupils ᴡith familiarity ɑnd thhe capability
tо expect concern patterns.
Іn a competitive Singaporean education ɑnd learning ѕystem, junior college math tuition ցives pupils tһe sіde to attain һigh grades
essential foг university admissions.
Distinctive fгom оthers, OMT’s syllabus complements MOE’ѕ vіa a concentrate on resilience-building workouts, assisting trainees tackle tough
troubles.
OMT’ѕ оn-ⅼine system advertises ѕеⅼf-discipline lor, trick t᧐
constant research аnd gгeater examination outcomes.
Ϝor Singapore pupils facing extreme competition, math tuition guarantees tһey stay ahead Ьy enhancing foundational
abilities early оn.
Feel free to visit my һomepage … additional math tuition singapore
additional math tuition singapore
15 Oct 25 at 5:00 pm
PIDORCAM
PIDORCAM
15 Oct 25 at 5:00 pm
$MTAUR presale is flying under radar but shouldn’t—80% discount is insane value. In-game mini-games unlocked by tokens add replayability. Bullish on its 9% annual market growth projection.
mtaur coin
WilliamPargy
15 Oct 25 at 5:02 pm
ordering drugs from canada: trusted online pharmacy USA – trusted online pharmacy USA
AndrewPal
15 Oct 25 at 5:02 pm
потолочки [url=https://natyazhnye-potolki-nizhniy-novgorod.ru]https://natyazhnye-potolki-nizhniy-novgorod.ru[/url] .
natyajnie potolki nijnii novgorod_drOt
15 Oct 25 at 5:03 pm
1win qeydiyyat linki [url=www.1win5004.com]www.1win5004.com[/url]
1win_dwoi
15 Oct 25 at 5:05 pm
Hiya! I know this is kinda off topic but I’d figured I’d ask.
Would you be interested in trading links or maybe guest authoring a
blog post or vice-versa? My site discusses a lot of the same topics as yours and I
think we could greatly benefit from each other. If you happen to be
interested feel free to send me an e-mail. I look forward to hearing from you!
Great blog by the way!
turkey visa for australian
15 Oct 25 at 5:05 pm
is crypto legal in europe
Williameleri
15 Oct 25 at 5:05 pm
social live
MichaelSig
15 Oct 25 at 5:07 pm
Reveal tһe most effective ⲟf Singapore’s shopping scene at Kaizenaire.cօm, where top promotions from
favorite brands ɑre curated simply fⲟr you.
In Singapore, promotions aгe king in this shopping paradise, loved Ьy deal-lovingSingaporeans.
Checking оut street art іn areаs liҝe Haji Lane motivates innovative Singaporeans, аnd ҝeep in mind to stay upgraded
ⲟn Singapore’ѕ most current promotions ɑnd shopping deals.
STEngineerting supplies aerospace аnd defense engineering solutions, valued bʏ Singaporeans foг
tһeir advancement in technology ɑnd national payments.
Bank of Singapore ɡives personal banking ɑnd riches management ѕia, valued by upscale Singaporeans fоr their tailored economic
recommendations lah.
Тhе Soup Spoon ladles ᧐ut passionate soups ɑnd salads, ⅼiked f᧐r wholesome, global-inspired bowls tһat match health-conscious restaurants.
Ԝhy ѕo lazy leh, simply сlick Kaizenaire.com typically оne,
obtained ⅼots of deals from favorite brand names ѡaiting.
My webpage … Deals Singapore
Deals Singapore
15 Oct 25 at 5:08 pm
1win tətbiqi [url=http://1win5004.com]http://1win5004.com[/url]
1win_nnoi
15 Oct 25 at 5:09 pm
1win qeydiyyat yoxlaması [url=www.1win5005.com]1win qeydiyyat yoxlaması[/url]
1win_pmml
15 Oct 25 at 5:10 pm
купить диплом в арзамасе [url=https://rudik-diplom6.ru/]купить диплом в арзамасе[/url] .
Diplomi_ebKr
15 Oct 25 at 5:10 pm
Hurrah! After all I got a blog from where I be able to actually
take valuable information concerning my study and knowledge.
turkey visa on arrival for australian
15 Oct 25 at 5:14 pm
потолочников натяжные потолки [url=https://natyazhnye-potolki-nizhniy-novgorod.ru/]https://natyazhnye-potolki-nizhniy-novgorod.ru/[/url] .
natyajnie potolki nijnii novgorod_laOt
15 Oct 25 at 5:14 pm
Aw, this was a really nice post. Spending some time and actual effort to create a superb article… but what can I say…
I hesitate a lot and don’t manage to get anything done.
https://566-app.com/
15 Oct 25 at 5:15 pm
https://zencaremeds.com/# safe online medication store
MervinWoorE
15 Oct 25 at 5:16 pm
With $MTAUR coin, collecting in-game currency while running mazes is addictive. Presale bonuses for vesting make holding appealing. Team’s track record impresses me.
mtaur token
WilliamPargy
15 Oct 25 at 5:16 pm
Spinrise Casino
FrankAmoum
15 Oct 25 at 5:17 pm
Yes! Finally someone writes about https://www.instagram.com/ivfmexico#ivf mexico.
ivf mexico
15 Oct 25 at 5:17 pm
https://online-spr2.ru/
ZacharyFat
15 Oct 25 at 5:18 pm
I’ve been exploring for a little for any high-quality articles or weblog posts on this kind of space .
Exploring in Yahoo I eventually stumbled upon this web site.
Studying this information So i am happy to show that I’ve
an incredibly just right uncanny feeling I came upon just
what I needed. I most definitely will make sure to do not put out of your mind this website and provides it a glance regularly.
astrologia
15 Oct 25 at 5:19 pm
What’s up everyone, it’s my first go to see at this site, and
article is really fruitful designed for me, keep up posting such articles.
sga22
15 Oct 25 at 5:23 pm
Hi! I could have sworn I’ve visited this site before but after looking
at many of the posts I realized it’s new to me.
Anyways, I’m certainly happy I found it and I’ll be bookmarking it and checking back regularly!
Stretchable stroker
15 Oct 25 at 5:24 pm
Refresh Renovation Southwest Charlotte
1251 Arrow Pine Ɗr c121,
Charlotte, NC 28273, Unnited Ѕtates
+19803517882
Renovations custom and build design
Renovations custom and build design
15 Oct 25 at 5:25 pm
купить свидетельство о браке [url=http://rudik-diplom1.ru]купить свидетельство о браке[/url] .
Diplomi_dger
15 Oct 25 at 5:27 pm
Joined $MTAUR coin presale—easy entry. ICO’s marketing sharp. Creatures whimsical.
minotaurus presale
WilliamPargy
15 Oct 25 at 5:27 pm
cryptomagneto.com
Williameleri
15 Oct 25 at 5:27 pm
аренда грузоподъемной техники [url=https://arenda-mini-ekskavatora-v-moskve.ru/]аренда грузоподъемной техники[/url] .
arenda mini ekskavatora v moskve_sgEn
15 Oct 25 at 5:27 pm
devoted the remainder of hislife to making strenuous efforts to maintain and educate the orphanEven when the police official was spending his evenings at the theatre,ラブドール 女性 用the worthy actor generally filled his place in the family circle,
セックス 人形
15 Oct 25 at 5:28 pm
натяж потолки [url=https://www.natyazhnye-potolki-nizhniy-novgorod.ru]https://www.natyazhnye-potolki-nizhniy-novgorod.ru[/url] .
natyajnie potolki nijnii novgorod_sdOt
15 Oct 25 at 5:31 pm
TG @‌LINKS_DEALER | EFFECTIVE SEO LINKS FOR SPINBETTERBET.COM
Jamesrab
15 Oct 25 at 5:32 pm
https://slovarikslov.ru/terem/xaus/
https://slovarikslov.ru/terem/xaus/
15 Oct 25 at 5:37 pm
It’s hard to find experienced people in this particular subject, but you seem
like you know what you’re talking about! Thanks
bästa svenska casino
15 Oct 25 at 5:39 pm