public function relative($action = 'index', $id = null, $child = null)
    {
        // Get the current path, adding a leading slash that should be missing
        $path = '/'.$this->path;

        // Get the URL up to and including the last controller.  If we're not linking
        // to a child, also remove the id, which may be replaced by a passed id
        $actions = implode('|', $this->actions);
        if ($child) {
            $pattern = '#(/('.$actions.'))?/?$#';
        } else {
            $pattern = '#(/\d+)?(/('.$actions.'))?/?$#';
        }
        $path = preg_replace($pattern, '', $path);

        // If there is an id and we're not linking to a child, add that id
        if (!$child && $id) {
            $path .= '/'.$id;
        }

        // If there is a child controller, add that now
        if ($child) {

            // If the child has a backslash, it's a namespaced class name, so convert to just name
            if (strpos($child, '\\') !== false) {
                $child = $this->slugController($child);
            }

            // If currently on an edit view (where we always respect child parameters literally),
            // or if the link is to an index view (for many to many to self) or if the child
            // is different than the current path, appened the child controller slug.
            if (preg_match('#edit$#', $this->path)
                || $action == 'index'
                || !preg_match('#'.$child.'(/\d+)?$#', $path)
                ) {
                $path .= '/'.$child;
            }

            // If the action was not index and there was an id, add it
            if ($action != 'index' && $id) {
                $path .= '/'.$id;
            }
        }

        // Now, add actions (except for index, which is implied by the lack of an action)
        if ($action && $action != 'index') {
            $path .= '/'.$action;
        }

        // Done, return it
        return $path;
    }