Akelos Framework v1 forum archive. This forum is no longer maintained. To report bugs please visit https://github.com/akelos/akelos/issues
    • CommentAuthorSport11
     

    So I have a has_and_belongs_to_many relationship between an Asset and a Tag.

    class Asset extends ActiveRecord { var $has_and_belongs_to_many = 'tags'; }

    class Tag extends ActiveRecord { var $has_and_belongs_to_many = 'assets'; }

    I created an Asset controller that has add and edit actions.

    My Add looks like this:

    function add() { if ( $this->Request->isPost() && !empty( $this->params['asset'] ) ) { $this->Asset->setAttributes( $this->params['asset'] );

      if ( empty( $this->params['asset']['tag_id'] ) )
      {
        $this->params['asset']['tag_id'] = array();
      }
    
      $this->Asset->tag->setByIds( $this->params['asset']['tag_id'] );      
    
      if ( $this->Asset->save() )
      {
        $this->flash['notice'] = $this->t('Asset was successfully created.');
        $this->redirectTo( array( 'action' => 'show', 'id' => $this->Asset->id ) );
      }
    }
    

    }

    and the edit as follows:

    function edit() { if ( empty( $this->params['id'] ) ) { $this->redirectToAction( 'search' ); }

    if ( $this->Request->isPost() && ! empty( $this->params['asset'] ) && ! empty( $this->params['id'] ) )
    {
      $this->Asset->setAttributes( $this->params['asset'] );
    
      if ( empty( $this->params['asset']['tag_id'] ) )
      {
        $this->params['asset']['tag_id'] = array();
      }
    
      $this->Asset->tag->setByIds( $this->params['asset']['tag_id'] );
    
      if ( $this->Asset->save() )
      {
        $this->flash['notice'] = $this->t('Asset was successfully updated.');
        $this->redirectTo( array( 'action' => 'show', 'id' => $this->Asset->id ) );
      }
    }
    

    }

    After the add action, I have 1 row in the assets table and 1 row in the assets_tags association table that matches the association I selected in the select box from the form. All is good.

    When I show the form again for the 'edit' action the data gets pre-populated as expected.

    I am using the following to generate the tags select box: $Asset->tag->load(); $tags_selected = $Asset->collect( $Asset->tags, null, 'id' );

    <?php echo $form_options_helper->select( 'asset', 'tag_id', $Tag->collect( $Tag->findAll(), 'name', 'id' ), array( 'selected' => $tags_selected ), array( 'multiple' => 'true' ) ); ?>

    P.S. I modified the AkActiveRecord::collect function to only include an array of values if the 2nd parameter (key) is null. Handy in the cases where you need just the value and no associated key

    The form gets generated properly and the data in the $this->params variable is as expected. The Asset in the db gets updated but I get 2 rows generated in the assets_tags table.

    Here is a development log snippet of the request:

    Asset executing SQL: SELECT * FROM assets WHERE assets.id = 1 LIMIT 1 Tag executing SQL: SELECT * FROM tags WHERE tags.id = 2 LIMIT 1 Tag executing SQL: SELECT tags.* FROM tags LEFT OUTER JOIN assets_tags ON assets_tags.tag_id = tags.id LEFT OUTER JOIN assets ON assets_tags.asset_id = assets.id WHERE assets.id = 1 AssetTag executing SQL: SELECT * FROM assets_tags WHERE asset_id = '1' AND tag_id = '1' AssetTag executing SQL: DELETE FROM assets_tags WHERE id = '186' AssetTag executing SQL: INSERT INTO assets_tags (asset_id, tag_id, created_at) VALUES (1,2,'2008-01-15 17:12:08') Asset executing SQL: UPDATE assets SET id=1, title='Racing Stripes', description='Adding description for now and more', created_at='2008-01-14 15:51:14', updated_at='2008-01-15 17:12:08' WHERE id=1 \lib\AkActiveRecord\AkHasAndBelongsToMany.php line 868 AssetTag executing SQL: INSERT INTO assets_tags (asset_id, tag_id, created_at) VALUES (1,2,'2008-01-15 17:12:08')

    You can see the original DELETE of the old assets_tags association and the creation of the new one - this occurs when the setByIds() is called, which is what I expect. Then the UPDATE occurs with the save() call and from what I can gather the AkHasAndBelongsToMany _afterCallback() (traced at line 868) is called and does the 2nd insert.

    So I have 2 questions: 1) Why is there a 2nd INSERT ? (When I run the save action again I end up with 6 assocation rows... all the same) 2) Why bother including the 'id =1' and the created_at='2008-01-14 15:51:14' in the UPDATE as its just extra overhead and the values should never really change?

    Sorry for the long post !

    I have been developing with PHP for years now and I really like this framework. I have made some additions to the framework for myself, and would be very interested to start contributing back some of the updates and other thoughts.

    • I have augmented sinTags to generate the width / height tag for images dynamically from the image file itself (in dev mode only) using the php function getimagesize() <%= image_tag 'home/temp_jobs.gif' %>
      generates image_tag( 'home/temp_jobs.jpg', array( 'width' => 762, 'height' => 201 ) ); ?>
    • I have added a 'partiallayout' option to the AkActionController::render() function so that I can include global layouts within other layouts, similar to the way the default scaffolding works with _forms.tpl.

    I have made others, but thats just a start.

    I think I have said enough for now ... Thanks in advance !

    • CommentAuthorKaste
     

    well, thats a long post. so, you're welcome and dadada

    $habtm = array('Tags' => array('unique'=>true));
    

    should solve your problem. would like to hear/speak about your modifications but right now I'm in a hurry

    • CommentAuthorSport11
     

    Ah! After reading your answer, I took at look at the AkHasAndBelongsToMany API and did a search for unique. Sure enough, its the last option mentioned!

    I also had gone through http://wiki.akelos.org/how-to-implement-many-to-many-relationships a few times and unfortunately it doesn't mention anything about the unique option.

    Most instances I can think of would have the unique flag turned on. Any thoughts on making this the default ?

    Any thoughts or comments on my second question?

    • Why bother including the 'id =1' and the created_at='2008-01-14 15:51:14' in the UPDATE as its just extra overhead and the values should never really change?
    • CommentAuthorKaste
     

    Most instances I can think of would have the unique flag turned on.

    to be fair, right now, ähm, don't know when to set this to false.

    second thought/comment is a good one, but actually we always send all attributes to the database. so this is something I would like to see, but it's 'deep' in the ActiveRecord implementation. That means it isn't trivial to solve. (except we exclude just the id and created attribute, but hey, that's a hack ;-)

    • CommentAuthorKaste
     

    second thought on the second thought, just do it.

    can you upload the modified AkActiveRecord::collect to Trac?

    I dont get the partial layout-thing. why not just use render :partial?

    • CommentAuthorKaste
     

    and will you ticketize the unique-thing, please?