5
\$\begingroup\$

Building complex applications can sometimes be a pain when extending or editing later on; I read online about the S.O.L.I.D principles of OOD, I want to understand if I am following a good approach that I can follow when developing the rest of the app.

I need answers to the following questions

  1. Is the code well-documented?
  2. The use of namespaces, Was it necessary ?
  3. Does the class violates any of the SOLID principles ?
  4. $ic = new static; Is it wrong to use this approach for inline usage?
  5. Using static methods for easy access in a single line of code to creating and getting taxonomies, Are there better ideas ?
  6. App\Taxonomy::register("categories")->isHierarchical()->produce() The usage, Is it developer friendly to you ? Or are there other approaches developers would rather ?

Some of the ideas I had in mind when writing down the Class:

  1. I used namespaces because the project will have many classes and sub packages that would need categorizing for better usage by developers when they develop mini apps (plugins).
  2. I used static methods for single line usage to make it easier for developers to register new taxonomies and set options into one line of code.

Here is the class

namespace App;

/**
 * Class Taxonomy
 *
 * @package App
 */

class Taxonomy {

    /**
     * Store all the taxonomies
     *
     * @since 0.5
     *
     * @var array
     */
    protected static $taxonomies = array();

    /**
     * Default settings for creating taxonomies
     *
     * @since 0.5
     *
     * @var array
     */
    protected static $tax_defaults = array(
        'key' => null,
        'hierarchical' => false
    );

    /**
     * A Temporary variable that holds the taxonomy
     * settings until the taxonomy is being produced
     * then the temporary variable is being reset
     * to an empty array
     *
     * @since 0.5
     *
     * @var array
     */
    protected static $tax = array();

    /**
     * Temporarily holds an error because
     * in some cases errors occurs when for example
     * using a duplicate taxonomy key
     *
     * @since 0.5
     *
     * @var bool
     */
    protected static $error = false;

    /**
     * Register a new taxonomy to be later on
     * added to a data set
     *
     * @since 0.5
     *
     * @param $taxonomy_key String Unique key used for the taxonomy as an identifier
     * @return static
     */
    public static function register( $taxonomy_key ){
        $ic = new static;
        self::reset();

        if( isset( self::$taxonomies[ $taxonomy_key ] ) )
            self::$error = "taxonomy-already-registered";

        self::$tax = self::$tax_defaults;
        self::$tax['key'] = $taxonomy_key;

        return $ic;
    }

    /**
     * Set the taxonomy to hierarchical
     *
     * @since 0.5
     *
     * @return static
     */
    static function isHierarchical(){
        $ic = new static;
        self::$tax['hierarchical'] = true;
        return $ic;
    }

    /**
     * Final step, This method is used to store
     * the taxonomy to App global taxonomies variable
     *
     * @since 0.5
     *
     * @return bool
     */
    static function produce(){
        if( self::$error !== false )
            return self::$error;

        $key = self::$tax['key'];
        self::$taxonomies[$key] = self::$tax;
        self::reset();
    }

    /**
     * Return the object of the Taxonomy
     *
     * @since 0.5
     *
     * @param $taxonomy_key
     * @return bool
     */
    static function get( $taxonomy_key ){
        return isset( self::$taxonomies[$taxonomy_key] ) ? self::$taxonomies[$taxonomy_key] : false;
    }

    /**
     * Reset temporary variables
     *
     * @since 0.5
     */
    protected static function reset(){
        self::$tax = array();
    }
}

Usage example

// Register Taxonomies
App\Taxonomy::register("categories")->isHierarchical()->produce();
App\Taxonomy::register("tags")->produce();

// Get Taxonomies
App\Taxonomy::get("tags"); // Will return an array of the information registered
\$\endgroup\$
5
\$\begingroup\$

I think you're mixing too many ideas here and as a consequence your class ends up having too many responsibilities, which than need extensive documentation because their behaviour may not be obvious and self explanatory.

Try to keep things just as simple as possible. In your case a simple plain old PHP object would potentially do the job.

Take for example the following entity class, which is basically the core of your code, all the rest of your functions are just creational util function.

class Taxonomy
{
    private $name;
    private $isHierarchical;

    public function __construct($name, $isHierarchical = false)
    {
        $this->name           = $name;
        $this->isHierarchical = $isHierarchical;
    }

    public function getName()
    {
        return $this->name;
    }

    public function isHierarchical()
    {
        return $this->isHierarchical;
    }
}

Because the code is that simple and self explanatory I don't even need to add any comment. Generally it's preferable to have clear and readable code over extensive documentation ...

That little extra bit of logic to have unique taxonomy names within an array of taxonomies could be archived by using for example a TaxonomyCollection object which takes care of that.

E.g.

class TaxonomyCollection
{
    private $taxonomies = [];

    public function __construct(array $taxonomies)
    {
        array_walk($taxonomies, function($taxonomy) {
            $this->addTaxonomy($taxonomy);
        });
    }

    public function addTaxonomy(Taxonomy $taxonomy)
    {
        if ($this->getTaxonomyByName($taxonomy->getName())) {
            throw new \RuntimeException(
                sprintf(
                    'Taxonomy name "%s" not unique within the collection.',
                    $taxonomy->getName()
                )
            );
        }

        array_push($this->taxonomies, $taxonomy);
    }

    public function getTaxonomies()
    {
        return $this->taxonomies;
    }

    public function getTaxonomyByName($taxonomyName)
    {
        foreach($this->taxonomies as $taxonomy) {
            if ($taxonomyName === $taxonomy->getName()) {
                return $taxonomy;
            }
        }
        return null;
    }
}

Example usage:

new TaxonomyCollection([
    new Taxonomy('foo', true),
    new Taxonomy('bar'),
]);

Now if you like to have a more convenient way for creating objects have a look on the factory pattern for example, but don't pollute your entities with endless boilerplate.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.