1

I have an action in my controller called createAction. I also have a model My_Application_Product, that I'm using to create the product within the system. I'm following the Architecting Your Models talk. Is this the "correct" way to save my product? Code for My_Application_Product follows below.

class ProductController  extends Zend_Controller_Action {
    public function createAction() {
        $categoryAdapter = new Application_Model_Categories();
        $categories = $categoryAdapter->fetchAll('parent_id IS NOT NULL');

        $form = new My_Application_Forms_Product_Create();
        $category = $form->getElement('category');

        foreach ($categories as $cat) {
            $category->addMultiOption($cat->id, $cat->name);
        }

        if ($this->getRequest()->isPost()) {
            if (! $form->isValid($_POST)) {
                $this->view->form = $form;
                return $this->render('create');
            }

            $product = new My_Application_Product();
            $product->name = $_POST['name'];
            $product->company_id = 1;
            $product->category_id = $_POST['category'];
            $product->trade_names = $_POST['trade_names'];
            $product->website = $_POST['website'];
            $product->description = $_POST['description'];
            $product->closed_loop = $_POST['closed_loop'];
            $product->sold_as = $_POST['sold_as'];
            $product->sold_in = $_POST['sold_in'];
            $product->dilution = $_POST['dilution'];
            $id = $product->save();

            $url = $this->getHelper('Url')
                        ->url(array('action' => 'registryservices', 'id' => $id));

            $this->_redirect($url);
        }

        $this->view->form = $form;
    }
}

'

class My_Application_Product implements My_Application_Product_Interface {
    // declare all the internally used variables here.
    // if something isn't showing up when trying to save, that's probably
    // because it's missing from here
    protected $_id;
    protected $_name;
    protected $_company_id;
    protected $_trade_names;
    protected $_website;
    protected $_description;
    protected $_closed_loop;
    protected $_sold_as;
    protected $_sold_in;
    protected $_dilution;
    protected $_category_id;
    protected $_verification_level;
    protected $_dfe_sccp;
    protected $_dfe_siicp;
    protected $_el_ccd_hsc;

    public function __set($name, $value) {
        $local_var_name = "_" . $name;
        if (property_exists($this, $local_var_name)) {
            $this->{$local_var_name} = $value;
        }
    }

    public function __get($name) {
        $local_var_name = "_" . $name;
        if (property_exists($this, $local_var_name)) {
            return $this->{$local_var_name};
        }
    }

    /**
     *
     * @param array $data The data to save
     */
    public function save() {
        // this means we're editing something
        if ($this->id) {
            $table = new My_Application_Product_Table();
            $data = $table->find($this->id)->toArray();
            $data = $data[0];

            foreach (get_class_vars(get_class($this)) as $key => $value) {
                if (! is_null($this->$key)) {
                    $data[preg_replace('/^_/', '', $key)] = $this->$key;
                }
            }
            $id = $table->update($data, sprintf('id = %d', $this->id));
        // this means we're creating, and this is the data we need
        } else {
            $data = array(
                'id' => rand(1,1000000),
                'name' => $this->name,
                'date_created' => date('Y-m-d H:i:s'),
            );
            $id = $table->insert($data);
        }

        return $id;
    }
}

'

class My_Application_Product_Table extends Zend_Db_Table_Abstract {
    protected $_name = 'products';
    protected $_primary = 'id';
}
5
  • 1
    Are you looking for a code review? Commented Jul 12, 2011 at 14:27
  • Use this, $values = $form->getValues();, instead of $_POST, filters may be involved or you're circumventing possible future code. Commented Jul 12, 2011 at 14:29
  • Minor item: I'd probably push the categories/multioptions business down into the form itself. Make the $categories array a constructor argument for the form and then in init(), use the categories to add the multioptions. Leans out the controller by a few lines. Commented Jul 12, 2011 at 15:10
  • @brady.vitrano I wouldn't mind, but I'm looking more for suggestions of how to do it more in the MVC style. Commented Jul 12, 2011 at 15:14
  • Maybe it's just me but I think MVC is too big of a topic to discuss with just a few code snippets. Overall I will say, though, you are heading into the right direction. Commented Jul 12, 2011 at 16:45

1 Answer 1

1

Split your model in multiple classes :

  • 1 class representing the entity (no methods, except for accessors).

this class represents your "real-life" object, and is just a structured data container, which encapsulates data

class My_Application_Model_Product {

    protected $_id;
    protected $_name;
    protected $_company_id;
    protected $_trade_names;
    protected $_website;

    //...

    public function __set($name, $value) {
    //Implement your setter here
    }


    public function __get($name) {

    }

}
  • 1 class responsible of data mapping.

This class makes is the link between your data source (database, webservice, file...) and your entity.

 Class My_Application_Model_DataMapper_Product {

     protected $_adapter


     public function __construct($adapter)
     {
       $this->setAdapter($adapter);
     }
     public function setAdapter($adapter)
     {
       $this->_adapter = $adapter;
     }
     public function save(My_Application_Model_Product $product)
     {
       //Perform your save operation here
     }
     public function fetchAll()
     {

     }
     public function findById($id)
     {
     }
      //You may implement specific methods for any needed specific operation (search, bulk-update...
 }
  • a third class for data access and persistence (Zend_Db_table, Soap client...) This third class is passed to the datamapper as the adapter and is used inside the methods to getch/save data.

With this architecture, you have a clear separation of responsibilities, and may change one part without affecting the other : for example, you could switch from a database to a webservice without affecting your Product class.

A very simple example is given in the zf Quickstart

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.