DrupalCamp St. Louis
September 10, 2016Joseph D. Purcell
@josephdpurcellWoh nedes a sepll cehcker?
... computers aren't so forgiving
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
The "goto fail" bug could have been caught by static analysis
Source: Martin Fowler
Anything you can learn from code without executing it.
if (($err = SSLHashSHA1::update($hashCtx, $signedParams)) != 0)
goto fail;
goto fail;
Read the file off disk and look for a pattern.
protected function doLoadMultiple(array $names, $immutable = TRUE) { ... if (isset($GLOBALS['config'][$name])) { $this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]); ...
protected function formSingleElement(FieldItemListInterface $items, $delta... $entity = $items->getEntity(); $element += array( '#field_parents' => $form['#parents'], // Only the first widget should be required. '#required' => $delta == 0 && $this->fieldDefinition->isRequired(), '#delta' => $delta, '#weight' => $delta, ); $element = $this->formElement($items, $delta, $element, $form, $form_state); if ($element) { ...
If it stinks, change it.
- Grandma Beck, "Refactoring"
protected function doLoadMultiple(array $names, $immutable = TRUE) { ... if (isset($GLOBALS['config'][$name])) { $this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]); ...
protected function formSingleElement(FieldItemListInterface $items, $delta... $entity = $items->getEntity(); $element += array( '#field_parents' => $form['#parents'], // Only the first widget should be required. '#required' => $delta == 0 && $this->fieldDefinition->isRequired(), '#delta' => $delta, '#weight' => $delta, ); $element = $this->formElement($items, $delta, $element, $form, $form_state); if ($element) { ...
$entity
is supposed to do.$entity
a bug?private function getProxyInstantiator() { if (!$this->proxyInstantiator) { $this->proxyInstantiator = new RealServiceInstantiator(); } ...
class EntityType implements EntityTypeInterface { public function get($property) { public function set($property, $value) { public function isStaticallyCacheable() { public function isRenderCacheable() { public function isPersistentlyCacheable() { public function getKeys() { public function getKey($key) { public function hasKey($key) { public function id() { public function getProvider() { public function getClass() { public function getOriginalClass() { public function setClass($class) { public function isSubclassOf($class) { public function getHandlerClasses() { public function getHandlerClass($handler_type, $nested = FALSE) { public function setHandlerClass($handler_type, $value) { public function hasHandlerClass($handler_type, $nested = FALSE) { public function getStorageClass() { public function setStorageClass($class) { ... 49 more methods!
class WorkspaceController extends ControllerBase { public function add() { $types = WorkspaceType::loadMultiple(); if ($types && count($types) == 1) { $type = reset($types); return $this->addForm($type); } ...
::loadMultiple()
public function update(WorkspacePointerInterface $source, WorkspacePointerInterface $target) { return $this->doReplication($source, $target); }
update
is generic, why is it just a wrapper to doReplication
?public function disableEntityTypes() { foreach ($entity_types as $entity_type_id => $entity_type) { try { if ($storage->hasData()) { catch (\Exception $e) { if ($has_data[$entity_type_id]) { if ($entity_type_id == 'file') { foreach ($entity_manager->getDefinitions() as $entity_type) { if ($entity_type->isSubclassOf(FieldableEntityInterface::CLASS)) { foreach ($entity_manager->getFieldStorageDefinitions($entity_type_id)... if ($storage_definition->getProvider() == 'multiversion' && !$storage... foreach ($enabled_entity_types as $entity_type_id) { foreach ($entity_types as $entity_type_id => $entity_type) { if ($has_data[$entity_type_id]) { ...
... namespace Drupal\multiversion; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\State\StateInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Database\Connection; use Drupal\multiversion\Workspace\WorkspaceManagerInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\Serializer\Serializer; class MultiversionManager implements MultiversionManagerInterface, ContainerAwareInterface { ...
A static analysis platform, free for open source (on GitHub).
Examples on GitHub:
github.com/josephdpurcell/code-climate-and-drupal
--- engines: phpmd: enabled: true config: file_extensions: "php,inc,module,install" rulesets: ".phpmd.xml" phpcodesniffer: enabled: true config: file_extensions: "php,inc,module,install" encoding: utf-8 standard: "Drupal" ignore_warnings: true ratings: paths: - "web/modules/custom/**.php" - "web/modules/custom/**.inc" - "web/modules/custom/**.module" - "web/modules/custom/**.install" exclude_paths: - conf - web/core - web/modules/contrib - web/profiles - web/sites - web/themes - web/*.php
<?xml version="1.0"?> <ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3... <description> A PMD Ruleset for Drupal coding standards. </description> <!-- Code Size --> <rule ref="rulesets/codesize.xml/CyclomaticComplexity"/> <rule ref="rulesets/codesize.xml/NPathComplexity"/> <rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/> <rule ref="rulesets/codesize.xml/ExcessiveClassLength"/> <rule ref="rulesets/codesize.xml/ExcessiveParameterList"/> <rule ref="rulesets/codesize.xml/ExcessivePublicCount"/> <rule ref="rulesets/codesize.xml/TooManyFields"/> ...
Speak for the code.
Come to the sprints tomorrow!
Slides: github.com/josephdpurcell/code-climate-and-drupal
Want help setting up Code Climate?