Search code examples
phpcakephpcakephp-2.3

CakePHP - problem with merging add and edit


I am trying to "merge" add and edit function so to speak, into one "save" function, which will, whether $id of the model is provided, update or add a new instance of the model. By starting to code this, I realised that this idea brings more complications than built in CakePHP add and edit methods, thing is, my mentor insists that I merge this so I shall try it, even if i personally think this is not the best approach.

ItemTypesController.php

class ItemTypesController extends AppController {
public function save($id = null) {
    if($this->request->is(array('post', 'put'))){
        $this->ItemType->set($this->request->data);
        //if i put an exit() funct here, it exits on this spot
        if($this->ItemType->validates()){
            if(!$id){
                $this->ItemType->create();
                if ($this->ItemType->save($this->request->data)) {
                    $this->Flash->success(__('The item type has been saved.'));
                    return $this->redirect(array('action' => 'index'));
                } else {
                    $this->Flash->error(__('The item type could not be saved. Please, try again.'));
                }
            }
            else{
                if ($this->ItemType->save($this->request->data)) {
                    $this->Flash->success(__('The item type has been saved.'));
                    return $this->redirect(array('action' => 'index'));
                } else {
                    $this->Flash->error(__('The item type could not be saved. Please, try again.'));
                }
            }
        } else {
            $this->Flash->warning($this->ItemType->validationErrors, array(
                'key' => 'negative'
            ));
        }

    } else {
        $options = array('conditions' => array('ItemType.' . $this->ItemType->primaryKey => $id));
        $this->request->data = $this->ItemType->find('first', $options);
    }
    $this->set('classes', $this->ItemType->classes);
}
}

So basically the function will enter if block if $id is not provided, which is the case if i enter a link for a new ItemType. And it works fine for create, but, when I try to update it it always requires that any field must be changed, because of "isUnique" rule, i set that rule to be only for create, but CakePHP prolly thinks of its create function, albeit here is used my save() funct and it probably thinks it needs to enter that rule for my funct.

ItemType.php

class ItemType extends AppModel {

public $classes = array(
    'product' => 'Proizvod',
    'kit' => 'Kit (bundle)'
);

public $validate = array(
    'code' => array(
        'required' => array(
            'rule' => 'notBlank',
            'message' => 'A code is required'
        ),
        'alphanum' => array(
            'rule' => 'alphanumeric',
            'message' => 'A code must be an alphanumeric value'
        ),
        'unique' => array(
            'rule' => 'isUnique',
            'message' => 'This code already exists!',
            'required' => 'create'
        ),
        'between' => array(
            'rule' => array('lengthBetween', 3, 7),
            'message' => 'Code must be between 3 and 7 characters long'
        )
    ),
    'name' => array(
        'required' => array(
            'rule' => 'notBlank',
            'message' => 'A name is required'
        ),
        'unique' => array(
            'rule' => 'isUnique',
            'message' => 'This name already exists!',
            'required' => 'create'
        ),
        'between' => array(
            'rule' => array('lengthBetween', 3, 30),
            'message' => 'Name must be between 3 and 30 characters long'
        )
    ),
    'class' => array(
        'valid' => array(
            'rule' => array('inList', array('product', 'material', 'kit', 'semi_product', 'service_product', 'service_supplier','consumable','inventory','goods','other')),
            'message' => 'Please enter a valid class',
            'allowEmpty' => false
        )
    ),
    'tangible' => array(
        'bool' => array(
            'rule' => 'boolean',
            'message' => 'Incorrect value for the checkbox'
        )
    ),
    'active' => array(
        'bool' => array(
            'rule' => 'boolean',
            'message' => 'Incorrect value for the checkbox'
        )
    )
    );

public $hasMany = array(
    'Item' => array(
        'className' => 'Item',
        'foreignKey' => 'item_type_id',
        'dependent' => false,
        'conditions' => '',
        'fields' => '',
        'order' => '',
        'limit' => '',
        'offset' => '',
        'exclusive' => '',
        'finderQuery' => '',
        'counterQuery' => ''
    )
);
}

This is the view from which I am entering a new one or updating one:

index.ctp

    <div class="itemTypes index">
    <h2><?php echo __('Item Types'); ?></h2>
    <table cellpadding="0" cellspacing="0">
    <thead>
    <tr>
            <th><?php echo $this->Paginator->sort('id'); ?></th>
            <th><?php echo $this->Paginator->sort('code'); ?></th>
            <th><?php echo $this->Paginator->sort('name'); ?></th>
            <th><?php echo $this->Paginator->sort('class'); ?></th>
            <th><?php echo $this->Paginator->sort('tangible'); ?></th>
            <th><?php echo $this->Paginator->sort('active'); ?></th>
            <th><?php echo $this->Paginator->sort('created'); ?></th>
            <th><?php echo $this->Paginator->sort('modified'); ?></th>
            <th class="actions"><?php echo __('Actions'); ?></th>
    </tr>
    </thead>
    <tbody>
    <?php foreach ($itemTypes as $itemType): ?>
    <tr>
        <td><?php echo h($itemType['ItemType']['id']); ?>&nbsp;</td>
        <td><?php echo h($itemType['ItemType']['code']); ?>&nbsp;</td>
        <td><?php echo h($itemType['ItemType']['name']); ?>&nbsp;</td>
        <td><?php echo h($itemType['ItemType']['class']); ?>&nbsp;</td>
        <td><?php if($itemType['ItemType']['tangible']) echo "Yes"; else echo "No" ?></td>
        <td><?php if($itemType['ItemType']['active']) echo "Yes"; else echo "No" ?></td>
        <td><?php echo h($itemType['ItemType']['created']); ?>&nbsp;</td>
        <td><?php echo h($itemType['ItemType']['modified']); ?>&nbsp;</td>
        <td class="actions">
            <?php echo $this->Html->link(__('View'), array('action' => 'view', $itemType['ItemType']['id'])); ?>
            <?php echo $this->Html->link(__('Edit'), array('action' => 'save', $itemType['ItemType']['id'])); ?>
            <?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $itemType['ItemType']['id']), array('confirm' => __('Are you sure you want to delete # %s?', $itemType['ItemType']['id']))); ?>
        </td>
    </tr>
    <?php endforeach; ?>
    </tbody>
    </table>
    <p>
        <?php
        echo $this->Paginator->counter(array(
        'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
    ));
    ?>  </p>
    <div class="paging">
    <?php
        echo $this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
        echo $this->Paginator->numbers(array('separator' => ''));
        echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
    ?>
    </div>
</div>

    <div class="actions">
            <h3><?php echo __('Actions'); ?></h3>
            <ul><li><?php echo $this->Html->link(__('New Item Type'), array('action' => 'save'));         ?>
</li>
</ul>
</div>

save.ctp

<div class="itemTypes form">
    <?php echo $this->Form->create('ItemType'); ?>
    <fieldset>
        <legend><?php echo __('Add Item Type'); ?></legend>
        <?php
        echo $this->Form->input('code');
        echo $this->Form->input('name');
        echo $this->Form->input('class', array('options' => $classes));
        echo $this->Form->input('tangible');
        echo $this->Form->input('active');
        ?>
    </fieldset>
    <?php echo $this->Form->end(__('Submit')); ?>
</div>

    <div class="actions"><h3><?php echo __('Actions'); ?></h3><ul><li><?php echo     $this->Html->link(__('List Item Types'), array('action' => 'index')); ?></li></ul></div>

Solution

  • Function save is not coded well, because id of the model was never set, so it did not knew whether it was updating or not.

    public function save($id = null) {
            if($this->request->is(array('post', 'put'))){
                if($id){
                    $this->request->data['ItemType']['id'] = $id;
                }
                $this->ItemType->set($this->request->data);
                if($this->ItemType->validates()){
                    if(!$id){
                        $this->ItemType->create();
                    }
                    if ($this->ItemType->save($this->request->data)) {
                        $this->Flash->success(__('The item type has been saved.'));
                        return $this->redirect(array('action' => 'index'));
                    } else {
                        $this->Flash->error(__('The item type could not be saved. Please, try again.'));
                    }
                } else {
                    $this->Flash->warning($this->ItemType->validationErrors, array(
                        'key' => 'negative'
                    ));
                }
    
            } else {
                $options = array('conditions' => array('ItemType.' . $this->ItemType->primaryKey => $id));
                $this->request->data = $this->ItemType->find('first', $options);
            }
            $this->set('classes', $this->ItemType->classes);}
    

    Now, this is how function should look.