I am having a problem with my CakePHP 1.3 app, and I'm not sure if it's a code issue or a DB issue.
I have a pretty simple function in one of my controllers, and whenever I add a query portion to that controller, I get the following (infuriating and completely unhelpful) error message:
Missing Controller
Error: InternalError.htmlController could not be found.
Error: Create the class InternalError.htmlController below in file:
app/controllers/internal_error.html_controller.php
Here is the Model ForecastZones
class ForecastZone extends AppModel {
var $name = 'ForecastZone';
var $displayField = 'name';
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
var $hasMany = array(
'ForecastZonePoly' => array(
'className' => 'ForecastZonePoly',
'foreignKey' => 'forecast_zone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
Here is the controller function that inexplicably fails:
function poly($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid forecast zone', true));
$this->redirect(array('action' => 'index'));
}
$this->layout = false;
$result = $this->ForecastZone->query("SELECT coords FROM forecast_zone_polies WHERE forecast_zone_id = $id;");
$this->set('forecastZone', $result);
}
CakePHP epic fails whenever I call this controller action. It hangs for a LONG time... and then instead of telling me something useful like "database query took too long" or "model association broken" or something like that... it just gives up and gives me this complete BS error message.
This is not a path issue, the paths are correct. If I remove the $result variable, everything works fine and I get the appropriate "forecastZone is not set" error message. The crux of this issue seems to be a query that takes forever, and then Cake not properly reporting the error message.
Please help clear this up for me. Very frustrating... not "Cake" at all by any stretch of the word.
EDIT: I wanted to add that I originally had been using
$this->ForecastZone->read(null,$id);
To grab the data, but the hanging & failing of the query kept happening so I switched to the raw query in hopes that might change something.
EDIT 2:
More things I tried:
Added this line to the top of my controller:
var $uses = array('ForecastZone','ForecastZonePolies');
And then tried to do things "the right way" that still fail. UGH!
$result = $this->ForecastZonePolies->find('all',array('conditions' => array('ForecastZonePolies.forecast_zone_id' => $id)));
$result = $this->ForecastZone->ForecastZonePolies->find('all',array('conditions' => array('ForecastZonePolies.forecast_zone_id' => $id)));
None of these work.
First I'd check app/tmp/logs/error.log and app/tmp/logs/debug.log. If this really is an internal error, you should get details there.
From the weird inflecting, I'd suggest you to put Router::parseExtensions('html') in your app/config/routes.php to make sure this isn't a redirect issue.
Related
A model that I am using with both TranslateBehavior and TreeBehavior is failing to save. I suspect it is something to do with one of these behaviors. Here's the data going in:
array(
'Category' => array(
'id' => '3252',
'parent_id' => null,
'sort_order' => '0',
'name' => array(
'eng' => 'english name',
'fra' => 'french name',
'deu' => 'german name',
'ita' => 'italian name',
'spa' => 'spanish name'
),
)
)
And $this->Category->validationErrors is:
array(
'parent_id' => array(),
'sort_order' => array()
)
There are no validation rules defined in the model. There is no beforeSave() or beforeValidate() method defined.
I am not getting any validation errors displayed on screen, although all fields have the red "error" outline.
Edit - the save operation is not getting as far as Category::beforeSave(). I created that function and it does not get run. It gets as far as Category::beforeValidate().
$validates = $this->Category->validates($this->request->data);
debug($validates);
$saved = $this->Category->saveAll($this->request->data);
debug($saved);
In the above code, $validates is true, $saved is false. Category beforeSave is not called at any point in the above process. The validation seems to fail on the call to saveAll(). I need to use saveAll rather than save to save all translations at once (I am doing this elsewhere with another model with no problems).
So, after a while debugging I have found the problem:
public $hasMany = array(
'Category' => array('className' => 'Category', 'foreignKey' => 'parent_id', 'counterCache' => true),
...
I have no idea why I wrote this - I should have been aware that it was going to cause problems, I think I meant to write...
public $hasMany = array(
'Children' => array('className' => 'Category', 'foreignKey' => 'parent_id', 'counterCache' => true),
...
Anyway, changed it to the latter and these errors have gone.
Maybe it doesn't like the null and zero value of parent_id and sort_order? Also in the database what are their field types set as? Do they allow null values? etc. I'm guessing that as there are no validation rules in the model or parent/App model, then it must be some default validation with cake's lib linking to the database/mysql table itself. So I would check the Categories table structure for the parent_id and sort_order fields.
For CakePHP 2
I would like to create a categories menu which would list the categories of my products. It's a 3 levels menu. Each category in the menu is a link that opens a page listing all the products that belong to it. So if the category is a parent one, it should list all the products contained in the children, the 2 sub-levels. Also, if the category is a children, it should link to a listing page of the products that belong to it.
With that said, here's what I've done so far.
I created my categories table according to cake's conventions with the following columns:
id--parent_id--lft--rght--name
Then my products' table:
id--name--slug--category_id
Now the Category.php model:
<?php
class Category extends AppModel {
public $name = 'Category';
public $actsAs = array('Tree');
public $belongsTo = array(
'ParentCategory' => array(
'className' => 'Category',
'foreignKey' => 'parent_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
public $hasMany = array(
'ChildCategory' => array(
'className' => 'Category',
'foreignKey' => 'parent_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
I'm using the ProductsController to render the categories menu because this is the page that will hold this categories menu:
<?php
class ProductsController extends AppController{
public $uses = array('Product');
public function index(){
$this->layout = 'products';
$this->loadModel('Category');
$this->set('data',$this->Category->generateTreeList());
}
}
and my index.ctp view:
<?php debug($categories); ?>
What i would like now is to build a nested ul-li menu of my categories that link to the products page they belong according to the tree.
<ul class="ulclass">
<li class="liclass">category</li>
</ul>
I checked only for this kind of tutorial, unfortunately I didn't find anything well explained, I did find a TreeHelper but i have no idea how to use it >>> TreeHelper from Github
However, I would like to have the control on my category's tree menu by having the possibility to add css classes. If you think this helper can provide me this construction so it's fine then. But I have no idea how to use it though. And not to mention that I'm new to CakePHP :( but I want to learn it because it's a great tool.
I forgot something about my DB, do I have to add any other column in my tables to make this system work or is it correct as is?
Last thing, as I didn't find anything for CakePHP 2 about this categories/products dynamic tree menu, I will share the entire code on Github so that it can help many others.
All right.
Assuming you use my updated version:
// in your controller
$categories = $this->Model->children($id);
// or
$categories = $this->Model->find('threaded', array(...));
Then pass it down to the view.
// in your view ctp
$categories = Hash::nest($categories); // optional, if you used find(all) instead of find(threaded) or children()
$treeOptions = array('id' => 'main-navigation', 'model' => 'Category', 'treePath' => $treePath, 'hideUnrelated' => true, 'element' => 'node', 'autoPath' => array($currentCategory['Category']['lft'], $currentCategory['Category']['rght']));
echo $this->Tree->generate($categories, $treeOptions);
And here an example of the element in /Elements/node.ctp:
$category = $data['Category'];
if (!$category['active'] || !empty($category['hide'])) { // You can do anything here depending on the record content
return;
}
echo $this->Html->link($category['name'], array('action' => 'find', 'category_id' => $category['id']));
Here is a simple solution, Used in controller for index view. Later you use it by two for each loops for each $posts as $post and foreach $post['Post']['children'].
$posts = $this->Post->find('all', array('conditions' => array('parent_id'=>null)));
foreach ($posts as $postKey => $post) {
$posts[$postKey]['Post']['children'] = $this->Post->find('all', array('conditions' => array('parent_id'=>$post['Post']['id'])));
}
$this->set('posts', $posts);
I'm working on a small app to help learn cakephp 2.0. Its a simple task manager app.
Tables
users
tasks
tasktypes
I've a set up a foreign key in the tasks table called 'user_id'
As a task belongs to a user.
Now all I'm trying to do is display the tasks of a certain user and it wont work at all despite the sql query getting correct results when I tested it any help would be great.
In my taskscontroller I've the method;
//show the tasks of the current user
public function mytasks(){
$this->set('title_for_layout', 'Gerrys TaskManager: Display Tasks');
$this->Task->recursive = 0;
$tasks=$this->Task->find('all', array('conditions'=>array('username'=>'admin')));
$this->set('tasks', $this->paginate());
}
I'm trying to find the tasks of the user 'admin' or the "realted tasks" what am I doing wrong?
I suspect the problem maybe to with my models;
usermodel
/**
* hasMany associations
*
* #var array
*/
public $hasMany = array(
'Task' => array(
'className' => 'Task',
'foreignKey' => 'user_id'
)
);
task model;
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Tasktype' => array(
'className' => 'Tasktype',
'foreignKey' => 'tasktype_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
To get the tasks that belong to a user, it's much simpler to do that in the UsersController. Of course you have to set User hasMany Task in your UserModel.
Now you can create a function, for example to view the User and it's Tasks by id:
public function view($id = null) {
$this->User->id = $id;
$this->set('user', $this->User->read(null, $id));
}
The Tasks should now be available in your view by $user['tasks']. You have to pass the id in the url like: /path_to_your_app/users/view/1
You can always use debug() to see contents of an array or variable. To see what you've got add <?php debug($user);?> to your view.
You most likely want to list any tasks with a foreach in your view, very simple example::
foreach($user['Task'] as $task) {
echo $task['field1'] . ": " . $task['fied2'];
echo "<br />";
}
of course you might want to display the tasks in tables or something.
A good starting point for learning cakePHP is the Blog-Tutorial:
http://book.cakephp.org/2.0/en/getting-started.html#blog-tutorial
I am new to cakePHP and fairly new to PHP as well, I have gone through some Youtube videos to help me make a basic site set up with CRUD pages for everything. I am now trying to set up the user signup page to add a bunch of stuff to a HABTM table but cant figure out what is going wrong.
$this->User->create();
if ($this->User->save($this->data)) {
$lvl = $this->data['User']['level'];
$charids = $this->Kanji->find('list',array('conditions'=>array('grade' <= $lvl,'grade' >= 0)));
foreach ($charids as $charid){
$characterList = array('kanji_id'=>$charid,'user_id'=>$this->User->id, 'level'=>2);
$this->kanjisUsers->save($characterList);
A bit of clarification, The site is for a school project, I want it to help with learning Japanese and the idea is that you can put a string of Japanese text and it will simplify it to your level so when you sign up you tell it what your level of Japanese is (an int between 1 and 9) then it will go through the character list (kanjis table) and find all with a number equal to or less than your level (called 'grade' in the kanjis table) then I want it to add all these to the kanjis_users table with the int 2 to indicate it is known (then I will do it again with one level up characters and save them with int 1 for 'learning')
I had help with the code and am not sure how it all works, I have been changing lots of things and cant figure out what is wrong, any suggestions?
note: I also saw that the model was called kanjis_user.php and KanjisUser, I read the model should not be plural but when I tried to change it everything crashed, could this be a part of the problem?
I have also tried changing => with -> and vice versa and also created $characterList to remove it from the save function, don't know if these affected anything as it never worked...
Edit in response to comment by api55:
Here is the model relation For kanjis_users:
class KanjisUser extends AppModel {
var $name = 'KanjisUser';
//Validation stuff here
var $belongsTo = array(
'Kanji' => array(
'className' => 'Kanji',
'foreignKey' => 'kanji_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Here is the kanji mode:
var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'kanjis_users',
'foreignKey' => 'kanji_id',
'associationForeignKey' => 'user_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Here is the user model:
var $hasAndBelongsToMany = array(
'Kanji' => array(
'className' => 'Kanji',
'joinTable' => 'kanjis_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'kanji_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
This is just the standard generated model (minus validation).
For clarification on the error, there is no error, it just doesn't work, It saves the user, but dose not add anything to the kanjis_users table. Here is the whole register controller as it is now:
function register() {
if (!empty($this->data)) {
$this->User->create();
if ($this->User->save($this->data)) {
$lvl = $this->data['User']['level'];
//$test = $this->Kanji->find ('list',array('Kanji.grade <='<=$lvl, 'AND'=>array('Kanji.grade >=' >= 1)));
$charids = $this->Kanji->find('list',array('conditions'=>array('grade <=' => $lvl,'grade >=' >= 1)));
//print_r($charids);
//exit();
//$this->kanjisUsers->save(array('kanji_id'=>$charids,'user_id'=>$this->User->id));
//$this->kanjisUsers->saveALL(array('kanji_id'=>$charids,'user_id'=>$this->User->id));
foreach ($charids as $charid){
//echo("<p>Charid: ".$charid." is: </p>");
//var_dump($charid);
$this->kanjisUsers->save(array('kanji_id'=>$charid,'user_id'=>$this->User->id),'level'=> 2);
}
//exit();
$this->Session->setFlash(__('The user has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
}
}
}
Both seem to generate a similar array, but however I change the code sometimes it will crash, sometimes it will save the user, but it will never do anything to the kanjis_users table.
What I want:(simplified for clarity:
User table has: name, username, pw, userID etc...
kanjis table has: a Chinese character per row with ID, English, grade(int from 0 to 9) etc...
kanjis_users has: ID, user_id, kanji_id, created(date), modified(date), level(int).
I want a user to put a level when they sign up and then when the user gets created it will populate the kanjis_users table with all the rows in the Kanji table that have a 'grade' between 1 and the level the user put in the sign up form (called 'level').
So what I am trying to do above is after the user is saved (this user create() at the top), I then test if the save was a success and then get the level the user put in the form, and try to get all the characters from the rows from the kanjis table where the level is equal to or less than that (note I don't want to get ones with 0 as they are the hardest ones...) and add them all to the kanjis_users table. (this is only for sign up, when using the system the user can add and remove characters as they wish)
I noticed with the print_r that it was getting all 12000~ rows from the kanjis table, so I think the filter was not working...
I hope this makes sense, please let me know if I need to put any further info.
Create an input box in the register view:
$this->Form->input('Kanji', array('type' => 'hidden'));
Then try this:
function register() {
if (!empty($this->data)) {
$this->User->create();
$lvl = $this->data['User']['level'];
$charids = $this->Kanji->find('list',array('conditions'=>array('grade <=' => $lvl,'grade >=' => 1)));
$i = 0;
foreach ($charids as $charid){
$this->data['Kanji']['Kanji'][$i] = $charid;
$i++;
}
if ($this->User->save($this->data)) {
$this->Session->setFlash(__('The user has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
}
}
}
How it works
You save current level to $lvl ($this->data['User']['level'];)
You find all Kanjis maching your criteria ($charids = $this->Kanji->find('list',array('conditions'=>array('grade <=' => $lvl,'grade >=' => 1)));)
You define a new variable equal 0 ($i = 0;)
You make a loop going through your data array, storing every Kanjis you found and assigning it to $this->data['Kanji']['Kanji'] as it would be default data if you have selected it in a form.
You save the data as it has been filled by a form.
Ok, I see wrong 2 things :D
1) You get 12000+ rows from the find beacause your find condition is wrong :S and the one commented that i gave you has typos
the find MUST BE like this:
$test = $this->Kanji->find ('list',array(
'conditions'=> array(
'Kanji.grade <=' => $lvl,
'AND' => array(
'Kanji.grade >=' => 1)
)
)
);
2) the data in your save is wrong:
The cookbook explains that the data passed needs to be like this :
Array
(
[ModelName] => Array
(
[fieldname1] => 'value'
[fieldname2] => 'value'
)
)
So your save part should look something like this:
$this->KanjiUser->create();
$data = array(
'KanjiUser' => array(
'KanjiUser.kanji_id'=>$charid,
'KanjiUser.user_id'=>$this->User->id,
'KanjiUser.level'=>2
)
);
if ($this->KanjiUser->save($data))
echo 'Done ;)';
else
echo 'error';
all this inside the foreach or you can do the saveAll approach
$data = array('KanjiUsers'=> array());
foreach ($charids as $charid){
$data ['KanjiUsers'][] = array(
'KanjiUser' => array(
'KanjiUser.kanji_id'=>$charid,
'KanjiUser.user_id'=>$this->User->id,
'KanjiUser.level'=>2
)
);
}
$this->KanjiUser->create();
if ($this->KanjiUser->saveAll($data['KanjiUser'))
echo 'Done ;)';
else
echo 'error';
So I am trying to get a find table into my elements view and I am doing that by making a helper function in my Tags controller.
<?php
class TagsController extends AppController {
var $name = 'Tags';
function gettags(){
if (!empty($this->params['requested'])) {
return $this->Tag->find('list', array('fields'=>'Tag.tag_name'));
}
return false;
}
}
And then in my view, I call
<? $tags = $this->requestAction('/tags/gettags'); debug($tags); ?>
However, it returns the error
Warning (512): SQL Error: 1054: Unknown column 'Tag.tag_name' in 'field list' [CORE/cake/libs/model/datasources/dbo_source.php, line 684]
Query: SELECT Tag.id, Tag.tag_name FROM users AS Tag WHERE 1 = 1
which means that it thinks my tags table is actually users. This doesn't happen in the Tags view. Anyone have any ideas as to what I'm doing wrong? The tables aren't associated with either other or anything.
My Tag model is:
<?php
class Tag extends AppModel {
var $name = 'Tag';
var $hasMany = array(
'BrandTag' => array(
'className' => 'BrandTag',
'foreignKey' => 'tag_id',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
));
}
?>
Something like this should work:
$this->getModel('Tag')->find('list', array('fields'=>'Tag.tag_name');
As said you shouldn't be retrieving from a view like this, it's not good MVC practice.
If the Tag code will be retrieved by multiple controllers you should consider creating a component which these controllers can load as needed.
Dao it may be worth going into you app/tmp/cache folder and deleting the files in the model folder. You may have cached a corrupt model.