src/phpDocumentor/Plugin/Twig/Writer/Twig.php
protected function getDestinationPath($node, Transformation $transformation)
    {
        $writer = $this;

        if (!$node) {
            throw new \UnexpectedValueException(
                'The transformation node in the twig writer is not expected to be false or null'
            );
        }

        if (!$transformation->getArtifact()) {
            $rule = $this->routers->match($node);
            if (!$rule) {
                throw new \InvalidArgumentException(
                    'No matching routing rule could be found for the given node, please provide an artifact location, '
                    . 'encountered: ' . ($node === null ? 'NULL' : get_class($node))
                );
            }

            $rule = new ForFileProxy($rule);
            $url  = $rule->generate($node);
            if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) {
                return false;
            }
            $path = $transformation->getTransformer()->getTarget() . str_replace('/', DIRECTORY_SEPARATOR, $url);
        } else {
            $path = $transformation->getTransformer()->getTarget()
                . DIRECTORY_SEPARATOR . $transformation->getArtifact();
        }

        $finder = new Pathfinder();
        $destination = preg_replace_callback(
            '/{{([^}]+)}}/', // explicitly do not use the unicode modifier; this breaks windows
            function ($query) use ($node, $writer, $finder) {
                // strip any surrounding \ or /
                $filepart = trim((string) current($finder->find($node, $query[1])), '\\/');

                // make it windows proof
                if (extension_loaded('iconv')) {
                    $filepart = iconv('UTF-8', 'ASCII//TRANSLIT', $filepart);
                }
                $filepart = strpos($filepart, '/') !== false
                    ? implode('/', array_map('urlencode', explode('/', $filepart)))
                    : implode('\\', array_map('urlencode', explode('\\', $filepart)));

                return $filepart;
            },
            $path
        );

        // replace any \ with the directory separator to be compatible with the
        // current filesystem and allow the next file_exists to do its work
        $destination = str_replace(array('/','\\'), DIRECTORY_SEPARATOR, $destination);

        // create directory if it does not exist yet
        if (!file_exists(dirname($destination))) {
            mkdir(dirname($destination), 0777, true);
        }

        return $destination;
    }
protected function getDestinationPath($node, Transformation $transformation)
    {
        $writer = $this;

        if (!$node) {
            throw new \UnexpectedValueException(
                'The transformation node in the twig writer is not expected to be false or null'
            );
        }

        if (!$transformation->getArtifact()) {
            $rule = $this->routers->match($node);
            if (!$rule) {
                throw new \InvalidArgumentException(
                    'No matching routing rule could be found for the given node, please provide an artifact location, '
                    . 'encountered: ' . ($node === null ? 'NULL' : get_class($node))
                );
            }

            $rule = new ForFileProxy($rule);
            $url  = $rule->generate($node);
            if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) {
                return false;
            }
            $path = $transformation->getTransformer()->getTarget() . str_replace('/', DIRECTORY_SEPARATOR, $url);
        } else {
            $path = $transformation->getTransformer()->getTarget()
                . DIRECTORY_SEPARATOR . $transformation->getArtifact();
        }

        $finder = new Pathfinder();
        $destination = preg_replace_callback(
            '/{{([^}]+)}}/', // explicitly do not use the unicode modifier; this breaks windows
            function ($query) use ($node, $writer, $finder) {
                // strip any surrounding \ or /
                $filepart = trim((string) current($finder->find($node, $query[1])), '\\/');

                // make it windows proof
                if (extension_loaded('iconv')) {
                    $filepart = iconv('UTF-8', 'ASCII//TRANSLIT', $filepart);
                }
                $filepart = strpos($filepart, '/') !== false
                    ? implode('/', array_map('urlencode', explode('/', $filepart)))
                    : implode('\\', array_map('urlencode', explode('\\', $filepart)));

                return $filepart;
            },
            $path
        );

        // replace any \ with the directory separator to be compatible with the
        // current filesystem and allow the next file_exists to do its work
        $destination = str_replace(array('/','\\'), DIRECTORY_SEPARATOR, $destination);

        // create directory if it does not exist yet
        if (!file_exists(dirname($destination))) {
            mkdir(dirname($destination), 0777, true);
        }

        return $destination;
    }
protected function getDestinationPath ( $ node , Transformation $ transformation ) { $ writer = $ this ; if ( ! $ node ) { throw new \ UnexpectedValueException ( 'The transformation node in the twig writer is not expected to be false or null' ) ; } if ( ! $ transformation -> getArtifact ( ) ) { $ rule = $ this -> routers -> match ( $ node ) ; if ( ! $ rule ) { throw new \ InvalidArgumentException ( 'No matching routing rule could be found for the given node, please provide an artifact location, ' . 'encountered: ' . ( $ node === null ? 'NULL' : get_class ( $ node ) ) ) ; } $ rule = new ForFileProxy ( $ rule ) ; $ url = $ rule -> generate ( $ node ) ; if ( $ url === false || $ url [ 0 ] !== DIRECTORY_SEPARATOR ) { return false ; } $ path = $ transformation -> getTransformer ( ) -> getTarget ( ) . str_replace ( '/' , DIRECTORY_SEPARATOR , $ url ) ; } else { $ path = $ transformation -> getTransformer ( ) -> getTarget ( ) . DIRECTORY_SEPARATOR . $ transformation -> getArtifact ( ) ; } $ finder = new Pathfinder ( ) ; $ destination = preg_replace_callback ( '/{{([^}]+)}}/' , // explicitly do not use the unicode modifier; this breaks windows function ( $ query ) use ( $ node , $ writer , $ finder ) { // strip any surrounding \ or / $ filepart = trim ( ( string ) current ( $ finder -> find ( $ node , $ query [ 1 ] ) ) , '\\/' ) ; // make it windows proof if ( extension_loaded ( 'iconv' ) ) { $ filepart = iconv ( 'UTF-8' , 'ASCII//TRANSLIT' , $ filepart ) ; } $ filepart = strpos ( $ filepart , '/' ) !== false ? implode ( '/' , array_map ( 'urlencode' , explode ( '/' , $ filepart ) ) ) : implode ( '\\' , array_map ( 'urlencode' , explode ( '\\' , $ filepart ) ) ) ; return $ filepart ; } , $ path ) ; // replace any \ with the directory separator to be compatible with the // current filesystem and allow the next file_exists to do its work $ destination = str_replace ( array ( '/' , '\\' ) , DIRECTORY_SEPARATOR , $ destination ) ; // create directory if it does not exist yet if ( ! file_exists ( dirname ( $ destination ) ) ) { mkdir ( dirname ( $ destination ) , 0777 , true ) ; } return $ destination ; }
Uses the currently selected node and transformation to assemble the destination path for the file.

The Twig writer accepts the use of a Query to be able to generate output for multiple objects using the same
template.

The given node is the result of such a query, or if no query given the selected element, and the transformation
contains the destination file.

Since it is important to be able to generate a unique name per element can the user provide a template variable
in the name of the file.
Such a template variable always resides between double braces and tries to take the node value of a given
query string.

Example:

An artifact stating `classes/{{name}}.html` will try to find the
node 'name' as a child of the given $node and use that value instead.

@param DescriptorAbstract $node
@param Transformation     $transformation

@throws \InvalidArgumentException if no artifact is provided and no routing rule matches.
@throws \UnexpectedValueException if the provided node does not contain anything.

@return string|false returns the destination location or false if generation should be aborted.
Uses the currently selected node and transformation to assemble the destination path for the file .