Update – I’ve fixed it

I’ve been able to fix this problem, check out my solution.


This past week or so has not been my best. I’ve managed to use, and then break, two different authentication systems, and finally after building my own, had some major problems getting the registration page working. Happily however, by last night I had not only got the authentication system working, with a fully functioning registration page, but I had also been able to improve all my other existing code to make it function much more efficiently. But that’s not what this post is about

The set-up

I’m looking for some help getting Cake to save data to three different models all from one form. The three models in question are Story, Chapter and Path, each of which looks like this:

CREATE TABLE IF NOT EXISTS `stories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `slug` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
  `title` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
  `introduction` text COLLATE utf8_unicode_ci NOT NULL,
  `background` text COLLATE utf8_unicode_ci NOT NULL,
  `approved` tinyint(1) NOT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

CREATE TABLE IF NOT EXISTS `chapters` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `story_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `path_id` int(11) NOT NULL,
  `title` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
  `content` text COLLATE utf8_unicode_ci NOT NULL,
  `approved` tinyint(1) NOT NULL,
  `views` int(11) NOT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

CREATE TABLE IF NOT EXISTS `paths` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `chapter_id` int(11) NOT NULL,
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

With the following relations:

  • Story hasMany Chapter
  • Chapter belongsTo Story
  • Story hasMany NextPath (changed the name of the relation to solve some other issues)
  • Path belongsTo PrevChapter (ditto)

I also have $recursive set to -1 across the whole site as I’m using the Containable Behaviour.

The code

The idea is that upon adding a story to the site, you also need to provide the first chapter of the story, and then two paths which lead away from the chapter.

The code for the form is:

<?php echo $form->create('Story', array('url' => '/stories/add/'));?>
<fieldset>
<legend>Story information</legend>
<dl>
<dt><?php echo $form->label('Story.title', 'Story title'); ?></dt>
<dd><?php echo $form->text('Story.title'); ?></dd>
<dd><?php echo $form->error('Story.title'); ?></dd>

<dt><?php echo $form->label('Story.introduction', 'Story introduction'); ?></dt>
<dd><?php echo $form->textarea('Story.introduction'); ?></dd>
<dd><?php echo $form->error('Story.introduction'); ?></dd>

<dt><?php echo $form->label('Story.background', 'Story background'); ?></dt>
<dd><?php echo $form->textarea('Story.background'); ?></dd>
<dd><?php echo $form->error('Story.background'); ?></dd>
</dl>
</fieldset>
<fieldset>
<legend>First chapter</legend>
<dl>
<dt><?php echo $form->label('Chapter.title', 'Chapter title'); ?></dt>
<dd><?php echo $form->text('Chapter.title'); ?></dd>
<dd><?php echo $form->error('Chapter.title'); ?></dd>

<dt><?php echo $form->label('Chapter.content', 'Chapter content'); ?></dt>
<dd><?php echo $form->textarea('Chapter.content'); ?></dd>
<dd><?php echo $form->error('Chapter.content'); ?></dd>

<dt><?php echo $form->label('NextPath.0.title', 'First path'); ?></dt>
<dd><?php echo $form->text('NextPath.0.title'); ?></dd>
<dd><?php echo $form->error('NextPath.0.title'); ?></dd>

<dt><?php echo $form->label('NextPath.1.title', 'Second path'); ?></dt>
<dd><?php echo $form->text('NextPath.1.title'); ?></dd>
<dd><?php echo $form->error('NextPath.1.title'); ?></dd>
</dl>
</fieldset>
<?php echo $form->end('Submit');?>

And the code for the controller is:

function add()
	{
	// check if form has been submitted
	if (!empty($this->data)) // form not empty, continue
		{

		$this->data['Story']['user_id'] = $this->Auth->user('id');
		$this->data['Chapter']['user_id'] = $this->Auth->user('id');
		$this->data['Chapter']['path_id'] = 0; // set to zero because there is no previous path

		// attempt to save data
		if ($this->Story->saveAll($this->data, array('validate' => 'first'))) // passed validation and successfully saved
		{
			// set success message and forward to posted chapter
			$this->Session->setFlash('The story has been saved', 'success');
			$this->redirect(array('controller' => 'pages', 'action' => 'storyadded'));
		}
		else // chapter unable to save, set error message and return to form
		{
			$this->Session->setFlash('The story could not be saved. Please fix the errors below.', 'warning');
		}
	}
}

The problem

The problem I have is that when I submit an empty form, the validation for the Story and Chapter models works (displays the correct error messages next to the correct fields), but the ones for the Paths do not. I also get a couple of errors along the top of the page:

Warning (2): Cannot use a scalar value as an array [CORE\cake\libs\model\model.php, line 1590]

Warning (2): preg_match() expects parameter 2 to be string, array given [CORE\cake\libs\validation.php, line 848]

If I submit the form with valid data, the stories table populates correctly, the chapters table almost populates correctly (the story_id field is left blank, and the first characters of the title and content fields is replaced with the value that should be in story_id), but the paths do not populate at all.

The cry for help

I really hope that someone out there on the internets can help me with this problem. Thank you

Related posts: