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://peresechdesign.ru — портфолио демонстрирует квартиры, частные дома и коммерческие пространства с продуманной эргономикой и реалистичными визуализациями.
vykuntodot
20 Sep 25 at 6:07 am
hi!,I love your writing so so much! percentage we communicate more about your post on AOL?
I require an expert on this area to unravel my problem.
May be that is you! Taking a look forward to see you.
j88slot
20 Sep 25 at 6:07 am
мфо займ [url=http://www.zaimy-17.ru]мфо займ[/url] .
zaimi_hbSa
20 Sep 25 at 6:08 am
купить диплом о высшем образовании с занесением в реестр в красноярске [url=https://frei-diplom3.ru/]купить диплом о высшем образовании с занесением в реестр в красноярске[/url] .
Diplomi_hfKt
20 Sep 25 at 6:08 am
Hello, just wanted to mention, I enjoyed this blog post.
It was inspiring. Keep on posting!
royalshop.com.ua
20 Sep 25 at 6:09 am
Ever Trust Meds [url=http://evertrustmeds.com/#]Cheap Cialis[/url] п»їcialis generic
Michealstilm
20 Sep 25 at 6:09 am
займы всем [url=https://www.zaimy-17.ru]займы всем[/url] .
zaimi_tqSa
20 Sep 25 at 6:12 am
Hello There. I found your blog using msn. This is a very well written article.
I will be sure to bookmark it and return to read more of your
useful information. Thanks for the post. I’ll definitely return.
popbrapronto rtp
20 Sep 25 at 6:12 am
диплом купить проведенный [url=http://frei-diplom5.ru/]диплом купить проведенный[/url] .
Diplomi_xyPa
20 Sep 25 at 6:12 am
все онлайн займы [url=http://www.zaimy-25.ru]http://www.zaimy-25.ru[/url] .
zaimi_xzoa
20 Sep 25 at 6:13 am
займ всем [url=http://zaimy-23.ru/]http://zaimy-23.ru/[/url] .
zaimi_vjSl
20 Sep 25 at 6:15 am
купить официальный диплом [url=https://www.educ-ua7.ru]https://www.educ-ua7.ru[/url] .
Diplomi_zaea
20 Sep 25 at 6:16 am
все займы онлайн [url=www.zaimy-17.ru]все займы онлайн[/url] .
zaimi_agSa
20 Sep 25 at 6:17 am
все микрозаймы [url=www.zaimy-25.ru/]все микрозаймы[/url] .
zaimi_vmoa
20 Sep 25 at 6:17 am
как накрутить подписчиков в телеграм
DavidNOb
20 Sep 25 at 6:19 am
все микрозаймы онлайн [url=www.zaimy-23.ru]www.zaimy-23.ru[/url] .
zaimi_kgSl
20 Sep 25 at 6:19 am
займы онлайн [url=zaimy-25.ru]займы онлайн[/url] .
zaimi_wdoa
20 Sep 25 at 6:21 am
Получить диплом о высшем образовании поспособствуем. Кто может помочь купить диплом техникума в Вологде – [url=http://diplomybox.com/kupit-diplom-tekhnikuma-v-vologde/]diplomybox.com/kupit-diplom-tekhnikuma-v-vologde[/url]
Cazrvsk
20 Sep 25 at 6:21 am
Рекламные носители остаются одним из самых действенных инструментов PR. Среди них выделяется [url=https://format-ms.ru/catalog/x-banner/]паук для рекламы[/url] ведь такой мобильный стенд сочетает удобство и эффективность. Он формирует образ на форуме, в салоне или на семинаре. Конструкция проста для транспортировки, легко устанавливается и моментально заметен на лояльность клиентов.
Компания Format-MS уже давно занимается производством и подготовкой роллапов. В студии используют надёжные баннерные основы, технологии высокого разрешения и гарантируют точную цветопередачу. Клиенты доверяют нам соблюдение сроков заказов, профессиональную установку и индивидуальный подход. Адрес офиса: Москва, Нагорный проезд, дом 7, стр 1, офис 2320. Для уточнения деталей всегда доступен телефон +7 (499) 390-19-85. На сайте format-ms.ru можно ознакомиться с примерами и запросить просчёт.
Если вам требуется [url=https://format-ms.ru/]выставочные конструкции[/url] специалисты изготовят баннеры с адаптацией к погодным условиям и влаге. Усиленные полотна, усиленные крепления и стойкость красок делают такие изделия надёжными даже при мобильных мероприятиях. Это продукт станет эффективной рекламной опорой, который привлекает клиентов круглосуточно и сохраняет качество надолго.
Formenarog
20 Sep 25 at 6:27 am
I visited many websites except the audio quality for audio
songs current at this site is genuinely excellent.
Dinamico Finlore
20 Sep 25 at 6:29 am
микрозайм все [url=https://zaimy-23.ru/]https://zaimy-23.ru/[/url] .
zaimi_aeSl
20 Sep 25 at 6:29 am
https://net89887.blogzet.com/un-imparcial-vista-de-competencias-laborales-52067470
Hablar de competencias laborales mas valoradas en nuestro pais es critico para prepararse ante los desafios que hoy enfrentan las empresas. La tecnologia, la globalizacion y la nuevos profesionales estan cambiando que habilidades se premian en el mundo laboral.
Ranking de las habilidades mas valoradas
Adaptabilidad
Las organizaciones chilenos necesitan equipos capaces de adaptarse rapido a cambios.
Claridad al comunicar
No solo explicar, sino entender. En equipos distribuidos, esta habilidad es fundamental.
Capacidad analitica
Con datos por todos lados, las empresas valoran a quienes analizan antes de ejecutar.
Sinergia grupal
Mas alla del “buena onda”, es poder coordinarse con areas de diferentes estilos.
Gestion de personas
Incluso en equipos pequenos, se espera motivar y no solo mandar.
Competencias digitales
Desde apps de gestion hasta datos, lo digital es hoy una skill base.
?Por que importan tanto las competencias laborales mas demandadas?
Porque son la diferencia entre ser reemplazado o destacar en tu carrera. En Chile, donde la rotacion laboral es alta, tener estas capacidades se traduce en oportunidades.
La forma de desarrollar las competencias laborales mas buscadas
Programas de formacion.
Acompanamiento profesional.
Experiencia practica.
Retroalimentacion constantes.
Las competencias laborales mas buscadas son el pasaporte para garantizar tu futuro laboral.
JuniorShido
20 Sep 25 at 6:30 am
Качественные футболки печать и футболки рыбалка в Ростове-на-Дону. Свитшот дешево и ткань для толстовки в Костроме. Надписи на футболках для с фото и футболка пола в Курске. Одежда для официантов ресторана и набор одежды для барби в Новороссийске. Футболка оптом мафия и футболка хаки https://futbolki-s-printom.ru/
Gregorysnisp
20 Sep 25 at 6:31 am
Having read this I thought it was really informative.
I appreciate you finding the time and effort to put this informative article together.
I once again find myself personally spending way too much time both reading and commenting.
But so what, it was still worth it!
canadian pharmacy online
20 Sep 25 at 6:36 am
все микрозаймы онлайн [url=https://zaimy-23.ru/]https://zaimy-23.ru/[/url] .
zaimi_osSl
20 Sep 25 at 6:36 am
I like the valuable info you provide in your articles.
I’ll bookmark your weblog and check again here frequently.
I am quite certain I will learn a lot of new stuff right here!
Good luck for the next!
EuroBasket 2025
20 Sep 25 at 6:37 am
you are truly a excellent webmaster. The web site loading speed
is amazing. It seems that you are doing any distinctive trick.
Furthermore, The contents are masterwork. you have done a excellent process in this subject!
GasPipe AI Vélemény
20 Sep 25 at 6:38 am
It’s going to be finish of mine day, except before finish I am reading this fantastic piece of writing to increase my know-how.
kontol Panjang
20 Sep 25 at 6:39 am
Где сделать печать на футболки и футболку белую мужскую в Набережных Челнах. Толстовка с капюшоном мужская в интернет и толстовки промо оптом в Брянске. Надпись на футболке Магазин и сделать принт на футболке Москва в Ульяновске. Красивая бумага для упаковки подарков и одежда со своим дизайном в Краснодаре. Печать принты на футболки оптом и мужская футболка черная с надписью https://futbolki-s-printom.ru/
Gregorysnisp
20 Sep 25 at 6:40 am
займы [url=www.zaimy-23.ru]www.zaimy-23.ru[/url] .
zaimi_qdSl
20 Sep 25 at 6:40 am
Приобрести диплом о высшем образовании поможем. Купить аттестат Орёл – [url=http://diplomybox.com/kupit-attestat-v-orle/]diplomybox.com/kupit-attestat-v-orle[/url]
Cazrmha
20 Sep 25 at 6:41 am
купить диплом в москве с занесением в реестр [url=www.frei-diplom2.ru/]купить диплом в москве с занесением в реестр[/url] .
Diplomi_tjEa
20 Sep 25 at 6:41 am
Hello there, I found your site by way of Google whilst searching for a comparable matter, your web site came up, it appears good.
I’ve bookmarked it in my google bookmarks.
Hi there, simply changed into aware of your blog thru
Google, and located that it is really informative. I am going to be careful for brussels.
I’ll be grateful when you proceed this in future.
Many people will be benefited out of your writing.
Cheers!
dewascatter link alternatif
20 Sep 25 at 6:43 am
микрозаймы все [url=http://zaimy-23.ru/]http://zaimy-23.ru/[/url] .
zaimi_meSl
20 Sep 25 at 6:44 am
куплю диплом младшей медсестры [url=www.frei-diplom13.ru]www.frei-diplom13.ru[/url] .
Diplomi_kfkt
20 Sep 25 at 6:46 am
Hey hey, Singapore moms ɑnd dads, math proves
likely thе highly important primary subject, promoting innovation tһrough issue-resolving tо creative jobs.
Don’t mess around lah, pair а excellent Junior College
рlus math superiority tо ensure superior Ꭺ Levels гesults рlus seamless transitions.
Folks, dread tһe disparity hor, maths base іѕ essential at Junior College to comprehending figures, essential
іn modern online ѕystem.
Yishun Innova Junior College merges strengths fоr digital literacy ɑnd leadership excellence.
Upgraded facilities promote development ɑnd ⅼong-lasting knowing.
Varied programs іn media and languages foster imagination аnd citizenship.
Neighborhood engagements construct empathy ɑnd skills.
Students beϲome positive, tech-savvy leaders alⅼ set fоr tһe digital age.
Ѕt. Andrew’s Junior College accepts Anglican values tօ
promote holistic growth, cultivating principled people ᴡith robust character qualities tһrough а blend of spiritual assistance,
scholastic pursuit, аnd neighborhood involvement іn a warm and
inclusive environment. Ꭲhe college’s modern-dаy features, consisting of interactive class, sports complexes, аnd innovative arts studios, һelp with excellence аcross academic disciplines, sports programs tһat emphasize physical fitness ɑnd fair play, and creative undertakings tһаt motivate
self-expression аnd innovation. Neighborhood
service initiatives, ѕuch аs volunteer partnerships ѡith local companies and outreach jobs, instill
compassion, social obligation, ɑnd a sense of purpose,
improving trainees’ academic journeys. А varied series оf co-curricular activities,
fгom argument societies tօ musical ensembles, fosters teamwork,
leadership skills, аnd individual discovery,
allowing еvery trainee to shine in tһeir chosen areaѕ.
Alumni of St. Andrew’s Junior College regularly emerge ɑs ethical, resistant leaders who maқe
sіgnificant contributions tο society, reflecting tһe institution’ѕ extensive impact
᧐n establishing well-rounded, vaⅼue-driven people.
Eh eh, steady pom рi pi, maths proves οne of the toр topics during Junior College, laying base tο
A-Level calculus.
Օh no, primary math educates real-ԝorld uses ѕuch aѕ money management, ѕo guarantee y᧐ur youngster grasps tһіs correctly starting еarly.
Alas, without solid maths іn Junior College, even prestigious school kids
сould stumble in һigh school algebra, tһus build it іmmediately leh.
Math mastery іn JC prepares ʏou for the quantitative demands of business
degrees.
Ⅾon’t play play lah, link ɑ good Junior College alongside
math superiority t᧐ guarantee superior Α Levels marks ɑnd seamless chаnges.
Folks, worry ɑbout the difference hor, maths foundation гemains vital іn Junior College to grasping figures,
vital ᴡithin current tech-driven market.
Ꮇy web-site :: singapore math tutor
singapore math tutor
20 Sep 25 at 6:47 am
Купить диплом техникума в Кривой Рог [url=educ-ua7.ru]educ-ua7.ru[/url] .
Diplomi_xbea
20 Sep 25 at 6:47 am
купить диплом техникума 1997 года [url=https://www.frei-diplom9.ru]купить диплом техникума 1997 года[/url] .
Diplomi_adea
20 Sep 25 at 6:47 am
купить диплом техникума или колледжа [url=https://frei-diplom8.ru/]https://frei-diplom8.ru/[/url] .
Diplomi_ugsr
20 Sep 25 at 6:48 am
Israel’s attack in Doha was not entirely surprising, given Israel’s vow to eliminate Hamas — but some aspects of it are still shocking.
[url=https://megasbmegadarknetmarketonionhydrashopomgomgrutor555cnyid.com]mega2o2nde2gzktxse2fesqpyfeoma72qmvk3fkecip2l3uv3tbn5mad.onion[/url]
Here are three main reasons:
[url=https://mega2onq5nskz5ib5cg3a2aqkcprqnm3lojxtik2zeou6au6mno7d4ad.com]mega2ousbpnmmput4tiyu4oa4mjck2icier52ud6lmgrhzlikrxmysid.onion[/url]
Israel claimed credit immediately – in contrast to the last time the Israelis targeted a Hamas leader outside Gaza.
The US and Israel had asked Qatar to host Hamas leaders. Hamas’ location was not a secret. There was an unstated understanding that while Israel could assassinate the leaders, they would not do so, given Qatar’s mediation role.
The strike makes a hostage deal less likely, since any agreement requires negotiating with Hamas leadership in Doha.
Subscribers can read the full analysis here.
https://megadmeovbj6ahqw3reuqu5gbg4meixha2js2in3ukymwkwjqqib6tqd.net
mega2ooyov5nrf42ld7gnbsurg2rgmxn2xkxj5datwzv3qy5pk3p57qd.onion
Michaelfuelp
20 Sep 25 at 6:51 am
купить проведенный диплом кого [url=http://www.frei-diplom2.ru]купить проведенный диплом кого[/url] .
Diplomi_adEa
20 Sep 25 at 6:51 am
Buy Tadalafil 10mg: Ever Trust Meds – Cialis 20mg price
Dennisted
20 Sep 25 at 6:52 am
Приобрести диплом о высшем образовании можем помочь. Купить диплом бакалавра в Иркутске – [url=http://diplomybox.com/kupit-diplom-bakalavra-v-irkutske/]diplomybox.com/kupit-diplom-bakalavra-v-irkutske[/url]
Cazryed
20 Sep 25 at 6:52 am
диплом техникума проведенный купить [url=educ-ua7.ru]educ-ua7.ru[/url] .
Diplomi_lrea
20 Sep 25 at 6:55 am
Excellent goods from you, man. I’ve understand your stuff previous to and you are just extremely fantastic.
I actually like what you have acquired here, certainly like what you’re saying and
the way in which you say it. You make it entertaining and you still take care of to keep it
smart. I can’t wait to read far more from you. This is actually a great site.
dv188
20 Sep 25 at 6:56 am
Your style is very unique in comparison to other folks I have read stuff
from. Many thanks for posting when you have the opportunity, Guess
I’ll just book mark this web site.
EverClear Pools & Spas commercial pool builders near me
20 Sep 25 at 6:57 am
купить вкладыш к диплому техникума [url=www.frei-diplom9.ru]купить вкладыш к диплому техникума[/url] .
Diplomi_exea
20 Sep 25 at 6:59 am
https://vitaledgepharma.shop/# VitalEdge Pharma
AntonioRaX
20 Sep 25 at 6:59 am
купить диплом аграрного техникума [url=https://frei-diplom8.ru/]купить диплом аграрного техникума[/url] .
Diplomi_ewsr
20 Sep 25 at 6:59 am
купить диплом в виннице [url=http://educ-ua7.ru]http://educ-ua7.ru[/url] .
Diplomi_umea
20 Sep 25 at 7:00 am