{"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\/en\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper","title":{"rendered":"Business Logic in the Database Using SchemaKeeper","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>The goal of this article is to demonstrate the tools that can significantly ease the process of database development in PHP projects utilizing the PostgreSQL DBMS. <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex> Information from this article will primarily benefit developers who wish to maximize the capabilities of PostgreSQL but encounter difficulties in maintaining business logic that is offloaded to the database.<\/p>\n<p><\/p>\n<p>The article will not describe the advantages or disadvantages of storing business logic in the database. It is assumed that the reader has already made this choice. <\/p>\n<p><\/p>\n<p>The following questions will be addressed:<\/p>\n<p><\/p>\n<p>What format to use for storing database structure dumps in a version control system (hereafter referred to as VCS)<\/p>\n<p><\/p>\n<ol>\n<li>How to monitor changes in the database structure after saving the dump<\/li>\n<li>How to transfer changes in the database structure to other environments without conflicts and large migration files<\/li>\n<li>How to establish a process for multiple developers to work on the project in parallel<\/li>\n<li>How to safely deploy a larger number of changes in the database structure to the production environment<\/li>\n<li>SchemaKeeper<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\n<blockquote><p><strong>is designed to work with stored procedures written in the language<\/strong> PL\/pgSQL <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/plpgsql.html\">. Testing with other languages has not been conducted, so usage may not be as effective or could be impossible.<\/a><\/noindex>What format to use for storing database structure dumps in VCS\n<\/p><\/blockquote>\n<\/li>\n<\/ol>\n<p><\/p>\n<h2 id=\"v-kakom-vide-hranit-damp-struktury-bd-v-vcs\">provides a function<\/h2>\n<p><\/p>\n<p>Library <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex> saveDump <code>, which saves the structure of all objects from the database as separate text files. A directory is created that contains the database structure divided into grouped files that can be easily added to VCS.<\/code>Let's consider the conversion of objects from the database into files through several examples:<\/p>\n<p><\/p>\n<p>Object type<\/p>\n<p><\/p>\n<p>Relative path to the file<br \/>\nScheme<br \/>\nTitle<br \/>\nTable<\/p>\n<p>accounts<br \/>\npublic<br \/>\n.\/public\/tables\/accounts.txt<br \/>\n<code>Stored procedure<\/code><\/p>\n<p>auth(hash bigint)<br \/>\npublic<br \/>\n.\/public\/functions\/auth(int8).sql<br \/>\n<code>booking<\/code><\/p>\n<p>Representation<br \/>\ntariffs<br \/>\n.\/booking\/views\/tariffs.txt<br \/>\n<code>The content of the files is a textual representation of the structure of a specific database object. For example, the content of the file for stored procedures will be the full definition of the stored procedure, starting with the block<\/code><\/p>\n<p><\/p>\n<p>CREATE OR REPLACE FUNCTION <code>As seen from the table above, the file path contains information about the type, schema, and name of the object. This approach facilitates navigation through the dump and code review of changes in the database.<\/code>.<\/p>\n<p><\/p>\n<p>.sql<\/p>\n<p><\/p>\n<blockquote><p>Extension <code>.sql<\/code> For files with stored procedure source code, it was chosen so that the IDE automatically provides tools for interacting with the database when the file is opened.<\/p><\/blockquote>\n<p><\/p>\n<h2 id=\"kak-otslezhivat-izmeneniya-v-strukture-bd-posle-sohraneniya-dampa\">How to transfer changes in the database structure to other environments without conflicts and large migration files<\/h2>\n<p><\/p>\n<p>By saving a dump of the current database structure in VCS, we gain the ability to check whether changes have been made to the database structure since the dump was created. In the library, <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex> there is a function to identify changes in the database structure, <code>verifyDump<\/code>, which returns information about differences without side effects. <\/p>\n<p><\/p>\n<p>An alternative way to check is to call the function again, specifying the same directory and verifying in VCS for any changes. Since all objects from the database are saved in separate files, VCS will only show the changed objects. <code>, which saves the structure of all objects from the database as separate text files. A directory is created that contains the database structure divided into grouped files that can be easily added to VCS.<\/code>deployDump<br \/>\nThe main downside of this method is the need to overwrite files to see changes.<\/p>\n<p><\/p>\n<h2 id=\"kak-perenosit-izmeneniya-v-strukture-bd-na-drugie-okruzheniya-bez-konfliktov-i-gigantskih-faylov-migraciy\">How to establish a process for multiple developers to work on the project in parallel<\/h2>\n<p><\/p>\n<p>Thanks to the function <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code> For example, to create a new stored procedure in the schema, <\/p>\n<p><\/p>\n<p>it is enough to create a new file with the extension <code>public<\/code> public\/functions <code>.sql<\/code> in the directory <code>, place the source code of the stored procedure into it, including the block<\/code>, and then call the function. <code>As seen from the table above, the file path contains information about the type, schema, and name of the object. This approach facilitates navigation through the dump and code review of changes in the database.<\/code>Changes and deletions of stored procedures occur in the same way. Thus, the code simultaneously enters both VCS and the database. <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code>If there is an error in the source code of any stored procedure, or a mismatch between the file name and the stored procedure name, then <\/p>\n<p><\/p>\n<p>it will not execute, displaying the error message. Misalignment of stored procedures between the dump and the current database is impossible when using <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code> When creating a new stored procedure, there is no need to manually enter the correct file name. It is sufficient for the file to have the extension <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code>.<\/p>\n<p><\/p>\n<blockquote><p>. After calling <code>.sql<\/code>the error message will contain the correct name that can be used to rename the file. <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code> allows changing the function parameters or return type without additional actions, whereas in the classical approach you would have had to<\/p><\/blockquote>\n<p><code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code> first execute<br \/>\nDROP FUNCTION <code>, and only then.<\/code>, and only then <code>As seen from the table above, the file path contains information about the type, schema, and name of the object. This approach facilitates navigation through the dump and code review of changes in the database.<\/code>.<\/p>\n<p><\/p>\n<p>Unfortunately, there are situations where <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code> it cannot automatically apply changes. For example, if a trigger function is deleted that is used by at least one trigger. Such situations are resolved manually using migration files.<\/p>\n<p><\/p>\n<p>If the process of transferring changes in stored procedures is handled by <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/schema-keeper\/schema-keeper\">schema-keeper<\/a><\/noindex>, then to transfer the other changes in the structure, migration files must be used. For example, a good library for working with migrations is <noindex><a rel=\"nofollow\" href=\"https:\/\/packagist.org\/packages\/doctrine\/migrations\">doctrine\/migrations<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Migrations should be applied before launching <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code>. This allows all changes to the structure to be made and resolves problematic situations so that changes in stored procedures can later be transferred without issues.<\/p>\n<p><\/p>\n<p>More details on working with migrations will be described in the following sections.<\/p>\n<p><\/p>\n<h2 id=\"kak-naladit-process-parallelnoy-raboty-nad-proektom-neskolkih-razrabotchikov\">How to safely deploy a larger number of changes in the database structure to the production environment<\/h2>\n<p><\/p>\n<p>It is necessary to create a script for the complete initialization of the database, which will be run by the developer on their workstation, aligning the structure of the local database with the dump saved in VCS. It's easiest to break down the initialization of the local database into 3 steps:<\/p>\n<p><\/p>\n<ol>\n<li>Import the file with the basic structure, which might be called <code>base.sql<\/code> <\/li>\n<li>Applying migrations<\/li>\n<li>Call <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code><\/li>\n<\/ol>\n<p><\/p>\n<blockquote><p><code>base.sql<\/code> \u2014 this is the starting point upon which migrations are applied and executed <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code>, which means <code>base.sql + migrations + deployDump = current database structure<\/code>. Such a file can be generated using the utility <code>pg_dump<\/code>. It is used <code>base.sql<\/code> exclusively for initializing the database from scratch.<\/p><\/blockquote>\n<p>Let\u2019s name the complete database initialization script <code>refresh.sh<\/code>. The workflow might look as follows:<\/p>\n<p><\/p>\n<ol>\n<li>The developer runs in their environment <code>refresh.sh<\/code> and receives the current database structure<\/li>\n<li>The developer starts working on the assigned task, modifying the local database to meet the needs of the new functionality (<code>ALTER TABLE ... ADD COLUMN<\/code> etc.)<\/li>\n<li>After completing the task, the developer calls the function <code>, which saves the structure of all objects from the database as separate text files. A directory is created that contains the database structure divided into grouped files that can be easily added to VCS.<\/code>, to commit the changes made to the database to VCS<\/li>\n<li>The developer reruns <code>refresh.sh<\/code>, then <code>verifyDump<\/code>, which now shows the list of changes to be included in the migration<\/li>\n<li>The developer transfers all structural changes to the migration file, runs <code>refresh.sh<\/code> and <code>verifyDump<\/code>again, and if the migration is correctly composed, <code>verifyDump<\/code> will show no differences between the local database and the saved dump.<\/li>\n<\/ol>\n<p><\/p>\n<p>The process described above is compatible with gitflow principles. Each branch in the VCS will contain its own version of the dump, and merging branches will result in merging dumps. In most cases, no additional actions are required after merging, but if changes were made in different branches, for example, in the same table, conflicts may arise.<\/p>\n<p><\/p>\n<p>Let's consider a conflicting situation: there is a branch <em>develop<\/em>, from which two branches have been created: <em>feature1<\/em> and <em>feature2<\/em>, which do not have conflicts with <em>develop<\/em>, but have conflicts with each other. The task is to merge both branches into <em>develop<\/em>. In such a case, it is recommended to first merge one of the branches into <em>develop<\/em>, and then merge <em>develop<\/em> into the remaining branch, resolving conflicts in the remaining branch, after which the last branch can be merged into <em>develop<\/em>. During the conflict resolution stage, it may be necessary to correct the migration file in the last branch to match the final dump that includes the results of the merges.<\/p>\n<p><\/p>\n<h2 id=\"kak-bezopasno-deploit-bolshee-kolichestvo-izmeneniy-v-strukture-bd-na-production-okruzhenie\">SchemaKeeper<\/h2>\n<p><\/p>\n<p>Thanks to the presence of a current database structure dump in the VCS, it becomes possible to check the production database for exact compliance with the required structure. This ensures that all the changes the developers intended have been successfully transferred to the production database.<\/p>\n<p><\/p>\n<p>Since <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/ddl.html\">DDL<\/a><\/noindex> in PostgreSQL is <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis\">transactional<\/a><\/noindex>, it is recommended to follow this deployment order so that in case of unforeseen errors, one can execute rolls-back smoothly. <code>ROLLBACK<\/code>:<\/p>\n<p><\/p>\n<ol>\n<li>Begin transaction<\/li>\n<li>Perform all migrations in the transaction<\/li>\n<li>In this transaction, also execute <code>The source code of stored procedures can be edited just like regular application source code. You can add\/delete lines in the stored procedure code and immediately submit changes to the version control system, or create\/delete stored procedures by creating\/deleting the corresponding files in the dump directory.<\/code><\/li>\n<li>Without closing the transaction, execute <code>verifyDump<\/code>. If there are no errors, execute <code>COMMIT<\/code>. If there are errors, execute <code>ROLLBACK<\/code><\/li>\n<\/ol>\n<p><\/p>\n<p>These steps can be easily integrated into existing application deployment approaches, including zero-downtime deployments.<\/p>\n<p><\/p>\n<h1 id=\"zaklyuchenie\">Conclusion<\/h1>\n<p><\/p>\n<p>By using the methods described above, one can maximize performance from \"PHP + PostgreSQL\" projects, sacrificing relatively small amounts of development convenience compared to the implementation of all business logic in the main application code. Moreover, data processing in <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/plpgsql.html\">. Testing with other languages has not been conducted, so usage may not be as effective or could be impossible.<\/a><\/noindex> often appears more transparent and requires less code than the same functionality written in PHP.<\/p>\n<p>Source: <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.1.1 - 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\/en\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\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\/en\/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\udd47Business Logic in the Database with SchemaKeeper | ProHoster","description":"The purpose of this article is to illustrate tools that can significantly improve through the example of the schema-keeper library.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/biznes-logika-v-baze-dannyh-pri-pomoshhi-schemakeeper","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","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\/en\/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\/en\/wp-json\/wp\/v2\/posts\/31385","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=31385"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/31385\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=31385"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=31385"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=31385"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}