I am planning on implementing a basic CMS I will use internally for my own development. I want to develop a custom CMS for my own needs -- something lighter, more portable, and less redundant than Dreamweaver, but is geared towards someone who already knows how to code and just needs to consolidate information. Essentially, the plan is to store everything in a MySQL database, cache it all on the file system, and then, whenever data is queried via a fetching PHP file, a simple query is sent to the database checking for when that resource was last updated, and if the cached file on the system is recent enough, it is pulled from the cache directory; else, the cache file is overwritten.
The CMS will be storing all uploads in the database so that everything is in one place if the systems needs to move to another host, etc. It also makes backups really simple, and it could easily be extended to implement diff/revision repository, etc.
I would like to create a single table (e.g. "assets") that will contain all files uploaded and resources (pages, templates, etc.) created through the CMS interface. Ideally, this would handle two types: ASCII (text) and binary (BLOB).
Table "assets"
id INT, slug VARCHAR, ascii LONGTEXT, binary LONGBLOB, type INT, meta TEXT, modified DATE, ...
My question is, does it make sense to put this information in one table? Any given row in the "assets" table would only have a value in either the ascii column or the binary column, but never both. Does this waste any space? Slow down the process at all?
The columns would never be selected unnecessarily. The "type" field would correspond to an id in the "types" table, which would list text types (html, template, plaintext, etc.) and binary types (png, jpg, pdf, mp3, mp4, etc.). So I could query like so:
(Obviously pseudo-code)
$lastModified = SELECT modified FROM assets WHERE slug = $asset_slug;
if last_modified_date_of_file("cache/$asset_slug") != $lastModified :
$type_id = SELECT type FROM assets WHERE id = $asset_id;
$type_col = SELECT col FROM types WHERE id = $type_id;
if $col == 'ascii'
cache_file("cache/$asset_slug", SELECT ascii FROM assets WHERE slug = $asset_slug);
else
cache_file("cache/$asset_slug", SELECT binary FROM assets WHERE slug = $asset_slug);
In general, if you're storing binary data in your database you're doing something wrong; while I appreciate the desire to make migration easy, you'll quickly find your database slowing down when you're storing mp3s in it; databases are optimised for quick retrieval of small amounts of data, filesystems for organised access to large amounts of data. When I've implemented similar systems, I've stored the location of the file in the database and the file itself on the filesystem; for portability, you might want to just store the filename in the 'assets' table and store the path to the asset store elsewhere in the db.
Good database design typically means separating out properties of an entity from data associated with the entity - for example, in the classic 'contact card' scenario, a table 'person' might have 'name', 'DOB' and 'location', but data such as 'phone number' should be stored elsewhere as it's data associated with the person, not an attribute of the person. For your case, it'd be better (IMO) to have separate tables FKing back to the 'assets' table to link asset data to assets.