{"id":31385,"date":"2019-10-31T21:40:58","date_gmt":"2019-10-31T18:40:58","guid":{"rendered":"https:\/\/prohoster.info\/blog\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper\/"},"modified":"2019-10-31T21:40:58","modified_gmt":"2019-10-31T18:40:58","slug":"biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper","status":"publish","type":"post","link":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper","title":{"rendered":"Poslovna logika u bazi podataka uz pomo\u0107 SchemaKeepera","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Cilj ovog \u010dlanka je, na primjeru biblioteke <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex> prikazati alate koji zna\u010dajno olak\u0161avaju proces razvoja baza podataka unutar PHP projekata koji koriste SDB PostgreSQL.<\/p>\n<p><\/p>\n<p>Informacije iz ovog \u010dlanka, prije svega, bit \u0107e korisne programerima koji \u017eele maksimalno iskoristiti mogu\u0107nosti PostgreSQL-a, ali se suo\u010davaju s problemima odr\u017eavanja poslovne logike smje\u0161tene u Bazi podataka. <\/p>\n<p><\/p>\n<p>\u010clanak ne\u0107e opisivati prednosti ili nedostatke pohrane poslovne logike u bazi podataka. Pretpostavlja se da je \u010ditatelj ve\u0107 donio odluku.<\/p>\n<p><\/p>\n<p>Razmotrit \u0107e se sljede\u0107a pitanja:<\/p>\n<p><\/p>\n<ol>\n<li>Na koji na\u010din pohraniti dump strukture baze podataka u sustav kontrole verzija (dalje u tekstu - VCS)<\/li>\n<li>Kako pratiti promjene u strukturi baze podataka nakon \u0161to se pohrani dump<\/li>\n<li>Kako prenijeti promjene u strukturi baze podataka na druga okru\u017eenja bez sukoba i gigantskih datoteka migracija<\/li>\n<li>Kako uspostaviti proces paralelnog rada na projektu s vi\u0161e programera<\/li>\n<li>Kako sigurno implementirati ve\u0107i broj promjena u strukturi baze podataka na produkcijsko okru\u017eenje<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\n<blockquote><p><strong>SchemaKeeper<\/strong> prilago\u0111en je za rad s pohranjenim procedurama pisanima na jeziku <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/plpgsql.html\">PL\/pgSQL<\/a><\/noindex>. Testiranje s drugim jezicima nije provedeno, stoga kori\u0161tenje mo\u017ee biti manje u\u010dinkovito ili nemogu\u0107e.\n<\/p><\/blockquote>\n<\/li>\n<\/ol>\n<p><\/p>\n<h2 id=\"v-kakom-vide-hranit-damp-struktury-bd-v-vcs\">Na koji na\u010din pohraniti dump strukture baze podataka u VCS<\/h2>\n<p><\/p>\n<p>Biblioteka <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex> nudi funkciju <code>saveDump<\/code>, koja pohranjuje strukturu svih objekata iz baze podataka u obliku odvojenih tekstualnih datoteka. Na izlazu se stvara direktorij koji sadr\u017ei strukturu baze podataka podijeljenu na grupirane datoteke koje se lako mogu dodati u VCS.<\/p>\n<p><\/p>\n<p>Pogledajmo transformaciju objekata iz baze podataka u datoteke na nekoliko primjera:<\/p>\n<p><\/p>\n<p>Tip objekta<br \/>\nShema<br \/>\nNaziv<br \/>\nRelativna putanja do datoteke<\/p>\n<p>Tablica<br \/>\npublic<br \/>\naccounts<br \/>\n<code>.\/public\/tables\/accounts.txt<\/code><\/p>\n<p>Pohranjena procedura<br \/>\npublic<br \/>\nauth(hash bigint)<br \/>\n<code>.\/public\/functions\/auth(int8).sql<\/code><\/p>\n<p>Prikaz<br \/>\nbooking<br \/>\ntariffs<br \/>\n<code>.\/booking\/views\/tariffs.txt<\/code><\/p>\n<p><\/p>\n<p>Sadr\u017eaj datoteka \u010dini tekstualno prikazivanje strukture konkretne Baze podataka. Na primjer, za pohranjene procedure sadr\u017eaj datoteke \u0107e biti potpuna definicija pohranjene procedure, koja zapo\u010dinje s blokom <code>CREATE OR REPLACE FUNCTION<\/code>.<\/p>\n<p><\/p>\n<p>Kao \u0161to se mo\u017ee vidjeti iz gornje tablice, putanja do datoteke sadr\u017ei informacije o tipu, shemi i nazivu objekta. Ovaj pristup olak\u0161ava navigaciju kroz dump i pregled promjena u Bazi podataka.<\/p>\n<p><\/p>\n<blockquote><p>Pro\u0161irenje <code>.sql<\/code> za datoteke s izvornih kodom pohranjenih procedura odabrano je kako bi IDE automatski pru\u017eio alate za interakciju s BDP-om prilikom otvaranja datoteke.<\/p><\/blockquote>\n<p><\/p>\n<h2 id=\"kak-otslezhivat-izmeneniya-v-strukture-bd-posle-sohraneniya-dampa\">Kako pratiti promjene u strukturi baze podataka nakon \u0161to se pohrani dump<\/h2>\n<p><\/p>\n<p>Spremanjem ispisa trenutne strukture BDP-a u VCS, dobivamo mogu\u0107nost provjere jesu li izmjene unesene u strukturu baze nakon kreiranja ispisa. U biblioteci <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex> za otkrivanje promjena u strukturi BDP-a predvi\u0111ena je funkcija <code>verifyDump<\/code>, koja bez sporednih u\u010dinaka vra\u0107a informacije o razlikama. <\/p>\n<p><\/p>\n<p>Alternativni na\u010din provjere \u2014 ponovo pozvati funkciju <code>saveDump<\/code>, navode\u0107i isti direktorij, i provjeriti u VCS-u postoji li promjena. Budu\u0107i da su svi objekti iz BDP-a pohranjeni u zasebnim datotekama, VCS \u0107e pokazati samo izmijenjene objekte.<br \/>\nGlavna mana ovog na\u010dina \u2014 potreba za prepisivanjem datoteka kako bismo vidjeli promjene.<\/p>\n<p><\/p>\n<h2 id=\"kak-perenosit-izmeneniya-v-strukture-bd-na-drugie-okruzheniya-bez-konfliktov-i-gigantskih-faylov-migraciy\">Kako prenijeti promjene u strukturi baze podataka na druga okru\u017eenja bez sukoba i gigantskih datoteka migracija<\/h2>\n<p><\/p>\n<p>Zahvaljuju\u0107i funkciji <code>deployDump<\/code> izvorni kod pohranjenih procedura mo\u017ee se ure\u0111ivati na isti na\u010din kao i obi\u010dan izvorni kod aplikacije. Mo\u017eete dodavati\/uklanjati nove retke u kodu pohranjenih procedura i odmah slati promjene u sustav kontrole verzija, ili stvarati\/uklanjati pohranjene procedure stvaranjem\/uklanjanjem odgovaraju\u0107ih datoteka u direktoriju s ispisom. <\/p>\n<p><\/p>\n<p>Na primjer, za stvaranje nove pohranjene procedure u shemi <code>public<\/code> dovoljno je stvoriti novu datoteku s pro\u0161irenjem <code>.sql<\/code> u direktoriju <code>public\/functions<\/code>, staviti u nju izvorni kod pohranjene procedure, uklju\u010duju\u0107i blok <code>CREATE OR REPLACE FUNCTION<\/code>, a zatim pozvati funkciju <code>deployDump<\/code>. Na sli\u010dan na\u010din doga\u0111a se i izmjena i brisanje pohranjene procedure. Tako kod istovremeno ulazi i u VCS i u bazu podataka. <\/p>\n<p><\/p>\n<p>Ako u izvorom kodu neke pohranjene procedure do\u0111e do gre\u0161ke ili nesukladnosti izme\u0111u imena datoteke i pohranjene procedure, tada <code>deployDump<\/code> ne\u0107e se izvr\u0161iti, prikazuju\u0107i tekst gre\u0161ke. Nesklad pohranjenih procedura izme\u0111u ispisa i trenutnog BDP-a nemogu\u0107e je pri kori\u0161tenju <code>deployDump<\/code>.<\/p>\n<p><\/p>\n<blockquote><p>Pri stvaranju nove pohranjene procedure nije potrebno ru\u010dno unositi ispravno ime datoteke. Dovoljno je da datoteka ima pro\u0161irenje <code>.sql<\/code>. Nakon pozivanja <code>deployDump<\/code> tekst gre\u0161ke \u0107e sadr\u017eavati ispravno ime koje se mo\u017ee koristiti za preimenovanje datoteke.<\/p><\/blockquote>\n<p><code>deployDump<\/code> omogu\u0107ava promjenu parametara funkcije ili vra\u0107enog tipa bez dodatnih radnji, dok bi se pri klasi\u010dnom pristupu prvo moralo<br \/>\nizvr\u0161iti <code>DROP FUNCTION<\/code>, a tek onda. <code>CREATE OR REPLACE FUNCTION<\/code>.<\/p>\n<p><\/p>\n<p>Na\u017ealost, postoje neke situacije kada <code>deployDump<\/code> nema mogu\u0107nosti automatskog primjenjivanja promjena. Na primjer, ako se ukloni okida\u010dka funkcija koja se koristi barem od jedne okida\u010dke to\u010dke. Takve se situacije rje\u0161avaju ru\u010dno uz pomo\u0107 datoteka za migraciju.<\/p>\n<p><\/p>\n<p>Ako za prijenos promjena u pohranjenim procedurama odgovara sam <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex>, tada je potrebno koristiti datoteke migracija za prijenos ostalih promjena u strukturi. Na primjer, dobra biblioteka za rad s migracijama je <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/doctrine\/migrations\">doctrine\/migrations<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Migracije trebaju biti primijenjene prije pokretanja <code>deployDump<\/code>. To omogu\u0107uje uvo\u0111enje svih promjena u strukturu i rje\u0161avanje problemi, tako da se promjene u pohranjenim procedurama kasnije prenose bez problema.<\/p>\n<p><\/p>\n<p>Detaljnije informacije o radu s migracijama bit \u0107e opisane u sljede\u0107im odjeljcima.<\/p>\n<p><\/p>\n<h2 id=\"kak-naladit-process-parallelnoy-raboty-nad-proektom-neskolkih-razrabotchikov\">Kako uspostaviti proces paralelnog rada na projektu s vi\u0161e programera<\/h2>\n<p><\/p>\n<p>Potrebno je stvoriti skriptu za potpunu inicijalizaciju DB-a, koja \u0107e se pokretati od strane programera na njegovom radnom ra\u010dunalu, dovode\u0107i strukturu lokalne DB-a u skladu s spremljenim dumpom u VCS-u. Najlak\u0161e je podijeliti inicijalizaciju lokalne DB-a u 3 koraka:<\/p>\n<p><\/p>\n<ol>\n<li>Uvoz datoteke s osnovnom strukturom, koja \u0107e se zvati, na primjer, <code>base.sql<\/code> <\/li>\n<li>Primjena migracija<\/li>\n<li>Poziv <code>deployDump<\/code><\/li>\n<\/ol>\n<p><\/p>\n<blockquote><p><code>base.sql<\/code> \u2014 to je polazna to\u010dka, preko koje se primjenjuju migracije i izvr\u0161ava se <code>deployDump<\/code>, odnosno <code>base.sql + migracije + deployDump = aktualna struktura DB<\/code>. Takvu datoteku mogu\u0107e je formirati pomo\u0107u alata <code>pg_dump<\/code>. Koristi se <code>base.sql<\/code> isklju\u010divo prilikom inicijalizacije baze podataka od nule.<\/p><\/blockquote>\n<p>Nazovimo skriptu za potpunu inicijalizaciju DB-a <code>refresh.sh<\/code>. Radni proces mo\u017ee izgledati ovako:<\/p>\n<p><\/p>\n<ol>\n<li>Programer pokre\u0107e u svom okru\u017eenju <code>refresh.sh<\/code> i dobiva aktualnu strukturu DB<\/li>\n<li>Programer zapo\u010dinje rad na dodijeljenom zadatku, modificiraju\u0107i lokalnu DB prema potrebama nove funkcionalnosti (<code>ALTER TABLE ... ADD COLUMN<\/code> itd)<\/li>\n<li>Nakon zavr\u0161etka zadatka, programer poziva funkciju <code>saveDump<\/code>, kako bi zabilje\u017eio u VCS-u promjene napravljene u DB<\/li>\n<li>Programer ponovno pokre\u0107e <code>refresh.sh<\/code>, zatim <code>verifyDump<\/code>, koji sada prikazuje popis promjena za uklju\u010divanje u migraciju<\/li>\n<li>Programer prenosi sve promjene strukture u datoteku migracije, ponovno pokre\u0107e <code>refresh.sh<\/code> i <code>verifyDump<\/code>, i ako je migracija sastavljena ispravno, <code>verifyDump<\/code> prikazat \u0107e odsutnost razlika izme\u0111u lokalne DB i spremljenog dumpa<\/li>\n<\/ol>\n<p><\/p>\n<p>Opisani proces je uskla\u0111en s principima gitflow. Svaka grana u VCS-u sadr\u017eavat \u0107e svoju verziju dumpa, a prilikom spajanja grana do\u0107i \u0107e do spajanja dumpa. U ve\u0107ini slu\u010dajeva nakon spajanja nije potrebno poduzimati nikakve dodatne akcije, ali ako su napravljene promjene u razli\u010ditim granama, primjerice u istoj tablici, mo\u017ee do\u0107i do sukoba.<\/p>\n<p><\/p>\n<p>Razmotrit \u0107emo sukobnu situaciju na primjeru: postoji grana <em>develop<\/em>, od koje su odvojene dvije grane: <em>feature1<\/em> i <em>feature2<\/em>, koje nemaju sukoba s <em>develop<\/em>, ali imaju sukobe izme\u0111u sebe. Cilj je obaviti spajanje obje grane u <em>develop<\/em>. U takvoj situaciji preporu\u010duje se prvo obaviti spajanje jedne od grana u <em>develop<\/em>, a zatim spajanje <em>develop<\/em> u preostalu granu, rje\u0161avaju\u0107i pritom sukobe u preostaloj grani, nakon \u010dega slijedi spajanje posljednje grane u <em>develop<\/em>. Tijekom faze razrje\u0161avanja sukoba mo\u017eda \u0107e biti potrebno ispraviti datoteku migracije u posljednjoj grani kako bi odgovarala kona\u010dnom dumpu, koji uklju\u010duje rezultate spajanja.<\/p>\n<p><\/p>\n<h2 id=\"kak-bezopasno-deploit-bolshee-kolichestvo-izmeneniy-v-strukture-bd-na-production-okruzhenie\">Kako sigurno implementirati ve\u0107i broj promjena u strukturi baze podataka na produkcijsko okru\u017eenje<\/h2>\n<p><\/p>\n<p>Zahvaljuju\u0107i prisutnosti u VCS-u dumpa aktualne strukture BDP-a, postoji mogu\u0107nost provjere produkcijske baze na to\u010dno uskla\u0111enost sa zahtijevanom strukturom. To jam\u010di da su se u produkcijsku bazu uspje\u0161no prenijele sve promjene koje su dizajnirali programeri.<\/p>\n<p><\/p>\n<p>Budu\u0107i da <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/ddl.html\">DDL<\/a><\/noindex> u PostgreSQL-u je <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis\">transakcijski<\/a><\/noindex>, preporu\u010duje se pridr\u017eavati se sljede\u0107eg redoslijeda implementacije kako biste, u slu\u010daju nepredvi\u0111ene pogre\u0161ke, \"bezbolno\" izvr\u0161ili <code>ROLLBACK<\/code>:<\/p>\n<p><\/p>\n<ol>\n<li>Zapo\u010dnite transakciju<\/li>\n<li>U transakciji izvr\u0161ite sve migracije<\/li>\n<li>U istoj transakciji izvr\u0161ite <code>deployDump<\/code><\/li>\n<li>Ne zavr\u0161avaju\u0107i transakciju, izvr\u0161ite <code>verifyDump<\/code>. Ako nema gre\u0161aka, izvr\u0161ite <code>COMMIT<\/code>. Ako postoje gre\u0161ke, izvr\u0161ite <code>ROLLBACK<\/code><\/li>\n<\/ol>\n<p><\/p>\n<p>Ovi koraci se relativno lako uklapaju u postoje\u0107e pristupe implementaciji aplikacija, uklju\u010duju\u0107i zero-downtime.<\/p>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Zaklju\u010dak<\/h1>\n<p><\/p>\n<p>Zahvaljuju\u0107i gore opisanim metodama, mo\u017ee se izvu\u0107i maksimum performansi iz \"PHP + PostgreSQL\" projekata, \u017ertvuju\u0107i pri tom relativno malu koli\u010dinu udobnosti razvoja u usporedbi s realizacijom cijele poslovne logike u glavnom kodu aplikacije. \u0160tovi\u0161e, obrada podataka u <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/plpgsql.html\">PL\/pgSQL<\/a><\/noindex> \u010desto izgleda transparentnije i zahtijeva manje koda nego ista funkcionalnost napisana u PHP-u.<\/p>\n<p>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/447746\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0426\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 schema-keeper \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 PHP-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0445 \u0421\u0423\u0411\u0414 PostgreSQL. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0438\u0437 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0443 \u0445\u043e\u0442\u044f\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 PostgreSQL, \u043d\u043e \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u043d\u043e\u0439 \u0432 \u0411\u0414. \u0421\u0442\u0430\u0442\u044c\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-31385","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0426\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 schema-keeper \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"hr_HR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0411\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 SchemaKeeper | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0426\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 schema-keeper \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:40:58+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:40:58+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Poslovna logika u bazi podataka pomo\u0107u SchemaKeeper | ProHoster","description":"Cilj ovog \u010dlanka je na primjeru biblioteke schema-keeper pokazati alate koji omogu\u0107uju zna\u010dajno.","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0411\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 SchemaKeeper | ProHoster","og:description":"\u0426\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 schema-keeper \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e.","og:url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:40:58+00:00","article:modified_time":"2019-10-31T18:40:58+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"31385","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 05:54:24","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:17:26","updated":"2026-01-21 05:54:24","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/31385","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=31385"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/31385\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=31385"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=31385"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=31385"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}