Skip to content

Basic Usage

This guide covers the fundamental usage patterns and common workflows with the Go Composer SDK.

Quick Start

Creating a Composer Instance

go
package main

import (
    "fmt"
    "log"
    
    "github.com/scagogogo/go-composer-sdk/pkg/composer"
)

func main() {
    // Create with default options
    comp, err := composer.New(composer.DefaultOptions())
    if err != nil {
        log.Fatalf("Failed to create Composer instance: %v", err)
    }
    
    // Set your project directory
    comp.SetWorkingDir("/path/to/your/php/project")
    
    fmt.Println("Composer SDK is ready!")
}

Basic Operations

go
// Check if Composer is installed
if !comp.IsInstalled() {
    log.Fatal("Composer is not installed")
}

// Get version
version, err := comp.GetVersion()
if err != nil {
    log.Printf("Failed to get version: %v", err)
} else {
    fmt.Printf("Composer version: %s\n", version)
}

// Install dependencies
err = comp.Install(false, false) // noDev=false, optimize=false
if err != nil {
    log.Printf("Installation failed: %v", err)
}

Common Workflows

Project Setup Workflow

go
func setupNewProject(projectPath string) error {
    comp, err := composer.New(composer.DefaultOptions())
    if err != nil {
        return err
    }
    
    comp.SetWorkingDir(projectPath)
    
    // 1. Initialize project if needed
    if _, err := os.Stat(filepath.Join(projectPath, "composer.json")); os.IsNotExist(err) {
        initOptions := composer.InitOptions{
            Name:        "mycompany/my-project",
            Description: "My PHP project",
            Type:        "project",
            License:     "MIT",
        }
        
        if err := comp.InitProject(initOptions); err != nil {
            return fmt.Errorf("failed to initialize project: %w", err)
        }
    }
    
    // 2. Add essential packages
    packages := map[string]string{
        "symfony/console": "^6.0",
        "monolog/monolog": "^3.0",
    }
    
    if err := comp.RequirePackages(packages); err != nil {
        return fmt.Errorf("failed to add packages: %w", err)
    }
    
    // 3. Install dependencies
    if err := comp.Install(false, true); err != nil { // optimize=true
        return fmt.Errorf("failed to install dependencies: %w", err)
    }
    
    fmt.Println("✅ Project setup completed!")
    return nil
}

Maintenance Workflow

go
func maintainProject(projectPath string) error {
    comp, err := composer.New(composer.DefaultOptions())
    if err != nil {
        return err
    }
    
    comp.SetWorkingDir(projectPath)
    
    // 1. Validate composer.json
    if err := comp.Validate(); err != nil {
        return fmt.Errorf("validation failed: %w", err)
    }
    
    // 2. Check for outdated packages
    outdated, err := comp.ShowOutdated()
    if err != nil {
        log.Printf("Warning: Failed to check outdated packages: %v", err)
    } else if outdated != "" {
        fmt.Println("📦 Outdated packages found:")
        fmt.Println(outdated)
        
        // Optionally update
        fmt.Println("Updating packages...")
        if err := comp.Update(false, true); err != nil {
            log.Printf("Update failed: %v", err)
        }
    }
    
    // 3. Security audit
    auditResult, err := comp.Audit()
    if err != nil {
        log.Printf("Security audit failed: %v", err)
    } else {
        fmt.Println("🔒 Security audit completed")
        if auditResult != "" {
            fmt.Println(auditResult)
        }
    }
    
    // 4. Clean up
    if err := comp.ClearCache(); err != nil {
        log.Printf("Cache cleanup failed: %v", err)
    }
    
    return nil
}

Working with Dependencies

Adding Dependencies

go
// Add a single package
err := comp.RequirePackage("guzzlehttp/guzzle", "^7.0")

// Add multiple packages
packages := map[string]string{
    "symfony/http-foundation": "^6.0",
    "doctrine/orm":           "^2.14",
}
err = comp.RequirePackages(packages)

// Add development dependency
err = comp.RequireDevPackage("phpunit/phpunit", "^10.0")

Updating Dependencies

go
// Update all packages
err := comp.Update(false, false)

// Update specific package
err = comp.UpdatePackage("symfony/console")

// Update multiple specific packages
packages := []string{"symfony/console", "monolog/monolog"}
err = comp.UpdatePackages(packages)

Removing Dependencies

go
// Remove a package
err := comp.RemovePackage("old-package/deprecated")

// Remove multiple packages
packages := []string{"package1", "package2"}
err = comp.RemovePackages(packages)

Information and Analysis

Package Information

go
// List all installed packages
packages, err := comp.ShowAllPackages()
if err == nil {
    fmt.Println("Installed packages:")
    fmt.Println(packages)
}

// Show specific package details
details, err := comp.ShowPackage("symfony/console")
if err == nil {
    fmt.Printf("Package details:\n%s\n", details)
}

// Show dependency tree
tree, err := comp.ShowDependencyTree("")
if err == nil {
    fmt.Printf("Dependency tree:\n%s\n", tree)
}

Dependency Analysis

go
// Why is a package installed?
reasons, err := comp.WhyPackage("psr/log")
if err == nil {
    fmt.Printf("Why psr/log is installed:\n%s\n", reasons)
}

// Why can't a package be installed?
conflicts, err := comp.WhyNotPackage("symfony/console", "^7.0")
if err == nil {
    fmt.Printf("Conflicts for symfony/console ^7.0:\n%s\n", conflicts)
}

Error Handling Patterns

Basic Error Handling

go
func handleComposerOperation() error {
    comp, err := composer.New(composer.DefaultOptions())
    if err != nil {
        return fmt.Errorf("failed to create composer instance: %w", err)
    }
    
    comp.SetWorkingDir("/path/to/project")
    
    // Always check if Composer is available
    if !comp.IsInstalled() {
        return fmt.Errorf("composer is not installed")
    }
    
    // Perform operation with error handling
    if err := comp.Install(false, false); err != nil {
        return fmt.Errorf("installation failed: %w", err)
    }
    
    return nil
}

Robust Error Handling with Retries

go
func robustInstall(comp *composer.Composer, maxRetries int) error {
    for attempt := 1; attempt <= maxRetries; attempt++ {
        fmt.Printf("Installation attempt %d/%d...\n", attempt, maxRetries)
        
        err := comp.Install(false, false)
        if err == nil {
            fmt.Println("✅ Installation successful!")
            return nil
        }
        
        fmt.Printf("❌ Attempt %d failed: %v\n", attempt, err)
        
        if attempt < maxRetries {
            // Wait before retry
            time.Sleep(time.Duration(attempt) * time.Second)
            
            // Clear cache before retry
            if clearErr := comp.ClearCache(); clearErr != nil {
                log.Printf("Failed to clear cache: %v", clearErr)
            }
        }
    }
    
    return fmt.Errorf("installation failed after %d attempts", maxRetries)
}

Context and Timeouts

Using Context for Cancellation

go
func installWithCancellation() error {
    comp, err := composer.New(composer.DefaultOptions())
    if err != nil {
        return err
    }
    
    comp.SetWorkingDir("/path/to/project")
    
    // Create cancellable context
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    
    // Start installation in goroutine
    errChan := make(chan error, 1)
    go func() {
        errChan <- comp.InstallWithContext(ctx, false, false)
    }()
    
    // Wait for completion or user cancellation
    select {
    case err := <-errChan:
        if err != nil {
            return fmt.Errorf("installation failed: %w", err)
        }
        fmt.Println("✅ Installation completed!")
        return nil
        
    case <-time.After(30 * time.Second):
        // User decides to cancel after 30 seconds
        cancel()
        return fmt.Errorf("installation cancelled by user")
    }
}

Timeout Handling

go
func installWithTimeout(timeoutMinutes int) error {
    comp, err := composer.New(composer.DefaultOptions())
    if err != nil {
        return err
    }
    
    comp.SetWorkingDir("/path/to/project")
    
    // Create context with timeout
    ctx, cancel := context.WithTimeout(
        context.Background(),
        time.Duration(timeoutMinutes)*time.Minute,
    )
    defer cancel()
    
    err = comp.InstallWithContext(ctx, false, false)
    if err != nil {
        if errors.Is(err, context.DeadlineExceeded) {
            return fmt.Errorf("installation timed out after %d minutes", timeoutMinutes)
        }
        return fmt.Errorf("installation failed: %w", err)
    }
    
    return nil
}

Environment Configuration

Development Environment

go
func setupDevelopmentEnvironment(comp *composer.Composer) {
    comp.SetEnv([]string{
        "COMPOSER_MEMORY_LIMIT=-1",
        "COMPOSER_PROCESS_TIMEOUT=300",
        "COMPOSER_DISCARD_CHANGES=true",
        "COMPOSER_PREFER_STABLE=false",
    })
}

Production Environment

go
func setupProductionEnvironment(comp *composer.Composer) {
    comp.SetEnv([]string{
        "COMPOSER_MEMORY_LIMIT=-1",
        "COMPOSER_PROCESS_TIMEOUT=600",
        "COMPOSER_OPTIMIZE_AUTOLOADER=true",
        "COMPOSER_CLASSMAP_AUTHORITATIVE=true",
        "COMPOSER_PREFER_STABLE=true",
    })
}

Best Practices

1. Always Validate Before Operations

go
func safeComposerOperation(comp *composer.Composer) error {
    // Check Composer availability
    if !comp.IsInstalled() {
        return fmt.Errorf("composer not available")
    }
    
    // Validate project
    if err := comp.Validate(); err != nil {
        return fmt.Errorf("project validation failed: %w", err)
    }
    
    // Proceed with operation
    return comp.Install(false, false)
}

2. Use Appropriate Timeouts

go
func operationWithAppropriateTimeout(comp *composer.Composer, operation string) error {
    var timeout time.Duration
    
    switch operation {
    case "install", "update":
        timeout = 10 * time.Minute
    case "require", "remove":
        timeout = 5 * time.Minute
    default:
        timeout = 2 * time.Minute
    }
    
    ctx, cancel := context.WithTimeout(context.Background(), timeout)
    defer cancel()
    
    return comp.InstallWithContext(ctx, false, false)
}

3. Handle Different Environments

go
func createComposerForEnvironment() (*composer.Composer, error) {
    options := composer.DefaultOptions()
    
    // Adjust based on environment
    if os.Getenv("CI") == "true" {
        options.DefaultTimeout = 15 * time.Minute
    } else if os.Getenv("APP_ENV") == "production" {
        options.AutoInstall = false
    }
    
    comp, err := composer.New(options)
    if err != nil {
        return nil, err
    }
    
    // Set environment-specific variables
    if os.Getenv("CI") == "true" {
        comp.SetEnv([]string{
            "COMPOSER_NO_INTERACTION=1",
            "COMPOSER_PREFER_STABLE=true",
        })
    }
    
    return comp, nil
}

4. Logging and Monitoring

go
func monitoredOperation(comp *composer.Composer) error {
    start := time.Now()
    
    log.Printf("Starting Composer operation in: %s", comp.GetWorkingDir())
    
    err := comp.Install(false, false)
    
    duration := time.Since(start)
    if err != nil {
        log.Printf("❌ Operation failed after %v: %v", duration, err)
        return err
    }
    
    log.Printf("✅ Operation completed successfully in %v", duration)
    return nil
}

This covers the essential usage patterns you'll need for most Composer operations. The key is to always handle errors appropriately, use timeouts for long-running operations, and configure the environment based on your specific needs.

Released under the MIT License.