PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file IncludeSystemSniff.php

Documentation is available at IncludeSystemSniff.php

  1. <?php
  2. /**
  3.  * Ensures that systems, asset types and libs are included before they are used.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Channels;
  11.  
  12. use PHP_CodeSniffer\Sniffs\AbstractScopeSniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class IncludeSystemSniff extends AbstractScopeSniff
  17. {
  18.  
  19.     /**
  20.      * A list of classes that don't need to be included.
  21.      *
  22.      * @var string[] 
  23.      */
  24.     private $ignore = array(
  25.                        'self'                      => true,
  26.                        'static'                    => true,
  27.                        'parent'                    => true,
  28.                        'channels'                  => true,
  29.                        'basesystem'                => true,
  30.                        'dal'                       => true,
  31.                        'init'                      => true,
  32.                        'pdo'                       => true,
  33.                        'util'                      => true,
  34.                        'ziparchive'                => true,
  35.                        'phpunit_framework_assert'  => true,
  36.                        'abstractmysourceunittest'  => true,
  37.                        'abstractdatacleanunittest' => true,
  38.                        'exception'                 => true,
  39.                        'abstractwidgetwidgettype'  => true,
  40.                        'domdocument'               => true,
  41.                       );
  42.  
  43.  
  44.     /**
  45.      * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff.
  46.      */
  47.     public function __construct()
  48.     {
  49.         parent::__construct(array(T_FUNCTION)array(T_DOUBLE_COLONT_EXTENDS)true);
  50.  
  51.     }//end __construct()
  52.  
  53.  
  54.     /**
  55.      * Processes the function tokens within the class.
  56.      *
  57.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
  58.      * @param integer                     $stackPtr  The position where the token was found.
  59.      * @param integer                     $currScope The current scope opener token.
  60.      *
  61.      * @return void 
  62.      */
  63.     protected function processTokenWithinScope(File $phpcsFile$stackPtr$currScope)
  64.     {
  65.         $tokens $phpcsFile->getTokens();
  66.  
  67.         // Determine the name of the class that the static function
  68.         // is being called on.
  69.         $classNameToken $phpcsFile->findPrevious(
  70.             T_WHITESPACE,
  71.             ($stackPtr - 1),
  72.             null,
  73.             true
  74.         );
  75.  
  76.         // Don't process class names represented by variables as this can be
  77.         // an inexact science.
  78.         if ($tokens[$classNameToken]['code'=== T_VARIABLE{
  79.             return;
  80.         }
  81.  
  82.         $className $tokens[$classNameToken]['content'];
  83.         if (isset($this->ignore[strtolower($className)]=== true{
  84.             return;
  85.         }
  86.  
  87.         $includedClasses = array();
  88.  
  89.         $fileName strtolower($phpcsFile->getFilename());
  90.         $matches  = array();
  91.         if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|'$fileName$matches!== 0{
  92.             // This is an actions file, which means we don't
  93.             // have to include the system in which it exists.
  94.             $includedClasses[$matches[2]] = true;
  95.  
  96.             // Or a system it implements.
  97.             $class      $phpcsFile->getCondition($stackPtrT_CLASS);
  98.             $implements $phpcsFile->findNext(T_IMPLEMENTS$class($class + 10));
  99.             if ($implements !== false{
  100.                 $implementsClass     $phpcsFile->findNext(T_STRING$implements);
  101.                 $implementsClassName strtolower($tokens[$implementsClass]['content']);
  102.                 if (substr($implementsClassName-7=== 'actions'{
  103.                     $includedClasses[substr($implementsClassName0-7)= true;
  104.                 }
  105.             }
  106.         }
  107.  
  108.         // Go searching for includeSystem and includeAsset calls within this
  109.         // function, or the inclusion of .inc files, which
  110.         // would be library files.
  111.         for ($i ($currScope + 1)$i $stackPtr$i++{
  112.             $name $this->getIncludedClassFromToken($phpcsFile$tokens$i);
  113.             if ($name !== false{
  114.                 $includedClasses[$name= true;
  115.                 // Special case for Widgets cause they are, well, special.
  116.             else if (strtolower($tokens[$i]['content']=== 'includewidget'{
  117.                 $typeName $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING($i + 1));
  118.                 $typeName trim($tokens[$typeName]['content']" '");
  119.                 $includedClasses[strtolower($typeName).'widgettype'= true;
  120.             }
  121.         }
  122.  
  123.         // Now go searching for includeSystem, includeAsset or require/include
  124.         // calls outside our scope. If we are in a class, look outside the
  125.         // class. If we are not, look outside the function.
  126.         $condPtr $currScope;
  127.         if ($phpcsFile->hasCondition($stackPtrT_CLASS=== true{
  128.             foreach ($tokens[$stackPtr]['conditions'as $condPtr => $condType{
  129.                 if ($condType === T_CLASS{
  130.                     break;
  131.                 }
  132.             }
  133.         }
  134.  
  135.         for ($i = 0; $i $condPtr$i++{
  136.             // Skip other scopes.
  137.             if (isset($tokens[$i]['scope_closer']=== true{
  138.                 $i $tokens[$i]['scope_closer'];
  139.                 continue;
  140.             }
  141.  
  142.             $name $this->getIncludedClassFromToken($phpcsFile$tokens$i);
  143.             if ($name !== false{
  144.                 $includedClasses[$name= true;
  145.             }
  146.         }
  147.  
  148.         // If we are in a testing class, we might have also included
  149.         // some systems and classes in our setUp() method.
  150.         $setupFunction = null;
  151.         if ($phpcsFile->hasCondition($stackPtrT_CLASS=== true{
  152.             foreach ($tokens[$stackPtr]['conditions'as $condPtr => $condType{
  153.                 if ($condType === T_CLASS{
  154.                     // Is this is a testing class?
  155.                     $name $phpcsFile->findNext(T_STRING$condPtr);
  156.                     $name $tokens[$name]['content'];
  157.                     if (substr($name-8=== 'UnitTest'{
  158.                         // Look for a method called setUp().
  159.                         $end      $tokens[$condPtr]['scope_closer'];
  160.                         $function $phpcsFile->findNext(T_FUNCTION($condPtr + 1)$end);
  161.                         while ($function !== false{
  162.                             $name $phpcsFile->findNext(T_STRING$function);
  163.                             if ($tokens[$name]['content'=== 'setUp'{
  164.                                 $setupFunction $function;
  165.                                 break;
  166.                             }
  167.  
  168.                             $function $phpcsFile->findNext(T_FUNCTION($function + 1)$end);
  169.                         }
  170.                     }
  171.                 }
  172.             }//end foreach
  173.         }//end if
  174.  
  175.         if ($setupFunction !== null{
  176.             $start ($tokens[$setupFunction]['scope_opener'+ 1);
  177.             $end   $tokens[$setupFunction]['scope_closer'];
  178.             for ($i $start$i $end$i++{
  179.                 $name $this->getIncludedClassFromToken($phpcsFile$tokens$i);
  180.                 if ($name !== false{
  181.                     $includedClasses[$name= true;
  182.                 }
  183.             }
  184.         }//end if
  185.  
  186.         if (isset($includedClasses[strtolower($className)]=== false{
  187.             $error 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once';
  188.             $data  = array($className);
  189.             $phpcsFile->addError($error$stackPtr'NotIncludedCall'$data);
  190.         }
  191.  
  192.     }//end processTokenWithinScope()
  193.  
  194.  
  195.     /**
  196.      * Processes a token within the scope that this test is listening to.
  197.      *
  198.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where the token was found.
  199.      * @param int                         $stackPtr  The position in the stack where
  200.      *                                                this token was found.
  201.      *
  202.      * @return void 
  203.      */
  204.     protected function processTokenOutsideScope(File $phpcsFile$stackPtr)
  205.     {
  206.         $tokens $phpcsFile->getTokens();
  207.  
  208.         if ($tokens[$stackPtr]['code'=== T_EXTENDS{
  209.             // Find the class name.
  210.             $classNameToken $phpcsFile->findNext(T_STRING($stackPtr + 1));
  211.             $className      $tokens[$classNameToken]['content'];
  212.         else {
  213.             // Determine the name of the class that the static function
  214.             // is being called on. But don't process class names represented by
  215.             // variables as this can be an inexact science.
  216.             $classNameToken $phpcsFile->findPrevious(T_WHITESPACE($stackPtr - 1)nulltrue);
  217.             if ($tokens[$classNameToken]['code'=== T_VARIABLE{
  218.                 return;
  219.             }
  220.  
  221.             $className $tokens[$classNameToken]['content'];
  222.         }
  223.  
  224.         // Some systems are always available.
  225.         if (isset($this->ignore[strtolower($className)]=== true{
  226.             return;
  227.         }
  228.  
  229.         $includedClasses = array();
  230.  
  231.         $fileName strtolower($phpcsFile->getFilename());
  232.         $matches  = array();
  233.         if (preg_match('|/systems/([^/]+)/([^/]+)?actions.inc$|'$fileName$matches!== 0{
  234.             // This is an actions file, which means we don't
  235.             // have to include the system in which it exists
  236.             // We know the system from the path.
  237.             $includedClasses[$matches[1]] = true;
  238.         }
  239.  
  240.         // Go searching for includeSystem, includeAsset or require/include
  241.         // calls outside our scope.
  242.         for ($i = 0; $i $stackPtr$i++{
  243.             // Skip classes and functions as will we never get
  244.             // into their scopes when including this file, although
  245.             // we have a chance of getting into IF's, WHILE's etc.
  246.             if (($tokens[$i]['code'=== T_CLASS
  247.                 || $tokens[$i]['code'=== T_INTERFACE
  248.                 || $tokens[$i]['code'=== T_FUNCTION)
  249.                 && isset($tokens[$i]['scope_closer']=== true
  250.             {
  251.                 $i $tokens[$i]['scope_closer'];
  252.                 continue;
  253.             }
  254.  
  255.             $name $this->getIncludedClassFromToken($phpcsFile$tokens$i);
  256.             if ($name !== false{
  257.                 $includedClasses[$name= true;
  258.                 // Special case for Widgets cause they are, well, special.
  259.             else if (strtolower($tokens[$i]['content']=== 'includewidget'{
  260.                 $typeName $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING($i + 1));
  261.                 $typeName trim($tokens[$typeName]['content']" '");
  262.                 $includedClasses[strtolower($typeName).'widgettype'= true;
  263.             }
  264.         }//end for
  265.  
  266.         if (isset($includedClasses[strtolower($className)]=== false{
  267.             if ($tokens[$stackPtr]['code'=== T_EXTENDS{
  268.                 $error 'Class extends non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once';
  269.                 $data  = array($className);
  270.                 $phpcsFile->addError($error$stackPtr'NotIncludedExtends'$data);
  271.             else {
  272.                 $error 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once';
  273.                 $data  = array($className);
  274.                 $phpcsFile->addError($error$stackPtr'NotIncludedCall'$data);
  275.             }
  276.         }
  277.  
  278.     }//end processTokenOutsideScope()
  279.  
  280.  
  281.     /**
  282.      * Determines the included class name from given token.
  283.      *
  284.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
  285.      * @param array                       $tokens    The array of file tokens.
  286.      * @param int                         $stackPtr  The position in the tokens array of the
  287.      *                                                potentially included class.
  288.      *
  289.      * @return string 
  290.      */
  291.     protected function getIncludedClassFromToken(File $phpcsFilearray $tokens$stackPtr)
  292.     {
  293.         if (strtolower($tokens[$stackPtr]['content']=== 'includesystem'{
  294.             $systemName $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING($stackPtr + 1));
  295.             $systemName trim($tokens[$systemName]['content']" '");
  296.             return strtolower($systemName);
  297.         else if (strtolower($tokens[$stackPtr]['content']=== 'includeasset'{
  298.             $typeName $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING($stackPtr + 1));
  299.             $typeName = trim($tokens[$typeName]['content']" '");
  300.             return strtolower($typeName).'assettype';
  301.         else if (isset(Tokens::$includeTokens[$tokens[$stackPtr]['code']]=== true{
  302.             $filePath $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING($stackPtr + 1));
  303.             $filePath $tokens[$filePath]['content'];
  304.             $filePath trim($filePath" '");
  305.             $filePath basename($filePath'.inc');
  306.             return strtolower($filePath);
  307.         }
  308.  
  309.         return false;
  310.  
  311.     }//end getIncludedClassFromToken()
  312.  
  313.  
  314. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:33 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.