Preparing for Different Databases
Preparing for Different Databases
In the previous chapter, we created a PostRepository that returns some data from blog posts. While the implementation was adequate for learning purposes, it is quite impractical for real world applications; no one would want to modify the source files each time a new post is added! Fortunately, we an always turn to databases for the actual storage of posts; all we need to learn is how to interact with databases within our application.
There's one small catch: there are many database backend systems, including relational databases, documentent databases, key/value stores, and graph databases. You may be inclined to code directly to the solution that fits your application's immediate needs, but it is a better practice to create another layer in front of the actual database access that abstracts the database interaction. Therepository approach we used in the previous chapter is one such approach, primarily geared towards queries. In this section, we'll expand on it to addcommand capabilities for creating, updating, and deleting records.
What is database abstraction?
"Database abstraction" is the act of providing a common interface for all database interactions. Consider a SQL and a NoSQL database; both have methods for CRUD (Create, Read, Update, Delete) operations. For example, to query the database against a given row in MySQL you might use
$results = mysqli_query('SELECT foo FROM bar')`;
However, for MongoDB, for example you'd use something like:
$results = $mongoDbClient->app->bar->find([], ['foo' => 1, '_id' => 0])`;
Both engines would give you the same result, but the execution is different.
So if we start using a SQL database and write those codes directly into ourPostRepository and a year later we decide to switch to a NoSQL database, the existing implementation is useless to us. And in a few years later, when a new persistence engine pops up, we have to start over yet again.
If we hadn't created an interface first, we'd also likely need to change our consuming code!
On top of that, we may find that we want to use some sort of distributed caching layer for read operations (fetching items), while write operations will be written to a relational database. Most likely, we don't want our controllers to need to worry about those implementation details, but we will want to ensure that we account for this in our architecture.
At the code level, the interface is our abstraction layer for dealing with differences in implementations. However, currently, we only deal with queries. Let's expand on that.
Adding command abstraction
Let's first think a bit about what possible database interactions we can think of. We need to be able to:
- find a single blog post
- find all blog posts
- insert new blog post
- update existing blog posts
- delete existing blog posts
At this time, our PostRepositoryInterface deals with the first two. Considering this is the layer that is most likely to use different backend implementations, we probably want to keep it separate from the operations that cause changes.
Let's create a new interface, Blog\Model\PostCommandInterface, inmodule/Blog/src/Model/PostCommandInterface.php, and have it read as follows:
namespace Blog\Model;
interface PostCommandInterface
{
/**
* Persist a new post in the system.
*
* @param Post $post The post to insert; may or may not have an identifier.
* @return Post The inserted post, with identifier.
*/
public function insertPost(Post $post);
/**
* Update an existing post in the system.
*
* @param Post $post The post to update; must have an identifier.
* @return Post The updated post.
*/
public function updatePost(Post $post);
/**
* Delete a post from the system.
*
* @param Post $post The post to delete.
* @return bool
*/
public function deletePost(Post $post);
}
This new interface defines methods for each command within our model. Each expects a Post instance, and it is up to the implementation to determine how to use that instance to issue the command. In the case of an insert operation, ourPost does not require an identifier (which is why the value is nullable in the constructor), but will return a new instance that is guaranteed to have one. Similarly, the update operation will return the updated post (which may be the same instance!), and a delete operation will indicate if the operation was successful.
Conclusion
We're not quite ready to use the new interface; we're using it to set the stage for the next few chapters, where we look at using zend-db to implement our persistence, and later creating new controllers to handle blog post manipulation.
Preparing for Different Databases的更多相关文章
- [转] CVonline: Image Databases
转自:CVonline by Robert Fisher 图像数据库 Index by Topic Action Databases Biological/Medical Face Databases ...
- [开发笔记] Graph Databases on developing
TimeWall is a graph databases github It be used to apply mathematic model and social network with gr ...
- SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases)
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems) 实现代码(SQL Codes) 方法一:拼接SQL: 方法二: ...
- MySql: show databases/tables use database desc table
1. show databases mysql> show databases;+--------------------+| Database |+--------------------+| ...
- [转载]Back up all of your mysql databases nightly
原文地址:http://www.linuxbrigade.com/back-up-all-of-your-mysql-databases-nightly/ Put the following into ...
- codeforces B - Preparing Olympiad(dfs或者状态压缩枚举)
B. Preparing Olympiad You have n problems. You have estimated the difficulty of the i-th one as inte ...
- Elasticsearch: Indexing SQL databases. The easy way
Elasticsearchis a great search engine, flexible, fast and fun. So how can I get started with it? Thi ...
- Django~Databases
更换数据库 migrate 下哈 admin 要重新建立 修改\mysite\settings.py DATABASES = { 'default': { 'ENGINE': 'd ...
- Run same command on all SQL Server databases without cursors
original: https://www.mssqltips.com/sqlservertip/1414/run-same-command-on-all-sql-server-databases-w ...
随机推荐
- 【转】如何下载并编译Android4.0内核源码goldfish(图文)
原文网址:http://blog.csdn.net/flydream0/article/details/7070392 关于如何下载Android4.0源码,请查看我的博客内另一篇文章(同样是图文教程 ...
- 算法 后减前最大值,zt
一个人知道未来n天的每天股票的价格,请你给出一个算法,使得这个人从哪天买入,哪天卖出能获得最大的收益. 问题实际上就是求一个数组后面元素减前面元素的最大值 #include <stdio.h&g ...
- MEF技术
MEF 是一个使开发人员能够创建“插件式应用程序”的技术,这里的“插件”是指在应用程序部署后开发人员能够通过开发“插件”来扩展应用程序功能.但不同之处是使用MEF框架您在系统设计阶段不需要考虑在应用程 ...
- HDU 5534 Partial Tree 完全背包
一棵树一共有2*(n-1)度,现在的任务就是将这些度分配到n个节点,使这n个节点的权值和最大. 思路:因为这是一棵树,所以每个节点的度数都是大于1的,所以事先给每个节点分配一度,答案 ans=f[1] ...
- html中a标签中的onclick和href的使用
1. 链接的 onclick 事件被先执行,其次是 href 属性下的动作(页面跳转,或 javascript 伪链接): 假设链接中同时存在 href 与 onclick,如果想让 href 属性下 ...
- codeforce 604B More Cowbell
题意:n个球,分成k堆.问堆的最大值的最小. #include <bits/stdc++.h> typedef long long ll; using namespace std; int ...
- 【Zookeeper学习】Zookeeper-3.4.6安装部署
[时间]2014年11月19日 [平台]Centos 6.5 [工具] [软件]jdk-7u67-linux-x64.rpm zookeeper-3.4.6.tar.gz [步骤] 1. 准备条件 ( ...
- JDBC 的基本步骤
JDBC 的基本步骤: 一.导入mysql-connector-java-x.x.x-bin.jar后: 二.代码 1. 注册驱动(三种方式)2. 创建一个连接对象(三种方式) 3. 创建一个sql语 ...
- Bzoj-2005 能量采集 gcd,递推
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2005 题意:题目转换后的模型就是求Σ(gcd(x,y)), 1<=x<=n, ...
- Android实例-MediaPlayer播放音乐和视频(XE8+小米2)
结果: 1.播放视频需要手动放入MediaPlayerControl1控件,设置MediaPlayerControl1.MediaPlayer := MediaPlayer1; 2.播放声音文件正常, ...