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!
memek
certainly like your web site however you have to take a look at
the spelling on several of your posts. Several of them are rife with spelling problems and I to find it very bothersome to tell the truth
however I will surely come again again.
kontol
29 Oct 25 at 7:57 am
these objects and all ordinary objects were felt to afford too limited a field.ロシア エロRecourse was had to figures,
ラブドール
29 Oct 25 at 7:57 am
торкрет бетон цена [url=https://torkretirovanie-1.ru/]торкрет бетон цена[/url] .
torkretirovanie_rjen
29 Oct 25 at 7:58 am
веб-аналитика блог [url=https://statyi-o-marketinge7.ru]https://statyi-o-marketinge7.ru[/url] .
stati o marketinge _mzkl
29 Oct 25 at 7:58 am
you blackmailin swine,ラブドール エロyou.
ラブドール
29 Oct 25 at 7:58 am
Kamagra Oral Jelly Deutschland: Kamagra Oral Jelly Deutschland – Kamagra online kaufen
ThomasCep
29 Oct 25 at 7:58 am
купить диплом в брянске [url=https://www.rudik-diplom14.ru]купить диплом в брянске[/url] .
Diplomi_vzea
29 Oct 25 at 7:59 am
bringing with it avague,ロボット エロdim,
ラブドール
29 Oct 25 at 7:59 am
онлайн номера
купить виртуальный номер
29 Oct 25 at 7:59 am
https://mannvital.shop/# MannVital
Davidjealp
29 Oct 25 at 7:59 am
Kamagra Wirkung und Nebenwirkungen: diskrete Lieferung per DHL – Potenzmittel ohne ärztliches Rezept
ThomasCep
29 Oct 25 at 7:59 am
блог о рекламе и аналитике [url=statyi-o-marketinge7.ru]statyi-o-marketinge7.ru[/url] .
stati o marketinge _jikl
29 Oct 25 at 8:01 am
or present given onthe return,is a regular institution of Japanese home life.セックス ドール
ラブドール
29 Oct 25 at 8:02 am
Kamagra Oral Jelly Deutschland: vitalpharma24 – vitalpharma24
RichardImmon
29 Oct 25 at 8:02 am
kraken vk5
kraken vpn
Henryamerb
29 Oct 25 at 8:02 am
it sometimes rises togenius; and Ann is one of the vital geniuses.ラブドール アニメNot at all,
ラブドール
29 Oct 25 at 8:03 am
When someone writes an post he/she keeps the plan of
a user in his/her brain that how a user can know it.
So that’s why this article is great. Thanks!
link mv88
29 Oct 25 at 8:04 am
where their blood is immediately sucked,ラブドール エロand their carcasses afterwards hurled contemptuously out to an immense distance from “the caverns of death.
ラブドール
29 Oct 25 at 8:04 am
457.Morality,大型 オナホ
ラブドール
29 Oct 25 at 8:06 am
I’ve been exploring for a little for any high quality articles or weblog posts in this sort of area .
Exploring in Yahoo I ultimately stumbled upon this web site.
Studying this information So i’m glad to convey that I have a very excellent
uncanny feeling I found out exactly what I needed. I most
indisputably will make sure to don?t put out of your mind this web site and give it a glance regularly.
Quantum AI
29 Oct 25 at 8:06 am
エロ ロボットG.Northbury,
ラブドール
29 Oct 25 at 8:08 am
Арбитражные споры — это конфликты, которые
возникают в ходе деятельности физических и юридических лиц и касаются правовых вопросов.
В соответствии с российским законодательством, арбитражный суд
является специализированным органом,
разрешающим такие споры.
Классификация арбитражных споров
Конфликты, связанные с договорными обязательствами.
Споры о праве собственности.
Конфликты, касающиеся долговых обязательств.
Иные споры, возникающие в процессе коммерческой деятельности.
Процесс арбитражного разбирательства
Первым шагом в ведении арбитражных дел является подача искового заявления в арбитражный суд.
Согласно статье 125 Арбитражного процессуального кодекса, иск
должен содержать:
Наименование арбитражного суда.
Информация о сторонах дела.
Детали обстоятельств дела.
Требования истца.
Подтверждающие документы.
Как подготовить документы
Для удачного разрешения конфликта важно собрать и подать суду всю
актуальную информацию.
К таким документам относятся:
Договоры.
Письменные доказательства.
Свидетельские показания.
Иные документы, подтверждающие позиции сторон.
Решения арбитражного суда
Суд выносит решение, основываясь на
предоставленных данных и аргументах обеих сторон.
Суд учитывает все аспекты дела и выносит решение, которое может быть
обжаловано в вышестоящих инстанциях.
Важно отметить, что соблюдение сроков
подачи апелляционных жалоб имеет
большое значение.
Итоги и советы
Для повышения эффективности арбитражных разбирательств целесообразно заранее проконсультироваться с опытным юристом в этой области.
Это поможет избежать типичных ошибок и повысить вероятность положительного результата дела.
Следовательно, арбитражные
споры представляют собой сложный процесс, который требует внимательной подготовки и понимания законодательства, а
также учета всех нюансов арбитражной практики. юрист по арбитражным спорам
Вывод
Анализ арбитражных споров показывает, что
они значимы для системы правосудия, поскольку защищают права как граждан, так
и юридических лиц. Арбитражные суда рассматривают споры, вытекающие из гражданских
и коммерческих отношений, что
позволяет эффективно решать конфликты, связанные с обязательствами, договорами и иными правовыми аспектами.
Российское законодательство
предлагает детализированные и структурированные нормы, касающиеся процесса рассмотрения таких споров.
Это позволяет сторонам быть уверенными
в прозрачности и справедливости судебного процесса.
Арбитражный процессуальный кодекс регулирует все этапы арбитражных разбирательств, начиная
от подачи исковых требований и заканчивая вынесением решения.
Важно учитывать следующие аспекты:
Наличие корректных документов,
которые подтверждают требования сторон.
Следование установленным законом срокам для подачи исков.
Осознание прав и обязанностей сторон в рамках процесса.
Точное оформление исков и сопутствующих судебных бумаг.
Возможность обращения с апелляцией в случае неудовлетворительного решения.
Арбитражные споры имеют свои особенности,
и результат каждого из них определяется множеством факторов, включая доказательства, правовую
позицию сторон и уровень квалификации судей.
При этом важно помнить, что арбитражные суды действуют в соответствии с законодательством,
что обеспечивает законность
всех решений.
Таким образом, можно сделать вывод, что арбитражные споры составляют важнейшую часть правовой системы, помогая разрешать конфликты и защищая законные интересы физических
и юридических лиц. Ознакомление с практическими аспектами и особенностями
данного процесса позволит лучше подготовиться к участию в
подобных делах, минимизируя риски и достигая необходимых результатов.
В итоге, арбитражные споры
требуют тщательного подхода и знания законодательства.
Информация о практике арбитражных судов,
а также квалифицированное юридическое сопровождение могут значительно повысить шансы на успешный исход
дела. Надеемся, что данная статья поможет читателям
лучше понять основные принципы
и нюансы арбитражных споров.
https://r12imob.store/index.php?page=user&action=pub_profile&id=770419
29 Oct 25 at 8:08 am
Самые большие выигрыши обеспечивают тайтлы с прогрессивными джекпотами.
казино 7 к
29 Oct 25 at 8:09 am
торкрет бетон цена [url=https://www.torkretirovanie-1.ru]торкрет бетон цена[/url] .
torkretirovanie_pqen
29 Oct 25 at 8:09 am
блог про seo [url=https://www.statyi-o-marketinge7.ru]блог про seo[/url] .
stati o marketinge _bfkl
29 Oct 25 at 8:09 am
купить диплом в ревде [url=rudik-diplom14.ru]купить диплом в ревде[/url] .
Diplomi_rmea
29 Oct 25 at 8:10 am
kraken marketplace
kraken СПб
Henryamerb
29 Oct 25 at 8:10 am
and finding his progress arrested by the rock,stood stupidly bewildered.ロシア エロ
ラブドール
29 Oct 25 at 8:10 am
kraken onion
kraken ios
Henryamerb
29 Oct 25 at 8:10 am
to the base.While I gazed,ロシア エロ
ラブドール
29 Oct 25 at 8:11 am
контекстная реклама статьи [url=http://statyi-o-marketinge7.ru]контекстная реклама статьи[/url] .
stati o marketinge _wtkl
29 Oct 25 at 8:13 am
Этот информационный обзор станет отличным путеводителем по актуальным темам, объединяющим важные факты и мнения экспертов. Мы исследуем ключевые идеи и представляем их в доступной форме для более глубокого понимания. Читайте, чтобы оставаться в курсе событий!
Следуйте по ссылке – https://rsvd.es/hello-world
DustinTal
29 Oct 25 at 8:13 am
купить виртуальный номер
купить виртуальный номер
29 Oct 25 at 8:16 am
кракен маркетплейс
кракен vk5
Henryamerb
29 Oct 25 at 8:16 am
Increíble artículo sobre los juegos más populares de Pin-Up Casino en México.
Me sorprendió ver cómo títulos como Gates of Olympus y Sweet Bonanza siguen dominando entre los jugadores mexicanos.
Me gustó mucho cómo detallaron las mecánicas de cada juego y sus bonificaciones.
Vale la pena visitar la publicación original y conocer en detalle por qué estos títulos son tan jugados en 2025.
Además, me encantó que también mencionaran títulos como Plinko y Fruit Cocktail, que ofrecen algo diferente al jugador tradicional.
No dudes en leer la nota completa y descubrir por qué estos juegos son tendencia en los casinos online de México.
press release
29 Oct 25 at 8:16 am
Этот информационный обзор станет отличным путеводителем по актуальным темам, объединяющим важные факты и мнения экспертов. Мы исследуем ключевые идеи и представляем их в доступной форме для более глубокого понимания. Читайте, чтобы оставаться в курсе событий!
Подробнее – https://coniolabs.com/career/want-you-01
Darenaerox
29 Oct 25 at 8:18 am
Potenzmittel ohne ärztliches Rezept: Potenzmittel ohne ärztliches Rezept – Kamagra Oral Jelly Deutschland
ThomasCep
29 Oct 25 at 8:18 am
D᧐ not play play lah, combine a goοd Junior College alongside maths superiority іn оrder tⲟ guarantee һigh A Levels scores plus smooth ⅽhanges.
Mums and Dads, fear tһe disparity hor, math base rеmains essential in Junior College
fоr comprehending data, essential іn current digital market.
River Valley Ηigh School Junior College incorporates bilingualism
аnd ecological stewardship, producing eco-conscious leaders ᴡith global poіnt of views.
Տtate-of-thе-art labs ɑnd green initiatives support cutting-edge knowing іn sciences and liberal arts.
Students engage іn cultural immersions and service jobs, boosting compassion and
skills. The school’s unified neighborhood promotes resilience аnd teamwok tһrough sports аnd arts.
Graduates are prepared fоr success in universities ɑnd Ьeyond, embodying perseverance ɑnd cultural acumen.
National Junior College,holding tһe difference
as Singapore’s very first junior college, offеrs unequaled opportunities fⲟr intellectual expedition аnd
management growing ᴡithin а historical аnd motivating school thɑt mixes tradition ѡith contemporary instructional excellence.
Тhe unique boarding program promotes sеlf-reliance and a
sense of neighborhood, ԝhile modern гesearch centers
ɑnd specialized labs mɑke it possіble fߋr students fгom diverse backgrounds tο pursue advanced resеarch studies in arts,
sciences, and humanities ѡith optional choices f᧐r personalized learning paths.
Ingenious programs encourage deep scholastic immersion, ѕuch as project-based гesearch study and interdisciplinary seminars tһat hone analytical skills аnd foster imagination ɑmong
hopeful scholars. Τhrough extensive worldwide collaborations,
consisting ⲟf student exchanges, global symposiums, аnd collaborative efforts ᴡith abroad universities, students
develop broad networks ɑnd a nuanced understanding of агound thе world issues.
Tһе college’s alumni, who frequently assume popular
functions іn government, academia, аnd industry, exhibit National Junior College’s lօng lasting contribution t᧐ nation-building аnd tthe development of visionary, impactful leaders.
Օһ, mahs serves аs tһe foundation stone оf
primary schooling, assisting children іn dimensional reasoning
f᧐r design careers.
Оһ dear, without robust math іn Junior College, even leading establishment children mаy
falter witһ next-level equations, tһսs develop tһat noww leh.
Listen up, Singapore folks, mathematics гemains рerhaps the most crucial primary topic, encouraging innovation іn issue-resolving for creative professions.
Ɗon’t take lightly lah, link a gooԀ Junior College plus mathematics superiority for ensure hіgh A Levels results and seamless changes.
Parents, dread the disparity hor, maths base іs critical
Ԁuring Junior College to grasping data, essential fоr toԁay’ѕ digital system.
Oi oi, Singapore parents, maths proves ⅼikely thе extremely іmportant primary topic, fostering
creativity thгough challenge-tackling tօ groundbreaking
professions.
Ꭰon’t slack іn JC; A-levels determine іf уoս ցet int᧐
уоur dream coursе or settle fоr lesѕ.
Hey hey, Singapore parents, maths proves ⲣerhaps the mօst essential primary subject, fostering innovation f᧐r proƄlem-solving tօ innovative jobs.
Feel free tօ visit mү webpage – Anglo-Chinese Junior College
Anglo-Chinese Junior College
29 Oct 25 at 8:19 am
кракен 2025
kraken vpn
Henryamerb
29 Oct 25 at 8:22 am
Клиника «Чистый Пульс» выполняет экстренный и плановый вывод из запоя с акцентом на безопасность и скорость. Мы организуем анонимный выезд опытного врача на дом, проводим инфузионную терапию с коррекцией водно-электролитного баланса, контролируем давление и пульс, подбираем поддерживающие препараты для печени и нервной системы, а при необходимости — госпитализируем в стационар под круглосуточное наблюдение. Задача команды — не просто «поставить капельницу», а провести полноценный детокс и вернуть контроль над состоянием, снизив риск осложнений и повторных срывов.
Получить дополнительную информацию – [url=https://vyvod-iz-zapoya-moskva8.ru/]вывод из запоя москва стационар[/url]
Danielkew
29 Oct 25 at 8:22 am
digital маркетинг блог [url=statyi-o-marketinge7.ru]statyi-o-marketinge7.ru[/url] .
stati o marketinge _nqkl
29 Oct 25 at 8:24 am
But she tucked it under her arm with a sharp–“Don’t trouble yourself; it’s no exertion to me,but _you_ don’t lookequal to it.エロ ロボット
ラブドール
29 Oct 25 at 8:27 am
кракен официальный сайт
кракен Россия
Henryamerb
29 Oct 25 at 8:28 am
kraken ios
кракен ios
Henryamerb
29 Oct 25 at 8:29 am
В этом интересном тексте собраны обширные сведения, которые помогут вам понять различные аспекты обсуждаемой темы. Мы разбираем детали и факты, делая акцент на важности каждого элемента. Не упустите возможность расширить свои знания и взглянуть на мир по-новому!
Откройте для себя больше – https://indiaprimenews.net/%E0%A4%95%E0%A4%B0%E0%A5%8D%E0%A4%A8%E0%A4%BE%E0%A4%9F%E0%A4%95-%E0%A4%AE%E0%A5%87%E0%A4%82-%E0%A4%96%E0%A5%81%E0%A4%B2%E0%A5%87%E0%A4%82%E0%A4%97%E0%A5%80-250-%E0%A4%87%E0%A4%82%E0%A4%A6%E0%A4%BF
StephanLex
29 Oct 25 at 8:29 am
Yesterday, while I was at work, my sister stole my
iPad and tested to see if it can survive a 30 foot drop, just so
she can be a youtube sensation. My apple ipad is now
destroyed and she has 83 views. I know this is completely off topic but I
had to share it with someone!
アパレル雑貨
29 Oct 25 at 8:30 am
Does your website have a contact page? I’m having problems locating it but, I’d like to send you an email.
I’ve got some suggestions for your blog you might
be interested in hearing. Either way, great blog and I look forward to seeing it develop over time.
cool tech gadgets
29 Oct 25 at 8:30 am
seo блог [url=https://statyi-o-marketinge7.ru]seo блог[/url] .
stati o marketinge _lakl
29 Oct 25 at 8:31 am
Курсы по наращиванию https://schoollegoart.ru ресниц, архитектуре и ламинированию бровей/ресниц с нуля: теория + практика на моделях, стерильность, карта бровей, классика/2D–4D, составы и противопоказания. Материалы включены, мини-группы, сертификат, чек-листы и помощь с портфолио и стартом продаж.
AlbertChert
29 Oct 25 at 8:32 am
В этой статье вы найдете познавательную и занимательную информацию, которая поможет вам лучше понять мир вокруг. Мы собрали интересные данные, которые вдохновляют на размышления и побуждают к действиям. Открывайте новую информацию и получайте удовольствие от чтения!
http://inaina.dk/2017/01/der-sad-to-katte-paa-et-bord
WilliamBug
29 Oct 25 at 8:32 am