1<?php
2/**
3 * This file is part of the static reflection component.
4 *
5 * PHP Version 5
6 *
7 * Copyright (c) 2009-2011, Manuel Pichler <mapi@pdepend.org>.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 *   * Redistributions of source code must retain the above copyright
15 *     notice, this list of conditions and the following disclaimer.
16 *
17 *   * Redistributions in binary form must reproduce the above copyright
18 *     notice, this list of conditions and the following disclaimer in
19 *     the documentation and/or other materials provided with the
20 *     distribution.
21 *
22 *   * Neither the name of Manuel Pichler nor the names of his
23 *     contributors may be used to endorse or promote products derived
24 *     from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 *
39 * @category  PHP
40 * @package   pdepend\reflection\queries
41 * @author    Manuel Pichler <mapi@pdepend.org>
42 * @copyright 2009-2011 Manuel Pichler. All rights reserved.
43 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
44 * @version   SVN: $Id$
45 * @link      http://pdepend.org/
46 */
47
48namespace pdepend\reflection\queries;
49
50/**
51 * This query class allows access to reflection class instances for all classes
52 * and interfaces declared in a given directory.
53 *
54 * <code>
55 * $query   = $session->createDirectoryQuery();
56 * $classes = $query->find( __DIR__ . '/source' );
57 *
58 * foreach ( $classes as $class )
59 * {
60 *     echo 'Class: ', $class->getShortName(), PHP_EOL,
61 *          'File:  ', $class->getFileName(), PHP_EOL,
62 *          '-- ', PHP_EOL;
63 * }
64 * </code>
65 *
66 * @category  PHP
67 * @package   pdepend\reflection\queries
68 * @author    Manuel Pichler <mapi@pdepend.org>
69 * @copyright 2009-2011 Manuel Pichler. All rights reserved.
70 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
71 * @version   Release: @package_version@
72 * @link      http://pdepend.org/
73 */
74class ReflectionDirectoryQuery extends ReflectionQuery
75{
76    /**
77     * The type of this class.
78     */
79    const TYPE = __CLASS__;
80
81    /**
82     * Array with regular expressions used to exclude some files.
83     *
84     * @var array(string)
85     */
86    private $_excludes = array( '([/\\\\]\.)' );
87
88    /**
89     * This method will create reflection class instances for all interfaces
90     * and classes that can be found in the source code files within the given
91     * directory.
92     *
93     * @param string $directory The source directory that is the target of the
94     *        class search.
95     *
96     * @return Iterator
97     */
98    public function find( $directory )
99    {
100        if ( file_exists( $directory ) === false || is_file( $directory ) )
101        {
102            throw new \LogicException( 'Invalid or not existant directory ' . $directory );
103        }
104
105        $classes = array();
106        foreach ( $this->_createIterator( $directory ) as $fileInfo )
107        {
108            if ( !$fileInfo->isFile() || $this->_isExcluded( $fileInfo, $directory ) )
109            {
110                continue;
111            }
112            foreach ( $this->parseFile( $fileInfo->getRealpath() ) as $class )
113            {
114                $classes[] = $class;
115            }
116        }
117        return new \ArrayIterator( $classes );
118    }
119
120    /**
121     * Adds a regular expected that will be used to filter out those files that
122     * should no be parsed.
123     *
124     * @param string $regexp A regular expression used to filter the result.
125     *
126     * @return \pdepend\reflection\queries\ReflectionDirectoryQuery
127     */
128    public function exclude( $regexp )
129    {
130        $this->_excludes[] = $regexp;
131        return $this;
132    }
133
134    /**
135     * This method returns a iterator with all files that could be found within
136     * the given source directory.
137     *
138     * @param string $directory The source directory that is the target of the
139     *        class search.
140     *
141     * @return Iterator
142     */
143    private function _createIterator( $directory )
144    {
145        return new \RecursiveIteratorIterator(
146            new \RecursiveDirectoryIterator( $directory )
147        );
148    }
149
150    /**
151     * Will return <b>true</b> when the given file object should not be
152     * accepted.
153     *
154     * @param \SplFileInfo $fileInfo  The currently parsed file info object.
155     * @param string       $directory The context directory.
156     *
157     * @return boolean
158     */
159    private function _isExcluded( \SplFileInfo $fileInfo, $directory )
160    {
161        $pathName = substr( $fileInfo->getRealPath(), strlen( realpath( $directory ) ) );
162        foreach ( $this->_excludes as $regexp )
163        {
164            if ( preg_match( $regexp, $pathName ) > 0 )
165            {
166                return true;
167            }
168        }
169        return false;
170    }
171}
172