Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
17 / 17
SpaghettiCoupling
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
2 / 2
8
100.00% covered (success)
100.00%
17 / 17
 setFilterPath(Strategy\Search $strategy)
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 generateCoupledClassGraph()
100.00% covered (success)
100.00%
1 / 1
7
100.00% covered (success)
100.00%
15 / 15
<?php
/*
 * Mondrian
 */
namespace Trismegiste\Mondrian\Analysis;
use Trismegiste\Mondrian\Transform\Vertex\ImplVertex;
use Trismegiste\Mondrian\Transform\Vertex\MethodVertex;
use Trismegiste\Mondrian\Transform\Vertex\ClassVertex;
use Trismegiste\Mondrian\Transform\Vertex\InterfaceVertex;
use Trismegiste\Mondrian\Graph\Edge;
use Trismegiste\Mondrian\Graph\BreadthFirstSearch;
/**
 * SpaghettiCoupling is an analyser which finds coupling between classes,
 *
 * How ?
 * This analyser searches path between two classes through calls of public
 * methods, inheritance or instanciation.
 *
 * The language I used for representing source code into a digraph was
 * created especially to show that.
 *
 * Note 1 : This service creates a new digraph by selecting only the class
 * vertices because with the implementations, there are too many vertices.
 * The goal of the digraph is the "search for bridges". This is a concept
 * in graph theory where two highly connected graphs are linked by only one
 * edge. By cuting this edge (by adding an interface for example), you can
 * easily break your "monolith of code" into two pieces.
 *
 * Note 2 : since I only analyse public methods, I knowingly miss some
 * connections. I state that it is not an issue now. If there is a new
 * instance in a protected method, this an "inner refactoring" not a refactoring
 * of the structure of public implementations.
 *
 * In a second time, you can refactor this coupling later because you have
 * more freedom to change that : you are in a class, there is no coupling outside,
 * or perhaps it's ok (factory method pattern for example). Remember, the purpose
 * of this service is to help you to "break a monolith" you barely know,
 * not to replace your coding skills. There is no magic for that.
 *
 * There are more immportant issues with cycles of components for example.
 *
 */
class SpaghettiCoupling extends BreadthFirstSearch
{
    protected $strategy = null;
    /**
     * Set the strategy to reduce the graph by shortening a path between 2
     * components
     *
     * @param Strategy\Search $strategy
     */
    public function setFilterPath(Strategy\Search $strategy)
    {
        $this->strategy = $strategy;
    }
    /**
     * Generate a digraph reduced to all concrete coupled classes
     */
    public function generateCoupledClassGraph()
    {
        if (is_null($this->strategy)) {
            throw new \LogicException('No defined strategy');
        }
        $vSet = $this->graph->getVertexSet();
        foreach ($vSet as $src) {
            if ($src instanceof ClassVertex) {
                foreach ($vSet as $dst) {
                    if (($dst instanceof ClassVertex) && ($dst !== $src)) {
                        $this->resetVisited();
                        $path = $this->searchPath($src, $dst);
                        $this->strategy->collapseEdge($src, $dst, $path);
                    }
                }
            }
        }
    }
    /*
    private function generateCoupledClassGraph2()
    {
        $reducedGraph = new \Trismegiste\Mondrian\Graph\Digraph();
        $vSet = $this->graph->getVertexSet();
        $topo = new \Trismegiste\Mondrian\Graph\FloydWarshall($this->graph);
        $matrix = $topo->getDistance();
        foreach ($vSet as $line => $src) {
            if ($src instanceof ClassVertex) {
                foreach ($vSet as $column => $dst) {
                    if ($dst instanceof ClassVertex) {
                        if ($matrix->get($line, $column) > 0) {
                            $reducedGraph->addEdge($src, $dst);
                        }
                    }
                }
            }
        }
        return $reducedGraph;
    }*/
}