Jump to content

OOP Calling one class from within another


tgavin
Go to solution Solved by ignace,

Recommended Posts

I have a class for building forms and I want to upgrade it to handle Bootstrap. I'd like to use my current methods to build the Bootstrap elements, but I don't want all of this new Bootstrap code cluttering up my current Forms class, so I'd like to put it into its own class in a separate file.

 

Below is a very simple example of what I'm trying to do. Obviously this doesn't work and the code is wrong, however, from this you can hopefully see what I'm trying to accomplish.



<?php

class Forms {
    public function input_text($name) {
        return '<input type="text" name="'.$name.'">';
    }
}

class Bootstrap {
    public function bootstrap_input_text($name) {
        $return  = '<div class="control-group">';
        $return .= '<label class="control-label" for="'.$name.'">First name</label>';
        $return .= '<div class="controls">';
        $return .= $this->Forms->input_text($name);
        $return .= '</div>';
        $return .= '</div>';
return $return;
    }
}

$form = new Forms();
echo $form->bootstrap_input_text('fname');

Link to comment
Share on other sites

class Bootstrap extends Forms{
    public function bootstrap_input_text($name) {
        $return  = '<div class="control-group">';
        $return .= '<label class="control-label" for="'.$name.'">First name</label>';
        $return .= '<div class="controls">';
        $return .= $this->input_text($name);
        $return .= '</div>';
        $return .= '</div>';
        return $return;
    }
}

$bs = new Bootstrap();
echo $bs->bootstrap_input_text('fname');

You can even redefine input_text() in the Boostrap class, but here you wouldn't want to.

Link to comment
Share on other sites

You know, 'Bootstrap extends Forms' is pretty much the first thing I tried, but I didn't want to create a new $bs object, because I wanted to keep it simple and use the $form object for everything. I know it's only the difference in typing $form-> vs. $bs->, but it's easy to forget when you're on a roll. :)

 

So, if I don't want to create a new object, is my only option to put all of the bootstrap methods in the Forms class?

 

Thanks!

Link to comment
Share on other sites

I'm not a hardcore OOP guy that uses interfaces, abstract classes and all the other stuff, so maybe someone else can chime in, but maybe something like this.  I'm probably breaking all kinds of OOP / design pattern rules, but oh well:

class Forms {
    public function bootstrap() {
        if(!is_object($this->bootstrap)) {
            $this->bootstrap = new Bootstrap;
            return $this->bootstrap;
        }
    }
}
$form = new Forms;
$form->bootstrap()->bootstrap_input_text('fname');

The other thing I thought of if you will extend this more with other classes is to use __call() in Forms and have it instantiate the proper class and call the method.  Not sure if I'm sending you down the wrong path or not.

Link to comment
Share on other sites

Use dependency injection and delegate:

 

class Forms
{
    private $bootstrap;

    public function __construct($bootstrap)
    {
        $this->bootstrap = $bootstrap;
    }

    public function input_text($name)
    {
        return $this->bootstrap->bootstrap_input_text($name);
    }
}
Link to comment
Share on other sites

Kevin already mentioned it, you need delegation, more particular, the Decorator pattern.

 

interface FormInterface {
  public function input($value, $type = 'text');
}

abstract class FormDecorator implements FormInterface {
  protected $form;
  
  public function __construct(FormInterface $form) {
    $this->form = $form;
  }
}

class BootstrapFormDecorator extends FormDecorator {
  public function input($value, $type = 'text') {
    return '<bootstrap-here>' . $this->form->input($value, $type) . '</bootstrap-here>';
  }
}

class Form implements FormInterface {
  public function input($value, $type = 'text') {
    return "<input type=\"$type\" value=\"$value\">";
  }
}
$form = new BootstrapFormDecorator(new Form);

echo $form->input('foo');
Edited by ignace
Link to comment
Share on other sites

Thanks for your help guys. Before I try any of this, I'm thinking: what about just doing the following

 

class Forms extends Bootstrap {

     ....

}

 

Seems simple enough, and works! Would there be any problems with this?

Link to comment
Share on other sites

  • Solution

The problem with that is that you will have to re-write your form every time you change framework.

 

Your form never changes, an input remains an input so you should be able to re-use that code and decorate your form with the bootstrap css framework.

 

The added benefit is that the interface you "talk" to is the same regardless wether you are using a plain form or a bootstrap form. Allowing you to even re-use your existing forms and changing them is as easy as:

 

function get_form() {
  return new BootstrapForm(new SimpleForm);
}
to

 

function get_form() {
  return new BlueprintForm(new SimpleForm);
}
And now all your existing forms on your website have been changed from bootstrap to blueprint. You can even go crazy and do something like:

 

function get_form() {
  return new BootstrapForm(new BlueprintForm(new SimpleForm));
}
If you are concerned about not enough flexibility you can always extend the FormInterface:

 

interface FormInterface {
  public function input($name, $value, $type = 'text', $id = null, array $attrs = array());
  public function textInput($name, $value, $id = null, array $attrs = array());
  public function radioInput($name, $onOrOff = false, $id = null, array $attrs = array());
  ..
  public function dropDown($name, array $options, $id = null, array $attrs = array());
  ..
}
Also take a look at

- http://framework.zend.com/manual/2.2/en/modules/zend.form.intro.html

- and http://symfony.com/doc/current/book/forms.html

Edited by ignace
Link to comment
Share on other sites

I'm digging into this and am getting a better understanding of how this works - thank you guys for pointing it out to me - I can totally see the value of this!

 

I'm curious though about the FormInterface... class? interface?

 

What does that do? I can build my forms with all of the arguments right inside the Form class, so why are those additional methods set inside FormInterface?

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.