Jump to content
Larry Ullman's Book Forums

lrzins

Members
  • Posts

    20
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by lrzins

  1. Hi Larry, on page 216 of your Yii book, you describe how to rename an uploaded file using the $model->id of the User model. I think this is a good idea, but I don't see how your code can work without an afterSave or something.

     

    Here is your code:

    $model->avatar->saveAs($dest . '/' . $model->id . '.' .
        $model->avatar->extensionName);

    The line above would have to come after the code to save the model:

    if ($model->save())

    because you don't obtain the $model->id until after you save it.

     

    But since you've already saved the file's name to the database, the filename in the database and the name of the uploaded file don't match.

     

    And you should'nt save the uploaded file in the file system until you know that the save to the database was successful.

     

    Do you see what I mean? Am I missing something?

     

    Larry Z.

     

     

  2. Hi Larry, to determine if any records are returned using find() and findAll(), I see that when nothing is returned using find(), that a NULL is returned. When nothing is found using findAll that an empty array is returned.

     

    Is this the best way to determine if records are returned?:

     

     

    $var=SomeModelClass::model()->find($condition, $params);
    
    if ($var !== null) 
        // Check if a single record is returned.
    

     

     

    $var=SomeModelClass::model()->findAll($condition, $params);
    
    if (!empty($var))
       // Check for returned records
    

     

    Larry Z.

  3. Update: To sort by department abbreviation + course number, I had to use this in the Course model:

            public function search()
            {
                    $criteria=new CDbCriteria;
                    $criteria->with = array('department');
                    $criteria->compare('department.department_abbreviation',$this->dept_course,true);
                    // Other criteria
    
                    return new CActiveDataProvider($this, array(
                            'criteria'=>$criteria,
                            'sort'=>array(
                                    'attributes'=>array(
                                            'dept_course'=>array(
                                                    'asc'=>'department.department_abbreviation, course_number',
                                                    'desc'=>'department.department_abbreviation desc, course_number',
                                            ),
                                            '*',
                                    ),
                            ),
                    ));

    Whew!

  4. Hi Larry, I got the column to sort. I'm fairly comfortable with the solution, but still wonder if there is a better way. I'll definitely revisit this later. Here's what I did:

     

    Created a new attribute called $dept_course in my Model:

    class Course extends CActiveRecord
    {
            public $dept_course;
     

    Then set up the search() method in the Course Model to use this attribute to access the related fields in the Department Model, and sort the returned values:

    public function search()
            {
                    $criteria=new CDbCriteria;
                    $criteria->with = array('department');
                    $criteria->compare('department.department_abbreviation',$this->dept_course,true);
                    // Other compare criteria
    
                    return new CActiveDataProvider($this, array(
                            'criteria'=>$criteria,
                            'sort'=>array(
                                    'attributes'=>array(
                                            'dept_course'=>array(
                                                    'asc'=>'department.department_abbreviation',
                                                    'desc'=>'department.department_abbreviation desc',
                                            ),
                                            '*',
                                    ),
                            ),
                    ));
    

    It was not necessary to add "dept_course" to the 'safe' scenario in the rules method of the Model.

     

    Then in the admin.php view file, assign the new attribute to the name parameter of the columns array in the CGridView:

    <?php $this->widget('zii.widgets.grid.CGridView', array(
            'id'=>'course-grid',
            'dataProvider'=>$model->search(),
            'columns'=>array(
                    array('name'=>'dept_course', 'value'=>'$data->department->department_abbreviation . " " . $data->course_number', 'header'=>'Course'),
    

    This solution was gleaned from the following wiki article:

     

    http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview

     

    Larry Z.

     

  5. Well in fact that column is defined as:

     

    array('name'=>'Course', 'value'=>'CValidator::isEmpty($data->course) ? "Other University" : $data->course->department->department_abbreviation . " " . $data->course->course_number'),

    but now it's not sortable when clicking the column header.

     

    I can't figure out how to sort this column. Is it easy?

     

    Larry Z.

  6. I found the cause of the problem. It's that I need to have a NULL value in a foreign key. I have the foreign key "course_id" defined in a course_taken table, that references the course table, that needs to be NULL sometimes. In the CGridView widget, with a NULL value for "course_id" this way works:

     

    'course.course_number',

    and this way generates the error "Trying to get property of non-object":

     

    array('name'=>'Course', 'value'=>'$data->course->course_number'),

    So I believe the best solution is to check for a NULL in the 'value' property (above). Unfortunately this level of detail is not explained in the  Yii documentation.

     

    Larry, will you be covering this stuff in the Widgets chapter of your wonderful book?

     

    Larry Z.

  7. Sorry to spam the list again. I just deleted all rows from the course_taken table, and it works now:

     

    array('name'=>'Course', 'value'=>'$data->course->department->department_abbreviation . " " . $data->course->course_number'),
     

    I did'nt even look at the data first, before deleting it, so it's not clear what the cause was. Onward!

     

    Larry Z.

  8. Hi there, I've got a column defined in a CGridView widget, in the view file admin.php, that correctly returns the course_number attribute from a related table:

     

    <?php $this->widget('zii.widgets.grid.CGridView', array(
            'id'=>'course-taken-grid',
            'dataProvider'=>$model->search(),
            'columns'=>array(
            'course.course_number',
            // Other columns
           array(
                            'class'=>'CButtonColumn',
                    ),
            ),
    )); ?>
    

    For some reason, if I use the name/value syntax to do the same thing:

     

    array('name'=>'Course', 'value'=>'$data->course->course_number'),
    

    I get the error "Trying to get property of non-object".

     

    I can't figure out why. In the same CGridView widget, in the same file, a simliar query works:

     

    array('name'=>'Student Name', 'value'=>'$data->studentRecord->user->first_name . " " . $data->studentRecord->user->last_name'),

     

    And I need to do something similiar in order to obtain the course number and department abbreviation from related tables.

     

    Weird right?

     

    Thanks for any tips.

     

    Larry Z.

     

     

  9. For Pete's sake, I just figured it out, thanks to this post:

     

    http://www.yiiframework.com/forum/index.php/topic/28254-using-cdetailview-to-show-another-models-view/

     

    and then this made more sense:

     

    http://www.yiiframework.com/doc/api/1.1/CDetailView#attributes-detail

     

    At least this is one way to do it I suppose. You can access data in the database directly using a relation defined in your model.

     

    In my Course model I have this relation:

     

    'department' => array(self::BELONGS_TO, 'Department', 'department_id'),
    

     

    In the view.php file I add an attribute to the CDetailView widget that accesses the data:

     

    <?php $this->widget('zii.widgets.CDetailView', array(
            'data'=>$model,
            'attributes'=>array(
                    array('label'=>'Department', 'name'=>'department_name', 'value'=>$model->department->department_name),
                    'course_title',
                    'department_core_course',
                    'elective_graduate_or_upper_division',
                    'units',
            ),
    )); ?>
    

     

    And in the _view.php file:
     
    <b><?php echo CHtml::encode($data->getAttributeLabel('department_id')); ?>:</b>
    <?php echo CHtml::encode(department_name); ?>
    <br />
    

     

    But what if you make a calculation in a controller, which is not stored in the database, and want to display it in the _view.php file? Would it be available in $this->some_variable? OK I'll test...
     
    Whew!
     
    Larry Z.
     
  10. Hi, I'm using Yii version 1.1.13. I've generated a variable in a controller, that I need to display in the view file "_view.php". I pass the variable to "view.php" with render, and I can access it there. But I can't figure out how to access the variable from "_view.php", which uses the CDetailView widget. How is this done? Am I missing something? You would think this would be very easy, since it is such a common task.

     

    Thanks for any tips,

    Larry Z.

     

  11. Hi, I am having to use the same Model methods in several different views. For example, in several different views for creating a new record, I have forms that have a drop down list of years from which to choose. I can add the same method getYears() to each model, and call the method from _form.php, like so:

     

    <?php echo $form->dropDownList($model, 'year_entered', $model->getYears(), array('empty' => 'Select Year')); ?>

     

    Or, I can reuse that method from another view like so:

     

    <?php echo $form->dropDownList($model, 'year', OtherModel::getYears(), array('empty' => 'Select Year')); ?>

     

    So then I thought, why not create a class just to hold shared methods, like so:

     

    In models/SharedStuff.php:

     

    class SharedStuff extends CActiveRecord
    {
    
         public function getYears()
         {
               $current_year=date('Y');
               $end_year=$current_year - 20;
               for ($year = $current_year; $year >= $end_year; $year--) {
                      $year_list[$year] = $year;
               }
               return $year_list;
         }
    }
    

     

    Which can be referenced from any _form.php file like so:

     

    <?php echo $form->dropDownList($model, 'year', SharedStuff::getYears(), array('empty' => 'Select Year')); ?>

     

    I guess another way to do this, is to move the SharedStuff.php class into the "components" directory, and then extend this class in the model files, but the approach above seems pretty clean.

     

    Is there a better way to share methods between different views, and I suppose controllers and models too? Am I missing something?

     

    Thanks for any advice,

     

    Larry Z.

  12. Thanks Edward and Antonio, that explains it. As Edward suggested, I moved the code from the controller into the model, and now have:

     

    In models/StudentRecord.php

     

    public function getStudentNames()
    {
        return CHtml::listData(User::model()->with('studentRecords')->findAll(), 'id', 'FullName');
    }
    

     

    In models/User.php

     

    public function getFullName()
    {
        return $this->first_name . " " . $this->last_name;
    }

     

    And in views/studentRecord/_form.php

     

    <?php echo $form->dropDownList($model, 'user_id', $model->getStudentNames(), array('empty' => 'Select Student Name')); ?>

     

    I think this is a good way to do it. It's nice to know about the convention of adding "get" to the method names (why and where).

     

    Best regards,

    Larry Z.

  13. Hi, I've created a drop down list of user's names, that I've concatenated from first_name and last_name in a database table. And it works perfectly! Here's what I've got:

     

    User Model:

     

    public function getFullName()
    {
        return $this->first_name . " " . $this->last_name;
    }

     

    StudentRecordController, in actionCreate():

     

    $students = CHtml::listData(User::model()->with('studentRecords')->findAll(), 'id', 'FullName');

     

    And in views/studentRecord/_form.php:

     

    <?php echo $form->dropDownList($model, 'user_id', $students, array('empty' => 'Select Student Name')); ?>

     

    My question is, how is the getFullName() method called by the third argument to listData, which is 'FullName'? The "get" is parsed out? If I use the full method name instead (getFullName), it does'nt work. And actually fullname, fullName, FuLlNaMe all work.

     

    Bear in mind, that with this approach, you have to include the $students array in the render method of the controller and the view.

     

    Larry Z.

  14. Just to wrap this up, I recreated the database tables with MyISAM, and used the "comment" method to declare the table relationships, and Gii outputed the exact same model files (rules and relations). I've used other PHP frameworks before, and Yii is looking very good. I'm delighted that Larry Ullman is writing a book about it. He's the best. In the future, I'll try not to use this forum as a personal blog (but hopefully it was useful to somebody).

     

    Larry Z.

  15. After looking into the problem more, I see now that in this relationship, the faculty table is the parent table, and the student_record table is the child table, and with a foreign key constraint, you can't insert a record in a child table without a reference to the parent table. So yes I have to remove the constraint.

     

    The lesson learned here, is that you can't liberally apply foreign key constraints just so that Gii will generate the table relationships in the model files for you! I will now try using the comment method of specifying relationships in MyISAM tables for Gii:

     

    approved_by int unsigned comment "constraint foreign key (approved_by) references faculty (id)",

     

    I wonder if the comment method for specifying table relationships for Gii will work in InnoDB tables?

     

    Cheers everybody,

     

    Larry

  16. Hi, I have a student_record table that has a field "approved_by" that has a BELONGS_TO relationship to a faculty table. My intention is to be able to create a student record for a student, and then at some point in the future, one of a list of faculty members can approve something.

     

    So I have the following foreign key contraint set up on the student_record table:

     

     

    CONSTRAINT

    FOREIGN KEY (approved_by)

    REFERENCES faculty (id)

    ON DELETE SET NULL

    ON UPDATE NO ACTION

     

    And I find that if I try to create a new student record, it is rejected with an "Integrity constraint violation", because I have'nt provided a faculty id in the approved_by field. So obviously I have to be able to create a student record without the approved_by field being set, since this is set by a faculty member at a future time.

     

    So must I remove this constraint to be able to do this?

     

    My main reference is: http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html

     

    I'm using MySQL 5.0.95

     

    I normally use MyISAM tables, but I was eager to see the relations() entries that Gii would generate if I used InnoDB and foreign key constraints. I'm learning Yii on relatively complex schema with 24 tables and lots of relationships.

     

    Thanks for any info.

     

    Larry (my name is Larry too)

     

    Love your books :)

×
×
  • Create New...