/**
  * Find the file for a class that in PSR-0 or PEAR would be in
  * $psr_0_root . '/' . $path_fragment . $path_suffix
  *
  * E.g.:
  *   - The class we look for is Some\Namespace\Some\Class
  *   - The file is actually in "exotic/location.php". This is not following
  *     PSR-0 or PEAR standard, so we need a plugin.
  *   -> The class finder will transform the class name to
  *     "Some/Namespace/Some/Class.php"
  *   - The plugin was registered for the namespace "Some\Namespace". This is
  *     because all those exotic classes all begin with Some\Namespace\
  *   -> The arguments will be:
  *     ($api = the API object, see below)
  *     $logical_base_path = "Some/Namespace/"
  *     $relative_path = "Some/Class.php"
  *     $api->getClass() gives the original class name, if we still need it.
  *   -> We are supposed to:
  *     if ($api->suggestFile('exotic/location.php')) {
  *       return TRUE;
  *     }
  *
  * @param InjectedApiInterface $api
  *   An object with a suggestFile() method.
  *   We are supposed to suggest files until suggestFile() returns TRUE, or we
  *   have no more suggestions.
  * @param string $logical_base_path_empty
  *   The key that this plugin was registered with.
  *   With trailing '/'.
  * @param string $relative_path_irrelevant
  *   Second part of the canonical path, ending with '.php'.
  *
  * @return bool|null
  *   TRUE, if the file was found.
  *   FALSE or NULL, otherwise.
  */
 function findFile($api, $logical_base_path_empty, $relative_path_irrelevant)
 {
     $q = db_select('registry');
     // Use LIKE here to make the query case-insensitive.
     $q->condition('name', db_like($api->getClass()), 'LIKE');
     $q->addField('registry', 'filename');
     $stmt = $q->execute();
     while ($relative_path = $stmt->fetchField()) {
         $file = $this->baseDir . $relative_path;
         // Attention: The db_select() above can trigger the class loader for
         // classes and interfaces of the database layer. This can cause some files
         // to be included twice, if the file defines more than one class.
         // So we need to use require_once here, instead of require. That is, use
         // guessFile() instead of claimFile().
         if ($api->guessFile($file)) {
             return TRUE;
         }
     }
     return FALSE;
 }
 /**
  * Looks up a class starting with "Drupal\$extension_name\\".
  *
  * This plugin method will be called for every class beginning with
  * "Drupal\\$extension_name\\", as long as the plugin is registered for
  * $logical_base_path = 'Drupal/$extension_name/'.
  *
  * A similar plugin will is registered along with this one for the PEAR-FLAT
  * pattern, called for every class beginning with $modulename . '_'.
  *
  * The plugin will eventually unregister itself and its cousin, once it has
  * - determined the correct path for the module, and
  * - determined that the module is using either PSR-0 or PSR-4.
  *   It does that by including the file candidate for PSR-0 and/or PSR-4 and
  *   checking whether the class is now defined.
  *
  * The plugin will instead register a direct
  *
  * @param \Drupal\xautoload\ClassFinder\InjectedApi\InjectedApiInterface $api
  *   An object with methods like suggestFile() and guessFile().
  * @param string $logical_base_path
  *   The logical base path determined from the registered namespace.
  *   E.g. 'Drupal/menupoly/'.
  * @param string $relative_path
  *   Remaining part of the logical path following $logical_base_path.
  *   E.g. 'FooNamespace/BarClass.php'.
  * @param string|null $extension_name
  *   Second key that the plugin was registered with. Usually this would be the
  *   physical base directory where we prepend the relative path to get the
  *   file path. But in this case it is simply the extensions name.
  *   E.g. 'menupoly'.
  *
  * @return bool|null
  *   TRUE, if the file was found.
  *   FALSE or NULL, otherwise.
  */
 function findFile($api, $logical_base_path, $relative_path, $extension_name = NULL)
 {
     $extension_file = $this->system->drupalGetFilename($this->type, $extension_name);
     if (empty($extension_file)) {
         // Extension does not exist, or is not installed.
         return FALSE;
     }
     $nspath = 'Drupal/' . $extension_name . '/';
     $testpath = $nspath . 'Tests/';
     $uspath = $extension_name . '/';
     $extension_dir = dirname($extension_file);
     $src = $extension_dir . '/src/';
     $lib_psr0 = $extension_dir . '/lib/Drupal/' . $extension_name . '/';
     $is_test_class = 0 === strpos($relative_path, 'Tests/');
     // Try PSR-4.
     if ($api->guessPath($src . $relative_path)) {
         if ($is_test_class) {
             // Register PSR-0 directory for "Drupal\\$modulename\\Tests\\"
             // This generally happens only once per module, because for subsequent
             // test classes the class will be found before this plugin is triggered.
             // However, for class_exists() with nonexistent test files, this line
             // will occur more than once.
             $this->namespaceMap->registerDeepPath($testpath, $src . 'Tests/', $this->defaultBehavior);
             // We found the class, but it is a test class, so it does not tell us
             // anything about whether non-test classes are in PSR-0 or PSR-4.
             return TRUE;
         }
         // Register PSR-4 directory for "Drupal\\$modulename\\".
         $this->namespaceMap->registerDeepPath($nspath, $src, $this->defaultBehavior);
         // Unregister the lazy plugins, including this one, for
         // "Drupal\\$modulename\\" and for $modulename . '_'.
         $this->namespaceMap->unregisterDeepPath($nspath, $extension_name);
         $this->prefixMap->unregisterDeepPath($uspath, $extension_name);
         // Test classes in PSR-4 are already covered by the PSR-4 plugin we just
         // registered. But test classes in PSR-0 would slip through. So we check
         // if a separate behavior needs to be registered for those.
         if (is_dir($lib_psr0 . 'Tests/')) {
             $this->namespaceMap->registerDeepPath($testpath, $lib_psr0 . 'Tests/', $this->psr0Behavior);
         }
         // The class was found, so return TRUE.
         return TRUE;
     }
     // Build PSR-0 relative path.
     if (FALSE === ($nspos = strrpos($relative_path, '/'))) {
         // No namespace separators in $relative_path, so all underscores must be
         // replaced.
         $relative_path = str_replace('_', '/', $relative_path);
     } else {
         // Replace only those underscores in $relative_path after the last
         // namespace separator, from right to left. On average there is no or very
         // few of them, so this loop rarely iterates even once.
         while ($nspos < ($uspos = strrpos($relative_path, '_'))) {
             $relative_path[$uspos] = '/';
         }
     }
     // Try PSR-0
     if ($api->guessPath($lib_psr0 . $relative_path)) {
         if ($is_test_class) {
             // We know now that there are test classes using PSR-0.
             $this->namespaceMap->registerDeepPath($testpath, $lib_psr0 . 'Tests/', $this->psr0Behavior);
             // We found the class, but it is a test class, so it does not tell us
             // anything about whether non-test classes are in PSR-0 or PSR-4.
             return TRUE;
         }
         // Unregister the lazy plugins, including this one.
         $this->namespaceMap->unregisterDeepPath($nspath, $extension_name);
         $this->prefixMap->unregisterDeepPath($uspath, $extension_name);
         // Register PSR-0 for regular namespaced classes.
         $this->namespaceMap->registerDeepPath($nspath, $lib_psr0, $this->psr0Behavior);
         // Test classes in PSR-0 are already covered by the PSR-0 plugin we just
         // registered. But test classes in PSR-4 would slip through. So we check
         // if a separate behavior needs to be registered for those.
         # if (is_dir($src . 'Tests/')) {
         #   $this->namespaceMap->registerDeepPath($testpath, $src . 'Tests/', $this->psr0Behavior);
         # }
         // The class was found, so return TRUE.
         return TRUE;
     }
     return FALSE;
 }
示例#3
0
 /**
  * Find the file for a class that in PSR-0 or PEAR would be in
  * $psr_0_root . '/' . $path_fragment . $path_suffix
  *
  * @param InjectedApiInterface $api
  * @param string $logical_path
  *   Class name translated into a logical path, either with PSR-4 or with PEAR
  *   translation rules.
  * @param int|bool $lastpos
  *   Position of the last directory separator in $logical_path.
  *   FALSE, if there is no directory separator in $logical_path.
  *
  * @return bool|NULL
  *   TRUE, if the class was found.
  */
 function apiFindFile($api, $logical_path, $lastpos)
 {
     $pos = $lastpos;
     while (TRUE) {
         $logical_base_path = FALSE === $pos ? '' : substr($logical_path, 0, $pos + 1);
         if (isset($this->paths[$logical_base_path])) {
             foreach ($this->paths[$logical_base_path] as $dir => $behavior) {
                 if ($behavior instanceof DefaultDirectoryBehavior) {
                     // PSR-4 and PEAR
                     if ($api->suggestFile($dir . substr($logical_path, $pos + 1))) {
                         return TRUE;
                     }
                 } elseif ($behavior instanceof Psr0DirectoryBehavior) {
                     // PSR-0
                     if ($api->suggestFile($dir . substr($logical_path, $pos + 1, $lastpos - $pos) . str_replace('_', '/', substr($logical_path, $lastpos + 1)))) {
                         return TRUE;
                     }
                 } elseif ($behavior instanceof xautoload_FinderPlugin_Interface) {
                     // Legacy "FinderPlugin".
                     if ($behavior->findFile($api, $logical_base_path, substr($logical_path, $pos + 1), $dir)) {
                         return TRUE;
                     }
                 }
             }
         }
         // Continue with parent fragment.
         if (FALSE === $pos) {
             return NULL;
         }
         $pos = strrpos($logical_base_path, '/', -2);
     }
     return NULL;
 }