PHP code example of jjuanrivvera / canvas-lms-kit

1. Go to this page and download the library: Download jjuanrivvera/canvas-lms-kit library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

jjuanrivvera / canvas-lms-kit example snippets


use CanvasLMS\Config;
use CanvasLMS\Api\Courses\Course;

Config::setApiKey('your-api-key');
Config::setBaseUrl('https://canvas.instructure.com');

// It's that simple!
$courses = Course::get();  // Get first page
foreach ($courses as $course) {
    echo $course->name . "\n";
}

use CanvasLMS\Config;

// Basic configuration
Config::setApiKey('your-api-key');
Config::setBaseUrl('https://canvas.instructure.com');

// Optional: Set account ID for scoped operations
Config::setAccountId(1);

// Optional: Configure middleware
Config::setMiddleware([
    'retry' => ['max_attempts' => 3],
    'rate_limit' => ['wait_on_limit' => true],
]);

use CanvasLMS\Config;
use CanvasLMS\Auth\OAuth;

// Configure OAuth credentials
Config::setOAuthClientId('your-client-id');
Config::setOAuthClientSecret('your-client-secret');
Config::setOAuthRedirectUri('https://yourapp.com/oauth/callback');
Config::setBaseUrl('https://canvas.instructure.com');

// Step 1: Get authorization URL
$authUrl = OAuth::getAuthorizationUrl(['state' => 'random-state']);
// Redirect user to $authUrl

// Step 2: Handle callback
$tokenData = OAuth::exchangeCode($_GET['code']);

// Step 3: Use OAuth mode
Config::useOAuth();

// Now all API calls use OAuth with automatic token refresh!
$courses = Course::get(); // User's courses (first page)

// Auto-detect from environment
Config::autoDetect();
// Ready to use!

use CanvasLMS\Config;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// Configure with Monolog
$logger = new Logger('canvas-lms');
$logger->pushHandler(new StreamHandler('logs/canvas.log', Logger::INFO));
Config::setLogger($logger);

// All API calls, OAuth operations, pagination, and file uploads are now logged!

use Psr\Log\LoggerInterface;

public function __construct(LoggerInterface $logger) {
    Config::setLogger($logger);
}

// Enable detailed request/response logging
Config::setMiddleware([
    'logging' => [
        'enabled' => true,
        'log_requests' => true,
        'log_responses' => true,
        'log_errors' => true,
        'log_timing' => true,
        'log_level' => \Psr\Log\LogLevel::DEBUG,
        'sanitize_fields' => ['password', 'token', 'api_key', 'secret'],
        'max_body_length' => 1000
    ]
]);

use CanvasLMS\Config;
use CanvasLMS\Api\Courses\Course;
use CanvasLMS\Api\Users\User;

// Enable masquerading as user 12345
Config::asUser(12345);

// All API calls will now ->enrollments(); // Also as user 12345

// Stop masquerading
Config::stopMasquerading();

// Subsequent calls are performed as the authenticated user
$normalCourse = Course::find(789);        // No masquerading

// Set masquerading for production context only
Config::setContext('production');
Config::asUser(12345, 'production');

// Only affects production context operations
Config::setContext('staging');
$stagingUser = User::find(1);  // Not masqueraded

Config::setContext('production');
$prodUser = User::find(1);      // Masqueraded as user 12345

// Check if masquerading is active
if (Config::isMasquerading()) {
    $masqueradeUserId = Config::getMasqueradeUserId();
    $logger->info("Performing operation as user {$masqueradeUserId}");
}

// Support agent helping a student
Config::asUser($studentId);
$submissions = Assignment::find($assignmentId)->getSubmission($studentId);
Config::stopMasquerading();

// Test different user roles
foreach ($testUsers as $userId => $role) {
    Config::asUser($userId);
    $canEdit = Course::find($courseId)->canEdit(); // Check permissions as this user
    echo "User {$userId} ({$role}): " . ($canEdit ? 'Can edit' : 'Cannot edit') . "\n";
}
Config::stopMasquerading();

// Process enrollments for multiple users
$userIds = [123, 456, 789];
foreach ($userIds as $userId) {
    Config::asUser($userId);
    $enrollment = Enrollment::create([
        'user_id' => $userId,
        'course_id' => $courseId,
        'enrollment_state' => 'active'
    ]);
    echo "Enrolled user {$userId} successfully\n";
}
Config::stopMasquerading();

// 1. get() - Fetch first page only (default: 10 items)
$courses = Course::get();                    // First 10 courses
$courses = Course::get(['per_page' => 50]); // First 50 courses

// 2. paginate() - Get results with pagination metadata
$result = Course::paginate(['per_page' => 25]);
echo "Page {$result->getCurrentPage()} of {$result->getTotalPages()}";
echo "Total courses: {$result->getTotalCount()}";

// 3. all() - Fetch ALL items from all pages automatically
$allCourses = Course::all();  // ⚠️ Use with caution on large datasets!

// ❌ WRONG - May exhaust memory with large datasets
$allUsers = User::all();  // Could be 50,000+ users!
foreach ($allUsers as $user) {
    processUser($user);
}

// ✅ CORRECT - Process in batches using paginate()
$page = 1;
do {
    $batch = User::paginate(['page' => $page++, 'per_page' => 100]);
    
    foreach ($batch->getData() as $user) {
        processUser($user);
    }
    
    // Optional: Add delay to respect rate limits
    if ($batch->hasNextPage()) {
        sleep(1);
    }
    
} while ($batch->hasNextPage());

// In your controller
$page = $_GET['page'] ?? 1;
$result = Course::paginate(['page' => $page, 'per_page' => 25]);

// In your view
foreach ($result->getData() as $course) {
    echo "<tr><td>{$course->name}</td></tr>";
}

// Pagination controls
if ($result->hasPreviousPage()) {
    echo "<a href='?page=" . ($page - 1) . "'>Previous</a>";
}
if ($result->hasNextPage()) {
    echo "<a href='?page=" . ($page + 1) . "'>Next</a>";
}
echo "Page {$result->getCurrentPage()} of {$result->getTotalPages()}";

// For small datasets (< 1000 items)
$assignments = Assignment::all(['course_id' => 123]);
exportToCSV($assignments);

// For large datasets - stream to file
$csvFile = fopen('enrollments.csv', 'w');
$page = 1;

do {
    $batch = Enrollment::paginate(['page' => $page++, 'per_page' => 500]);
    
    foreach ($batch->getData() as $enrollment) {
        fputcsv($csvFile, [
            $enrollment->userId,
            $enrollment->courseId,
            $enrollment->enrollmentState
        ]);
    }
    
} while ($batch->hasNextPage());

fclose($csvFile);

// When you need just a subset
$recentAssignments = Assignment::get([
    'per_page' => 10,
    'order_by' => 'due_at'
]);

// When searching through all pages
$found = false;
$page = 1;

do {
    $batch = User::paginate([
        'page' => $page++,
        'search_term' => '[email protected]'
    ]);
    
    foreach ($batch->getData() as $user) {
        if ($user->email === '[email protected]') {
            $found = $user;
            break 2; // Exit both loops
        }
    }
    
} while ($batch->hasNextPage() && !$found);

$result = Course::paginate(['per_page' => 20]);

// Data access
$courses = $result->getData();           // Array of Course objects
$total = $result->getTotalCount();       // Total number of courses

// Navigation
$result->hasNextPage();                  // true/false
$result->hasPreviousPage();              // true/false
$result->getNextPage();                  // Fetches next page (returns new PaginationResult)
$result->getPreviousPage();              // Fetches previous page

// Page information
$result->getCurrentPage();               // Current page number
$result->getTotalPages();                // Total number of pages
$result->getPerPage();                   // Items per page

// URL access (for custom implementations)
$result->getNextUrl();                   // Next page URL
$result->getPreviousUrl();               // Previous page URL

// 📗 Small datasets (< 100 items): Safe to use all()
$modules = Module::all();
$sections = Section::all();

// 📙 Medium datasets (100-1000 items): Consider your use case
$assignments = Assignment::get(['per_page' => 100]);     // If you need subset
$assignments = Assignment::paginate(['per_page' => 100]); // If processing batches
$assignments = Assignment::all();                         // If you need everything

// 📕 Large datasets (1000+ items): Use paginate() for memory efficiency
$users = User::paginate(['per_page' => 100]);
$enrollments = Enrollment::paginate(['per_page' => 500]);

// Note: The SDK 

$course = Course::find(123);
$modules = $course->modules();      // Returns ALL modules (all pages)
$enrollments = $course->enrollments(); // Returns ALL enrollments (could be thousands!)

// For large datasets, consider using pagination directly:
Enrollment::setCourse($course);
$paginatedEnrollments = Enrollment::paginate(['per_page' => 100]); // Memory efficient

// Or use paginate for control:
$paginatedModules = Module::paginate(['per_page' => 50]);

use CanvasLMS\Api\Courses\Course;

// Get first page of courses (memory efficient)
$courses = Course::get();

// Get ALL courses across all pages automatically
// ⚠️ Warning: Be cautious with large datasets (1000+ items)
$allCourses = Course::all();

// Get paginated results with metadata (recommended for large datasets)
$paginated = Course::paginate(['per_page' => 50]);
echo "Total courses: " . $paginated->getTotalCount();

// Find a specific course
$course = Course::find(123);

// Create a new course - just pass an array!
$course = Course::create([
    'name' => 'Introduction to PHP',
    'course_code' => 'PHP101',
    'start_at' => '2025-02-01T00:00:00Z'
]);

// Update a course
$course->update([
    'name' => 'Advanced PHP Programming'
]);

// Save changes with fluent interface support
$course->name = 'Updated Course Name';
$course->save()->enrollments(); // Save and immediately get enrollments

// Delete a course (also returns self for chaining)
$course->delete();

use CanvasLMS\Api\Assignments\Assignment;
use CanvasLMS\Api\Submissions\Submission;
use CanvasLMS\Api\Courses\Course;

// Set course context for Assignment
$course = Course::find(123);
Assignment::setCourse($course);

// Create an assignment - simple array syntax
$assignment = Assignment::create([
    'name' => 'Final Project',
    'description' => 'Build a web application',
    'points_possible' => 100,
    'due_at' => '2025-03-15T23:59:59Z',
    'submission_types' => ['online_upload', 'online_url']
]);

// Grade submissions (

use CanvasLMS\Api\Modules\Module;
use CanvasLMS\Api\Modules\ModuleItem;

// Get course and set context
$course = Course::find(123);
Module::setCourse($course);

// Create a module
$module = Module::create([
    'name' => 'Week 1: Introduction',
    'position' => 1,
    'published' => true
]);

// Add items to the module (
]);

// Or use the course instance method (recommended)
$modules = $course->modules();

use CanvasLMS\Api\Users\User;

// Get current authenticated user instance
$currentUser = User::self();

// Canvas supports 'self' for these endpoints:
$profile = $currentUser->getProfile();
$activityStream = $currentUser->getActivityStream();
$todos = $currentUser->getTodoItems();
$groups = $currentUser->groups();

// Other methods 

use CanvasLMS\Api\Groups\Group;
use CanvasLMS\Api\Groups\GroupMembership;

// Create a group in your account
$group = Group::create([
    'name' => 'Study Group Alpha',
    'description' => 'Weekly study sessions',
    'is_public' => false,
    'join_level' => 'invitation_only'
]);

// Add members to the group
$membership = $group->createMembership([
    'user_id' => 456,
    'workflow_state' => 'accepted'
]);

// Get group activity stream
$activities = $group->activityStream();

// Invite users by email
$group->invite(['[email protected]', '[email protected]']);

use CanvasLMS\Api\Files\File;

// Upload a file to a course
$file = File::upload([
    'course_id' => 123,
    'file_path' => '/path/to/document.pdf',
    'name' => 'Course Syllabus.pdf',
    'parent_folder_path' => 'course_documents'
]);

use CanvasLMS\Api\FeatureFlags\FeatureFlag;
use CanvasLMS\Api\Courses\Course;

// Get feature flags for the account
$flags = FeatureFlag::get();     // First page
$allFlags = FeatureFlag::all();  // All flags

// Get a specific feature flag
$flag = FeatureFlag::find('new_gradebook');

// Enable a feature for the account
$flag->enable();

// Disable a feature
$flag->disable();

// Feature flags for a specific course
$course = Course::find(123);
$courseFlags = $course->featureFlags();

// Enable a feature for a specific course
$courseFlag = $course->getFeatureFlag('anonymous_marking');
$courseFlag->enable();

use CanvasLMS\Api\Conversations\Conversation;

// Get conversations for the current user
$conversations = Conversation::get(['scope' => 'unread']); // First page
$allConversations = Conversation::all(['scope' => 'unread']); // All pages

// Create a new conversation
$conversation = Conversation::create([
    'recipients' => ['user_123', 'course_456_students'],
    'subject' => 'Assignment Feedback',
    'body' => 'Great work on your recent submission!',
    'group_conversation' => true
]);

// Add a message to existing conversation
$conversation->addMessage([
    'body' => 'Following up on my previous message...',
    'attachment_ids' => [789] // Attach files
]);

// Manage conversation state
$conversation->markAsRead();
$conversation->star();
$conversation->archive();

// Batch operations
Conversation::batchUpdate([1, 2, 3], ['event' => 'mark_as_read']);
Conversation::markAllAsRead();

// Get unread count
$unreadCount = Conversation::getUnreadCount();

use CanvasLMS\Api\Rubrics\Rubric;
use CanvasLMS\Api\ExternalTools\ExternalTool;
use CanvasLMS\Api\CalendarEvents\CalendarEvent;
use CanvasLMS\Api\Files\File;

// Direct calls default to Account context
$rubrics = Rubric::get();           // Account-level rubrics (first page)
$tools = ExternalTool::get();       // Account-level external tools (first page)
$events = CalendarEvent::get();     // Account-level calendar events (first page)
$files = File::get();               // Exception: User files (no account context)

// Course-specific access through Course instance
$course = Course::find(123);
$courseRubrics = $course->rubrics();            // Course-specific rubrics
$courseTools = $course->externalTools();        // Course-specific tools
$courseEvents = $course->calendarEvents();      // Course-specific events
$courseFiles = $course->files();                // Course-specific files

// Direct context access when needed
$userEvents = CalendarEvent::fetchByContext('user', 456);
$groupFiles = File::fetchByContext('groups', 789);

// ✅ GOOD: Memory-efficient for large datasets
$result = User::paginate(['per_page' => 100]);
while ($result) {
    foreach ($result->getData() as $user) {
        // Process batch of 100 users
    }
    $result = $result->hasNextPage() ? $result->getNextPage() : null;
}

// ✅ GOOD: Get only what you need
$recentCourses = Course::get(['per_page' => 20]); // Just first 20

// ⚠️ CAUTION: Loads entire dataset into memory
$allUsers = User::all();  // Could be 50,000+ users!
$allEnrollments = Enrollment::all(); // Could be millions!

// ⚠️ BETTER: Process in batches for large datasets
$page = 1;
do {
    $batch = Enrollment::paginate(['page' => $page++, 'per_page' => 500]);
    // Process batch
} while ($batch->hasNextPage());

use CanvasLMS\Api\Pages\Page;
use CanvasLMS\Api\Quizzes\Quiz;
use CanvasLMS\Api\Modules\Module;
use CanvasLMS\Api\DiscussionTopics\DiscussionTopic;
use CanvasLMS\Api\Courses\Course;

// Get your course
$course = Course::find(123);

// Option 1: Set context for each API (:get();     // Get first page
$discussions = DiscussionTopic::all(); // Get all discussions

// Option 2: Use course instance methods (recommended - no context setup needed)
$pages = $course->pages();          // Returns first page only
$quizzes = $course->quizzes();      // Returns first page only
$modules = $course->modules();      // Returns first page only
$discussions = $course->discussionTopics(); // Returns first page only

   // Get ALL modules for a course
   Module::setCourse($course);
   $allModules = Module::all();  // Gets all pages
   
   // Or paginate for control
   $paginated = Module::paginate(['per_page' => 50]);
   

use CanvasLMS\Api\Outcomes\Outcome;
use CanvasLMS\Api\OutcomeGroups\OutcomeGroup;

// Create an outcome group
$group = OutcomeGroup::create([
    'title' => 'Critical Thinking Skills',
    'description' => 'Core competencies for analytical thinking'
]);

// Create a learning outcome
$outcome = Outcome::create([
    'title' => 'Analyze Complex Problems',
    'description' => 'Student can break down complex problems into manageable parts',
    'mastery_points' => 3,
    'ratings' => [
        ['description' => 'Exceeds', 'points' => 4],
        ['description' => 'Mastery', 'points' => 3],
        ['description' => 'Near Mastery', 'points' => 2],
        ['description' => 'Below Mastery', 'points' => 1]
    ]
]);

// Link outcome to a group
$group->linkOutcome($outcome->id);

// Align outcome with an assignment
$assignment = Assignment::find(123);
$assignment->alignOutcome($outcome->id, [
    'mastery_score' => 3,
    'possible_score' => 4
]);

use CanvasLMS\Api\Courses\Course;
use CanvasLMS\Api\ContentMigrations\ContentMigration;

// Copy content between courses
$course = Course::find(456);
$migration = $course->copyContentFrom(123, [
    'except' => ['announcements', 'calendar_events']
]);

// Selective copy with specific items
$migration = $course->selectiveCopyFrom(123, [
    'assignments' => [1, 2, 3],
    'quizzes' => ['quiz-1', 'quiz-2'],
    'modules' => [10, 11]
]);

// Import a Common Cartridge file
$migration = $course->importCommonCartridge('/path/to/course.imscc');

// Copy with date shifting
$migration = $course->copyWithDateShift(123, '2024-01-01', '2025-01-01', [
    'shift_dates' => true,
    'old_start_date' => '2024-01-01',
    'new_start_date' => '2025-01-01'
]);

// Track migration progress
while (!$migration->isCompleted()) {
    $progress = $migration->getProgress();
    echo "Migration {$progress->workflow_state}: {$progress->completion}%\n";
    sleep(5);
    $migration->refresh();
}

// Handle migration issues
$issues = $migration->migrationIssues();
foreach ($issues as $issue) {
    if ($issue->workflow_state === 'active') {
        $issue->resolve();
    }
}

// The SDK automatically handles rate limiting and retries
$course = Course::find(123); // Protected by middleware

// Canvas API Rate Limiting (3000 requests/hour)
// ✅ Automatic throttling when approaching limits
// ✅ Smart backoff strategies
// ✅ Transparent to your application

// Manage multiple Canvas instances
Config::setContext('production');
$prodCourse = Course::find(123);

Config::setContext('test');
$testCourse = Course::find(456);

// Three simple methods for all your pagination needs:

// 1. get() - Fetch first page only (fast, memory efficient)
$courses = Course::get(['per_page' => 100]); 

// 2. all() - Fetch ALL items across all pages automatically
$allCourses = Course::all();

// 3. paginate() - Get results with pagination metadata
$result = Course::paginate(['per_page' => 50]);
echo "Page {$result->getCurrentPage()} of {$result->getTotalPages()}";
echo "Total courses: {$result->getTotalCount()}";

// Access the data
foreach ($result->getData() as $course) {
    echo $course->name;
}

// Navigate pages
if ($result->hasNextPage()) {
    $nextPage = $result->getNextPage();
}

// Save and continue working with the object
$course->name = 'New Name';
$enrollments = $course->save()->enrollments();

// Chain multiple operations
$assignment = new Assignment();
$assignment->name = 'Final Project';
$assignment->points_possible = 100;
$submissions = $assignment->save()->getSubmissions();

// Error handling with fluent interface
try {
    $user->email = '[email protected]';
    $user->save()->enrollments(); // Save and get enrollments
} catch (CanvasApiException $e) {
    // Handle error - no more silent failures!
}

// Efficient relationship loading
$course = Course::find(123);
$students = $course->getStudents();
$assignments = $course->assignments();
$modules = $course->modules();

use CanvasLMS\Canvas;

// Follow pagination URLs returned by Canvas
$courses = Course::paginate();
while ($nextUrl = $courses->getNextUrl()) {
    $nextPage = Canvas::get($nextUrl);
    // Process next page data
}

// Call custom or undocumented endpoints
$analytics = Canvas::get('/api/v1/courses/123/analytics');
$customData = Canvas::post('/api/v1/custom/endpoint', [
    'key' => 'value'
]);

// Download files directly
$file = File::find(456);
$content = Canvas::get($file->url);
file_put_contents('download.pdf', $content);

// Process webhook callbacks
$webhookData = json_decode($request->getContent(), true);
$resource = Canvas::get($webhookData['resource_url']);

// All HTTP methods supported
$response = Canvas::get($url);        // GET request
$response = Canvas::post($url, $data); // POST request
$response = Canvas::put($url, $data);  // PUT request
$response = Canvas::delete($url);      // DELETE request
$response = Canvas::patch($url, $data); // PATCH request
$response = Canvas::request($url, 'HEAD'); // Any HTTP method

// Direct API calls use Account context (Config::getAccountId())
$groups = Group::get();              // First page of groups in the account
$allGroups = Group::all();           // All groups in the account
$rubrics = Rubric::get();            // First page of rubrics in the account
$migrations = ContentMigration::all(); // All migrations in the account

// Course-specific access via Course instance methods
$course = Course::find(123);
$courseGroups = $course->groups();              // Groups in this course
$courseRubrics = $course->rubrics();            // Rubrics in this course
$courseMigrations = $course->contentMigrations(); // Migrations in this course

// User-specific access via User instance methods
$user = User::find(456);
$userGroups = $user->groups();                    // User's groups
$userMigrations = $user->contentMigrations();    // User's migrations

// Group-specific access via Group instance methods
$group = Group::find(789);
$groupMigrations = $group->contentMigrations();  // Group's migrations