Skip to content
Back to skills

Code Reviewer 14

ASecurity

Reviews PHP/CakePHP code for quality, standards compliance, and best practices

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
code-qualitygophpsqltestingrefactoringcode-reviewapidatabasesecurityperformance

Works with

  • api

Security analysis

A100/100

Scanned September 27, 2026

npx -y skills add David-Li0406/meta-skill-evloving --skill code-reviewer-14 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Code Reviewer 14?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Code Reviewer 14
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/david-li0406-code-reviewer-14/badge)](https://www.skillsdirectory.com/skills/david-li0406-code-reviewer-14)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: code-reviewer
description: Reviews PHP/CakePHP code for quality, standards compliance, and best practices
hooks:
  SessionStart:
    - type: command
      command: |
        if command -v yq &> /dev/null && [ -f ".claude/config.yaml" ]; then
          echo "=== Architecture Constraints ==="
          yq -o=json '.constraints.architecture' .claude/config.yaml 2>/dev/null || true
          echo "=== All Constraints ==="
          yq -o=json '.constraints' .claude/config.yaml 2>/dev/null || true
        fi
---

# PHP/CakePHP Code Reviewer

A specialized skill for reviewing PHP/CakePHP code to ensure quality, maintainability, and adherence to standards.

## Core Responsibilities

### 1. Code Quality Metrics

**Complexity Analysis:**
```php
/**
 * Cyclomatic Complexity Check
 *
 * Good: <= 10
 * Acceptable: 11-20
 * Needs refactoring: > 20
 */
public function analyzeComplexity($method)
{
    // Count:
    // - if statements
    // - case statements
    // - for/foreach/while loops
    // - catch blocks
    // - && and || operators
    // - ?: operators
}
```

**Method Length Check:**
```php
/**
 * Method Length Guidelines
 *
 * Ideal: <= 20 lines
 * Acceptable: 21-50 lines
 * Too long: > 50 lines
 */
```

**Class Cohesion:**
```php
/**
 * Single Responsibility Principle
 *
 * Each class should have one reason to change
 * Methods should be related to class purpose
 */
```

### 2. PHP Standards Review

**PSR-12 Compliance:**
```php
// ✅ CORRECT: PSR-12 formatting
<?php

declare(strict_types=1);

namespace App\Controller\User;

use Cake\Controller\Controller;
use Cake\Http\Response;

class UsersController extends Controller
{
    public function index(): ?Response
    {
        // 4 spaces indentation
        if ($condition) {
            $this->doSomething();
        }

        return null;
    }
}

// ❌ WRONG: Non-standard formatting
<?php
namespace App\Controller\User;
use Cake\Controller\Controller;

class UsersController extends Controller {
    public function index(){
        if($condition){
            $this->doSomething();
        }
    }
}
```

**Type Declarations:**
```php
// ✅ CORRECT: Strict types with declarations
declare(strict_types=1);

public function processData(array $data, int $limit): bool
{
    return true;
}

// ❌ WRONG: Missing type declarations
public function processData($data, $limit)
{
    return true;
}
```

### 3. CakePHP Convention Review

**Naming Conventions:**
```php
// ✅ CORRECT CakePHP naming
class UsersTable extends Table         // Plural for tables
class User extends Entity              // Singular for entities
class UsersController extends Controller  // Plural for controllers

// Model associations
$this->belongsTo('Company', [         // Singular for belongsTo
    'className' => 'Companys',
]);
$this->hasMany('Orders');             // Plural for hasMany

// ❌ WRONG naming
class UserTable extends Table         // Should be plural
$this->belongsTo('Companies');       // Should be singular alias
```

**MVC Separation:**
```php
// ✅ CORRECT: Thin controller, fat model
// Controller
public function approve($id)
{
    $application = $this->Applications->get($id);
    $result = $this->Applications->approve($application);

    if ($result) {
        $this->Flash->success(__('承認しました'));
    }
}

// Model
public function approve($application): bool
{
    // Complex business logic here
    $application->status = Configure::read('Application.Status.approved');
    // More logic...
    return $this->save($application);
}

// ❌ WRONG: Business logic in controller
public function approve($id)
{
    $application = $this->Applications->get($id);

    // Business logic should be in model
    $application->status = 3;
    $application->approved_date = date('Y-m-d');
    // Calculate approval logic...
    // Send notifications...

    $this->Applications->save($application);
}
```

### 4. Security Review

**SQL Injection Prevention:**
```php
// ✅ CORRECT: Using ORM query builder
$users = $this->Users->find()
    ->where(['email' => $userInput])
    ->all();

// ❌ WRONG: Raw SQL with concatenation
$query = "SELECT * FROM users WHERE email = '" . $userInput . "'";
```

**XSS Prevention:**
```php
// ✅ CORRECT: Escaping output in views
<?= h($userInput) ?>
<?= $this->Text->autoParagraph(h($content)) ?>

// ❌ WRONG: Unescaped output
<?= $userInput ?>
<?php echo $content; ?>
```

**Authentication & Authorization:**
```php
// ✅ CORRECT: Proper auth check
public function beforeFilter(EventInterface $event)
{
    parent::beforeFilter($event);

    if (!$this->Auth->user()) {
        throw new UnauthorizedException('ログインが必要です');
    }

    if (!$this->isAuthorized()) {
        throw new ForbiddenException('権限がありません');
    }
}

// ❌ WRONG: No auth check or weak implementation
public function delete($id)
{
    // Missing auth check
    $this->Model->delete($id);
}
```

**Password Handling:**
```php
// ✅ CORRECT: Using password hasher
use Cake\Auth\DefaultPasswordHasher;

$hasher = new DefaultPasswordHasher();
$hashed = $hasher->hash($password);

// ❌ WRONG: Plain text or weak hashing
$password = md5($password);  // Weak
$password = $plainText;       // Never store plain text
```

### 5. Performance Review

**N+1 Query Problem:**
```php
// ✅ CORRECT: Eager loading with contain
$users = $this->Users->find()
    ->contain(['Orders', 'Company'])
    ->all();

// ❌ WRONG: Lazy loading causes N+1
$users = $this->Users->find()->all();
foreach ($users as $user) {
    $orders = $user->orders; // Additional query per user
}
```

**Caching Strategy:**
```php
// ✅ CORRECT: Using cache for expensive operations
public function getExpensiveData()
{
    return Cache::remember('expensive_data', function () {
        return $this->calculateExpensiveOperation();
    }, 'long_term');
}

// ❌ WRONG: No caching for repeated expensive operations
public function getExpensiveData()
{
    return $this->calculateExpensiveOperation(); // Recalculated every time
}
```

**Database Optimization:**
```php
// ✅ CORRECT: Optimized query
$results = $this->Model->find()
    ->select(['id', 'name', 'status']) // Select only needed fields
    ->where(['status' => 1])
    ->order(['created' => 'DESC'])
    ->limit(100)
    ->all();

// ❌ WRONG: Inefficient query
$results = $this->Model->find('all'); // Loads everything
```

### 6. Error Handling Review

**Exception Handling:**
```php
// ✅ CORRECT: Proper exception handling
try {
    $result = $this->performOperation();

    if (!$result) {
        throw new \RuntimeException('Operation failed');
    }

    return $result;

} catch (RecordNotFoundException $e) {
    Log::warning('Record not found: ' . $e->getMessage());
    throw new NotFoundException('データが見つかりません');

} catch (\Exception $e) {
    Log::error('Unexpected error: ' . $e->getMessage());
    throw new InternalErrorException('システムエラーが発生しました');
}

// ❌ WRONG: Generic or no error handling
try {
    $this->performOperation();
} catch (\Exception $e) {
    // Too generic, no logging
    return false;
}
```

**Validation Errors:**
```php
// ✅ CORRECT: Proper validation error handling
$entity = $this->Model->patchEntity($entity, $data);

if ($this->Model->save($entity)) {
    $this->Flash->success(__('保存しました'));
} else {
    $errors = $entity->getErrors();
    foreach ($errors as $field => $fieldErrors) {
        foreach ($fieldErrors as $error) {
            $this->Flash->error($error);
        }
    }
}

// ❌ WRONG: Ignoring validation errors
$this->Model->save($entity); // No error check
```

### 7. Testing Considerations

**Testability Review:**
```php
// ✅ CORRECT: Testable code with dependency injection
class OrderService
{
    private $Orders;
    private $Mailer;

    public function __construct(OrdersTable $orders, MailerInterface $mailer)
    {
        $this->Orders = $orders;
        $this->Mailer = $mailer;
    }
}

// ❌ WRONG: Hard dependencies, difficult to test
class OrderService
{
    public function processOrder()
    {
        $Orders = TableRegistry::get('Orders'); // Hard to mock
        $mailer = new Mailer();                 // Hard to mock
    }
}
```

**Test Coverage Indicators:**
```php
// Methods that MUST have tests:
// - Public methods with business logic
// - Data validation methods
// - Security-critical methods
// - Methods with complex conditions

// Methods that MAY skip tests:
// - Simple getters/setters
// - Framework override methods with no custom logic
```

### 8. Documentation Review

**PHPDoc Standards:**
```php
// ✅ CORRECT: Complete PHPDoc
/**
 * Process order and send confirmation
 *
 * @param int $orderId Order ID to process
 * @param array $options Processing options
 * @return bool True on success
 * @throws \InvalidArgumentException When order ID is invalid
 * @throws \RuntimeException When processing fails
 */
public function processOrder(int $orderId, array $options = []): bool
{
    // Implementation
}

// ❌ WRONG: Missing or incomplete PHPDoc
// No documentation
public function processOrder($orderId, $options = [])
{
    // Implementation
}
```

## Review Checklist

### Code Structure
- [ ] Single Responsibility Principle followed
- [ ] DRY (Don't Repeat Yourself) principle applied
- [ ] Methods are concise (< 50 lines)
- [ ] Cyclomatic complexity is acceptable (< 20)
- [ ] Proper abstraction levels

### PHP Standards
- [ ] PSR-12 coding style
- [ ] Strict types declared
- [ ] Type hints for parameters and returns
- [ ] Proper namespace usage
- [ ] No deprecated functions

### CakePHP Conventions
- [ ] Naming conventions followed
- [ ] MVC separation maintained
- [ ] ORM used properly
- [ ] Configure::read() for configs
- [ ] Proper use of components and helpers

### Security
- [ ] No SQL injection vulnerabilities
- [ ] XSS prevention in place
- [ ] Authentication checks
- [ ] Authorization checks
- [ ] Proper password handling
- [ ] CSRF protection

### Performance
- [ ] No N+1 query problems
- [ ] Proper use of eager loading
- [ ] Caching where appropriate
- [ ] Optimized database queries
- [ ] No unnecessary loops

### Error Handling
- [ ] Proper exception handling
- [ ] Appropriate error messages
- [ ] Logging of errors
- [ ] Validation error handling

### Testing
- [ ] Code is testable
- [ ] No hard dependencies
- [ ] Mock-friendly design

### Documentation
- [ ] PHPDoc for all public methods
- [ ] Complex logic commented
- [ ] README updated if needed

## Review Output Format

```markdown
## Code Review: [File/Feature Name]

### Summary
- **Overall Quality**: Excellent/Good/Needs Improvement/Poor
- **Risk Level**: Low/Medium/High
- **Recommendation**: Approve/Approve with changes/Needs rework

### Strengths
- Well-structured MVC separation
- Good error handling
- Follows CakePHP conventions

### Issues Found

#### Critical (Must Fix)
1. **SQL Injection Risk** (Line 45)
   - Current: Raw SQL concatenation
   - Solution: Use ORM query builder
   ```php
   // Replace this
   $query = "SELECT * FROM users WHERE id = " . $id;

   // With this
   $user = $this->Users->get($id);
   ```

#### Major (Should Fix)
1. **N+1 Query Problem** (Line 78)
   - Current: Lazy loading in loop
   - Solution: Add eager loading

#### Minor (Consider Fixing)
1. **Missing PHPDoc** (Line 120)
   - Add documentation for public method

### Metrics
- Cyclomatic Complexity: 15 (Acceptable)
- Method Length: Max 45 lines (Good)
- Test Coverage Required: 85%

### Action Items
- [ ] Fix SQL injection vulnerability
- [ ] Add eager loading for associations
- [ ] Add missing PHPDoc comments
```

## Best Practices

1. **Be Constructive**: Provide solutions, not just problems
2. **Prioritize Issues**: Focus on critical/security issues first
3. **Consider Context**: Understand requirements and constraints
4. **Educate**: Explain why something is an issue
5. **Be Specific**: Reference line numbers and provide examples
6. **Stay Objective**: Focus on code, not person

Remember: Good code review improves code quality and helps team members learn and grow.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…