Save associated data into database with cakephp and HABTM - php

I have 2 tables: release_servers and release_components
I have a link table release_server_to_components
I right now have it so that each server can have multiple components and that each component can be on multiple servers.
The following are the create statements:
CREATE TABLE `release_components` (
`id` int(11) NOT NULL auto_increment,
`buildID` varchar(45) default NULL,
`svnNumber` varchar(45) NOT NULL,
`componentType` varchar(45) NOT NULL,
`release_id` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM
CREATE TABLE `release_servers` (
`id` int(11) NOT NULL auto_increment,
`server_name` varchar(45) NOT NULL,
`server_environment` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM
Link table:
CREATE TABLE `release_server_to_components` (
`id` int(11) NOT NULL auto_increment,
`release_component_id` int(11) NOT NULL,
`release_server_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM
What I want to add is the ability to have a system ID -- this system ID would be per component on a server (not per server and not per component, but per the component on each server). I want to be able to easily add the system ID per component and insert it into the database.
I can provide code for models and controllers if needed.

You want to "fake" Ruby's through association with CakePHP.
Why do this over HABTM?
Because you want to save data about the association. With Cake's HABTM saving data about the association is difficult, because the only thing you really have is a JOIN table. You need something more powerful than this.
First, get rid of the $hasAndBelongsToMany property in your model. Next we'll be refitting your release_server_to_components table as your "through" table.
So, in ReleaseComponent and ReleaseServer model you would have an association like this:
$hasMany = array('ReleaseServerToComponent');
Now, in your new ReleaseServerToComponent model you would have an association like this:
$belongsTo = array('ReleaseComponent', 'ReleaseServer');
Now, you can access this table just like a normal Cake model, ie $this->ReleaseServer->ReleaseServerToComponent->find(). You can add additional fields to the through table, like server_component_name. You already have a unique identifier for specific, server components with the primary key of the release_server_to_components table.
You could save this data using Cake's saveAll() method. Alternatively you could generate your own data to save, simply plugging in the server ID and component ID from form fields. At the top of that link is the format saved data should be in when you pass it to the model's save method.

Related

Database Announcements Table - Add Excutable Code Within

I have a database containing over 1,000 item information and I am now developing a system that will have this check the API source via a regular Cron Job adding new entries as they come. Usually, but not always the case, when a new item is released, it will have limited information, eg; Image and name only, more information like description can sometimes be initially withheld.
With this system, I am creating a bulletin to let everyone know new items have been released, so like most announcements, they get submitted to a database, however instead of submitting static content to the database for the bulletin, is it possible to submit something which will be executed upon the person loading that page and that bulletin data is firstly obtained then the secondary code within run?
, For example, within the database could read something like the following
<p>Today new items were released!</p>
<?php $item_ids = "545, 546, 547, 548"; ?>
And then on the page, it will fetch the latest known information from the other database table for items "545, 546, 547, 548"
Therefore, there would be no need to go back and edit any past entries, this page would stay somewhat up-to-date dynamically.
Typically you would do something like have a date field on your items, so you can show which items were released on a given date. Or if you need to have the items associated with some sort of announcement record, create a lookup table that joins your items and announcements. Do not insert executable code in the DB and then pull it out and execute it.
CREATE TABLE `announcements` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`publish_date` DATETIME NOT NULL,
`content` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `items` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` VARCHAR(128) NOT NULL,
`description` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `announcement_item_lkp` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`announcement_id` int(11) unsigned NOT NULL,
`item_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `announcement_item_lkp_uk1` (`announcement_id`,`item_id`),
KEY `announcement_item_lkp_fk_1` (`announcement_id`),
KEY `announcement_item_lkp_fk_2` (`item_id`),
CONSTRAINT `announcement_item_lkp_fk_1` FOREIGN KEY (`announcement_id`) REFERENCES `announcements` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `announcement_item_lkp_fk_2` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
With the announcement_item_lkp table, you can associate as many items to your announcement as you like. And since you have cascading deletes, if an item gets deletes, its lookup records are deleted as well, so you don't have to worry about orphaned references in your announcements, like you would it you just stuff a string of IDs somewhere.
You're already using a relational database, let it do its job.

How do I avoid ambiguous naming between my PHP-code and an SQL junction table?

Given the following database schema (MySQL), I'm worried about possibly introducing ambiguous naming in its PHP 5.5 model class given below (abstracted for simplicity).
CREATE TABLE `catalog_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`catalog_id` int(11) NOT NULL DEFAULT '0'
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catalog_item_property` (
`catalog_item_id` int(11) NOT NULL DEFAULT '0',
`catalog_item_properties_id` int(11) NOT NULL DEFAULT '0'
PRIMARY KEY (`catalog_item_id`,`catalog_item_properties_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catalog_item_properties` (
`id` int(11) NOT NULL AUTO_INCREMENT
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catalog_item_properties_description` (
`catalog_item_properties_id` int(11) NOT NULL DEFAULT '0',
`language_id` int(11) NOT NULL DEFAULT '0'
PRIMARY KEY (`catalog_item_properties_id`,`language_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Some background on the schema:
catalog_item holds items from a catalog.
catalog_item_property holds all properties belonging to a catalog_item.
catalog_item_properties holds a list of all possible item properties.
catalog_item_properties_description holds a multi-language description for all catalog_item_properties.
I'm following a singular naming convention for all my tables.
The interface function names that I am unsure of:
public function getItemProperty($id)
{
// Get all catalog item properties that belong to this catalog item?
}
public function getItemProperties()
{
// Get list of all possible catalog item properties?
}
As you can see, on my current iteration, getItemProperty may return more than one property. But so does getItemProperties. Ideally, I would like the function naming to speak for themselves, and for there to be no ambiguity at all. I would also like there to be a strong relation between the function names and the schema table names, for the sake of consistency.
Some questions I would love to hear some informed opinions on:
Do I change either the table names, or the function names (or both?) to resolve this potential ambiguity? Or, might there be no ambiguity at all?
Is it ok to mix the singular and plural form on table names in this scenario?
I'm pretty new to database design. If I completely missed the best practice approach here, please do let me know. Thank you in advance for sharing your thoughts!

Cake bake don't generate auto rules

I'm newbie in cakephp and i'm generating model's code with bake. But the code generated dont give with a array with auto validations. why not? My fields are not null, an id, an title and an content fields. Sorry for my bad english, and thanks very much.
My table:
CREATE TABLE `pages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(500) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Automatically the cakephp bake doesn't create validation rules for your models. However it provides an interactive shell to create the models and also the validation rules and/or relationships.
More info in the docs

Define relationships in database for CakePHP

Im trying out a sample project in CakePHP. It is taken from the cakePHP documentation. It has a total of 4 tables and two of the are listed here.
CREATE TABLE users (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password CHAR(40) NOT NULL,
group_id INT(11) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE posts (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT,
created DATETIME,
modified DATETIME
);
As you can see the id from the users table is added to the posts table as a foreign key in the form of user_id. But in the sample there are no relationships defined. I mean normally we would explicitly define user_id as a foreign key by adding the constraints (in my case using the Relation View of phpMyAdmin). But it is not done here or we are not instructed to do so. When using Cake Bake console to bake our Models do we need this foreign key constraints in place or does cakephp figure them out automatically?
Convention over configuration
Cakephp figures them out automatically for you but you have to follow the naming conventions

delete main row and all children mysql and php

I have inherited a PHP project and the client is wanting to add some functionality to their CMS, basically the CMS allows them to create some news, all the news starts with the same content, and that is saved in one table, the actually news headline and articles are saved in another table, and the images for the news are saved in another, basically if the base row for the news is deleted I need all the related rows to be deleted, the database is not setup to work with foreign keys so I cannot use cascade deletion, so how can I delete the all the content I need to, when I only what the ID of the base news row is?
Any help would be very helpful I am sorry I cannot give you much more help, here is this the original SQL of tables scheme if that helps?
--
-- Table structure for table `mailers`
--
CREATE TABLE IF NOT EXISTS `mailers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`mailer_title` varchar(150) NOT NULL,
`mailer_header` varchar(60) NOT NULL,
`mailer_type` enum('single','multi') NOT NULL,
`introduction` varchar(80) NOT NULL,
`status` enum('live','dead','draft') NOT NULL,
`flag` enum('sent','unsent') NOT NULL,
`date_mailer_created` int(11) NOT NULL,
`date_mailer_updated` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;
-- --------------------------------------------------------
--
-- Table structure for table `mailer_content`
--
CREATE TABLE IF NOT EXISTS `mailer_content` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`headline` varchar(60) NOT NULL,
`content` text NOT NULL,
`mailer_id` int(11) NOT NULL,
`position` enum('left','right','centre') DEFAULT NULL,
`created_at` int(10) NOT NULL,
`updated_at` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=18 ;
-- --------------------------------------------------------
--
-- Table structure for table `mailer_images`
--
CREATE TABLE IF NOT EXISTS `mailer_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(150) NOT NULL,
`filename` varchar(150) NOT NULL,
`mailer_id` int(11) NOT NULL,
`content_id` int(11) DEFAULT NULL,
`date_created` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;
It is worth noting that the schema cannot be changed nor can I change to the DB to MYISAM so that I can use foreign keys.
Add foreign key to table mailer_content
FOREIGN KEY (mailer_id)
REFERENCES mailers(id)
ON DELETE CASCADE
Add foreign key to table mailer_images
FOREIGN KEY (content_id)
REFERENCES mailer_content(id)
ON DELETE CASCADE
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
It is worth noting that the schema cannot be changed nor can I change to the DB to MYISAM so that I can use foreign keys.
Why can't the schema be changed? You designed the app, didn't you? Even if you didn't, adding the proper keys is just a matter of adding the right indexes and then altering the right columns. #Michael Pakhantosv's answer has what looks to be the right bits of SQL.
Further, it's InnoDB that does foreign keys, not MyISAM. You're fine there already.
If you could change the schema, making the appropriate IDs actual, real Foreign Keys and using ON DELETE CASCADE would work. Or maybe triggers. But that's just asking for it.
Now, for some reason, ON DELETE CASCADE isn't liked very much around here. I disagree with other people's reasons for not liking it, but I don't disagree with their sentiment. Unless your application was designed to grok ON DELETE CASCADE, you're in for a world of trouble.
But, given your requirement...
basically if the base row for the news is deleted I need all the related rows to be deleted
... that's asking for ON DELETE CASCADE.
So, this might come as a shock, but if you can't modify the database, you'll just have to do your work in the code. I'd imagine that deleting a news article happens in only one place in your code, right? If not, it'd better. Fix that first. Then just make sure you delete all the proper rows in an appropriate order. And then document it!
If you can not change the schema then triggers are not an option.
InnoDB supports transactions, so deleting from two tables should not be an issue, what exactly is your problem?
P.S. It would be worth noting which version of the server are you using.

Categories