Sorry for the stupid title, but I don't know how else to name this question :)
So I'm trying to build a very simple content management system that stores data in the database.
One of the data types is a "content type" (similar to WordPress's posts / custom post types).
A content type can be whatever: a page, a car listing, a comment, a book product etc.
Each content type has its own fields. For example:
a page has the: title, text.
a car listing has: make, model, type, year, price, ...
a book has: title, author, price
and so on...
The idea is that these content types are dynamic (and so are their fields). They would be added trough a extension of the CMS. The only built-in content type would be the page.
Anyway, I need advice on how to set up the database tables for them. This should be done from the main CMS, and not from the extensions which are supposed to be very easy to write using the CMS API.
How should I set up tables / table fields, in such a way that searching for results based on certain content type fields would be very fast?
WP uses a different table for the fields, and stores them as rows with a ID pointing to the post they are attached to. But this is pretty slow when you're searching for multiple fields...
There are a bunch of different options.
The most common is storing "key/value" pairs (I believe this is the WP model), alongside the content item. There are many problems with this model - boolean logic when searching quickly becomes unintelligible, content types aren't easily be defined and validated in code (e.g. "all CAR content types must have attribute engine size"), etc. However, they do make it easy to create and change content types.
Another model is to generate database tables on the basis of the content types, usually with a "base" content item as the root. There's a good discussion in Larman's book on how to model the database tables ("Applying UML and patterns"). This design creates a large amount of housekeeping code - creating and modifying the database tables is a pain, and I wouldn't recommend doing this for solutions where you're going to need lots of content types.
The most robust solution I've seen uses XML to store the content - often within a database. XML allows you to define a content type (using a DTD or schema), and validate/query it. It isn't as fast as SQL, though...
id suggest Neville K 's first solution which would need a structure with 4 tables. contents , content_properties_name ,content_properties_values and are joined in contents_properties (content_id , content_property_id , content_value_id ). its fast , search queries are a bit complicated
Related
Project
I am building an automated datasheet generator with the possibility to edit single blocks of the datasheet. There should be always a parent datasheet with the possibility to add translated versions to it. But those translated versions do not have to be the same in content, which means they can have a different amount of pages and blocks.
Basically you type in the article_number and my systems grabs all the default informations like article_number, manufacturer_number, ean_code, primary_image etc. from another database which stores all the product data.
Also every datasheet has a template assigned, which controls the main colors like primary, secondary and text color. Also a logo is assigned to every template.
But maybe some day there should be a possibility to have a template for pages aswell.
From this point you can start adding pages and blocks to every page etc.
Blocks should be stored as json strings and can have different types, like image, textblock, textblock with image, heading etc. So the fields can be quite different depending on the block type. Also the order of the blocks should be stored somehow. Blocks have their field definitions inside block_config also as a json string.
Finally the datasheet can be exported as a pdf file via TCPDF.
Basic Scheme
See here for my current scheme
The Problems
Let me make an example:
I create a datasheet with the article_number 12345.
This sheet contains several pages, and every page contains several blocks.
This datasheet should be available in german and english (more languages are possible too, like spanish, french etc.).
So the title and the subtitle can be different for every datasheet language.
But some attributes inside datasheets should be shared accross all languages.
There should be only one parent object which all translated objects should refer to, so I don't have to copy article 12345 over and over again inside the datasheets table.
Also the blocks can be different for every page and every translation of it.
So those fields like title and subtitle probably have to go into a separate translation table like datasheet_translations table with a locale column and datasheet_id column?
But do I have to do the same for all blocks and pages or is it fine to add a locale column directly to the pages and blocks?
So the questions are:
Is my database scheme any good and how to achieve all those goals above properly?
How to handle the translations? How to handle the order of the blocks, how to save them etc.?
I am quite unsure and afraid that the project will fail with a bad database structure.
I hope you can guide me into the right direction and I hope my explanation was clear enough. If there is any information missing, please let me know.
I'm looking for some help about "Custom View". I looked throw the internet but can't find it (maybe cause of my bad key words).
I created a custom view with a Table format. The goal is to display content (based on a content type) in a table.
I already have my content showing, I can reorganize rows by client/sector.. by clicking on the column header but now I'd like to :
Filter result depending on the string in an input textfield
and
Filter result using a dropdown menu
I guess It's client side, but I'm a beginner in drupal so it's a bit hard to find out.
Here is what I'd like :
http://hpics.li/175e64e
For the select filter, you should try using exposed filters in your view. In the filter section, add filter on the fields and expose them. If these fields are taxonomy reference fields it should work right away. Otherwise it depends : with entity reference I think Better Exposed Filters can be usefull.
With plain text fields it will be more difficult to get what you want (personnaly I give up on exposed filters when it becomes to complicated), but still possible with this approach and a bit of client side work.
The general idea is to create JSON view wich gets all differents values for a text field across the nodes, using Views Data Source (or get all nodes with fields values then fetch unique values for each fields in javascript).
On client side, on the page load make an ajax call to this view to get an array of all possible values, then build your select list using this array, and then do a client side filtering (using for example the excellent Isotope).
But in my opinion you need to take side : all with views and exposed filters (server side, can be hard and frustrating...) or all in JS (client side), mixing the two should result in a big mess...
For the plain text search box I would choose to work client side, Views won't be of any help I'm afraid.
You can also find good javascript plugins for table sorting / filtering like Datatables.
Good luck.
I am looking at customising the yii cgridview. I want to be able to allow users to select which columns they wish to see. Currently I am selecting the exact columns which will be displayed.
I have had a look for information on this but do not seem to be getting very far, maybe I am not looking for the correct terms or their is a specific term for this. Ideally users can click a button and tick the boxes which will be seen. I have seen this implemented on x2crm
http://demo.x2engine.com/index.php/accounts/index
I also like the ability to move the columns around ie resort the order of the columns and the ability to resize the columns when more are added. I realise someone isn't going to come along and do this for me, but certainly if someone could provide me any information or similar requests, it would be greatly appreciated.
After a long gruelling search I have found something that may in fact be the solution to both of my requests. An extension for Yii exists that allow for you to chooser the columns you wish to display with a simple tick box selection, as well as allowing for reordering of columns.
http://ecolumns.demopage.ru/index.php
The link above takes you to the demo page for the extension and the link below is the link to the extension download page.
http://www.yiiframework.com/extension/ecolumns/
This is by far the easiest way to implement this functionality on your web app.
Start by reading the docs for CGridView,
The constructor for it takes in an array specifying which columns to display (and whether to allow sort on them, etc) so allowing users to select which columns they want to see is almost trivial:
Display a form with checkboxes, the values of which are the names of the columns. When the user submits the form, loop over the checkboxes and add each of the present fields to the array that is passed to CGridView.
It is a little more complicated if you want to have specific settings for the column (i.e. a specific column header, or formatting) however not too much - in that case you just define an array holding the settings for it, and add that array to the total array you submit to CGridView.
Allowing drag and drop of the columns is a far more challenging enterprise, and may not actually be possible without a custom implementation - this is because CGridView is inherently just a table i.e. you could drag and drop rows easily (as they are whole items), but dragging a dropping a row is in reality dragging and dropping a lot of separate cells. However, there are jQuery examples that could get you started - and it wouldnt be a huge issue to implement a CGridView that uses divs instead of a table, and uses cells inside columns, rather than cells inside rows.
I hope that helps a little.
I've been struggling with this for a while now. One my CMS' is ready to be extended with a translation module. I've been thinking of different methods but haven't figured out what is the best way so far.
Basically I have a CMS which uses a template system to parse all data from a database to the screen. I've come so far to "split up" my templates in different folders to be able to translate things that are "static" like images with text, footer links, etc.
However, there are many modules (pages, news, products) that have multiple fields that require a database driven method to be translated. I started off with a "languages" table which describes languages (id, iso_code, name). That's as far as I've come.. since there were a couple of projects that had to be done I haven't spend any more time to this subject thus far.
My first thought ("the quick fix") was to add multiple fields inside the tables (such as "title_nl", "title_en"), but this actually makes the database more crowded than is needed in my opinion.
My second thought was to create a table, "news_translations" for example. Which contained the language iso code, a news_id, the fields that require translation. Obviously a news_id connects the translation to it's original and the language iso code is used to get the right language from the database. Then in my front-end code I would first check if the default language is selected (=> select from the "news" table) or a translation (=> check inside translations table). If the 2nd case does not return any results a message is display "Sorry, no translation available" and the default is shown (or an error message, what fits the client best..).
But then there's a 3rd option.. my websites all use search engine friendly links (www.domain.com/pagename/ or www.domain.com/news/1-news-item-here.html). It would be far better if I had the ability to also "override" the SEF URL in my translations table. But I guess in this case I would always need 1 extra query to the translations table (since we first want to check for a translated page)... guess it's not such a big deal, but it's worth considering I guess.
In the end I guess by describing my options number 3 is what I need. But I'd like to have some other opinions on the subject as well! This is what I am trying to achieve:
Create a CMS system with multi language support
No language files (obviously this is why I use templates)
Being able to translate an original page/newsitem/product
Optionally: to change the SEF URL according to the language
I think option 3 has all this.. so the steps to create this solution is:
Create a _translation table for each item (or perhaps even in the
original by adding 2 new fields 'translation_to' (containing the
PrimaryKey) and 'translation_is' (containing ISO code) - however..
in that case all fields would need to be edited (which is not always
necessary.. plus by creating a 2nd table I keep the originals
divided with their translations, right?)
If the default language is NOT chosen first query the translations table to find a translation, if one is found display the
translation. Otherwise notify/error the user and/or display the
original text (based on the SEF URL... if the SEF is not found
within the translations or original table, then obviously display an
error only).
Any suggestions? :-)
Thanks for thinking along!
I would like to see what your table structure looks like. Probably the best thing you can do is generate two seperate new tables named something like "CONTENT_MULTI_LANG" & "SITE_LOCALES".
Then in the code that prints out your content do an initial check for a language flag. I'd create two separate classes for loading static content, something like "Content_LoadStandard" and "Content_LoadMultiLang". So then your conditional will look like this.
if ($this->site_locale == 'standard'){
$contentLoader = new Content_LoadStandard();
} else {
$contentLoader = new Content_LoadMultiLang($this->site_locale);
}
$content->blah($cheese);
Your "CONTENT_MULTI_LANG" table should be a narrowed down version of your standard CMS object table, only containing the relevant content field(s) that need to be in alternative languages.
// PSEUDO SQL
CREATE TABLE `LOCALE` (
`id` int(11),
`locale` varchar(16), // name of locale (language)
... // any other fields
)
CREATE TABLE `CONTENT_MULTI_LANG` (
`id` int(11),
`pcid` int(11), // parent content id
`lid` medint(), // locale id
`content` {$type}, // whatever type you use (varchar, text, bin, etc)
... // any other fields
)
In your Content_LoadMultiLang class, create methods to query alternate content using a join.
TIP: Might be a good idea to establish relationships in your table to do cascading deletes on content rows, that way if you delete content in standard your multi lingual version(s) will also be deleted.
From what I've seen from Drupal, option three is how they handle it, with a couple of tweaks. They keep it all in one table and a field called language. Then there is a separate table that maps which items are connected.
This way is primary language agnostic, meaning the content can be created in any language without requiring a translation in any other.
How would I go about writing up a basic tags feature? (similar to the one on this site)
I'm struggling coming up with good logic with little redundancy and would like a more experienced programmer's take on this.
The site I have is fully developed as of right now and has a search feature (searches through titles) - I'm just looking to expand on this and allow the search to sift through tags as well.
Edit:
I was considering adding a row on to my main table called "tags". Then separating them by spaces.
But I have also thought about create a new table and using the same id's from my main table, creating tags in this manner.
I'd suggest 2 tables. One contains Tags - the name of the tag, a tag id, any anything else you want to keep track of on a tag. Also create a relationship table that connects your article/post id to the tag id. You won't repeat data in the database, you should be able to search the tags and join tables together to come up to return articles, and also query the tags if you want to display them along with posts.