A Laravel package for managing social media service providers (SMM) with an extensible provider architecture. This package allows you to integrate multiple social media service providers into your Laravel application.
- Extensible Provider Architecture: Easily add new service providers by extending the
AbstractProviderclass - SMM Provider Included: Ready-to-use SMM (Social Media Marketing) provider for services like likes, views, and comments
- Order Management: Built-in
OrderServicefor managing orders across providers - Request Definitions: Structured HTTP request handling with validation
- Status Synchronization: Sync order statuses between your application and external providers
- Cancel Order: Opt-out pushed order from the provider
- PHP ^8.0.2
- Composer
- Laravel ^9.0|^10.0|^11.0
If you don't have PHP and Composer installed:
Using Homebrew:
# Install Homebrew if you don't have it
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install PHP
brew install php
# Install Composer
brew install composerOr download Composer directly:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/local/bin/composercomposer require rexatgithub/istoy# Publish configuration
php artisan vendor:publish --tag=istoy-config
# Publish migration (optional - see Order Model Setup below)
php artisan vendor:publish --tag=istoy-migrationsThis will publish:
- Configuration file to
config/istoy.php - Migration file to
database/migrations/(if you choose to publish it)
Add these to your .env file:
SMM_PROVIDER_HOST=https://smmlite.com/api/v2
SMM_PROVIDER_KEY=your_api_key_here
ISTOY_ORDER_MODEL=App\Models\OrderYour Order model must have the following required columns. The package provides a migration to help you set this up.
If you don't have an orders table yet, or want to add the required columns:
-
Publish the migration:
php artisan vendor:publish --tag=istoy-migrations
-
Run the migration:
php artisan migrate
The migration will:
- Create the
orderstable with all required columns if it doesn't exist - Add missing columns to an existing
orderstable if it already exists - Safely skip columns that already exist
If you already have an orders table with different structure, you can manually add the required columns:
Required columns:
external_id(string/int, nullable) - ID from the external providerservice(int, nullable) - Service IDlink(string, required) - URL to the social media postquantity(int, required) - Quantity of services to orderstatus(string, default: 'pending') - Order statusstart_count(int, default: 0) - Starting countremains(int, default: 0) - Remaining count
Example migration:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('orders', function (Blueprint $table) {
if (!Schema::hasColumn('orders', 'external_id')) {
$table->string('external_id')->nullable()->after('id');
}
if (!Schema::hasColumn('orders', 'service')) {
$table->integer('service')->nullable()->after('external_id');
}
if (!Schema::hasColumn('orders', 'link')) {
$table->string('link')->after('service');
}
if (!Schema::hasColumn('orders', 'quantity')) {
$table->integer('quantity')->after('link');
}
if (!Schema::hasColumn('orders', 'status')) {
$table->string('status')->default('pending')->after('quantity');
}
if (!Schema::hasColumn('orders', 'start_count')) {
$table->integer('start_count')->default(0)->after('status');
}
if (!Schema::hasColumn('orders', 'remains')) {
$table->integer('remains')->default(0)->after('start_count');
}
});
}
public function down(): void
{
// Optionally remove columns if needed
// Be careful not to lose data!
}
};Your Order model should implement the following:
-
Use the
HasIstoyFieldstrait (Recommended):The easiest way is to use the provided trait which automatically adds all required fields to your
$fillablearray:use Istoy\Traits\HasIstoyFields; use Istoy\Contracts\OrderContract; class Order extends Model implements OrderContract { use HasIstoyFields; // Your other model code... // The fillable fields are automatically added! }
Or manually add to
$fillable(if you prefer):If you don't want to use the trait, you can manually add these fields to your
$fillablearray:external_idservicelinkquantitystatusstart_countremains
-
Implement a scope for finding by external ID:
use Illuminate\Database\Eloquent\Builder;
public function scopeWithExternalId(Builder $query, $externalId): Builder
{
return $query->where(['external_id' => $externalId]);
}- Optionally implement the
OrderContractinterface:
use Istoy\Contracts\OrderContract;
use Istoy\Traits\HasIstoyFields;
class Order extends Model implements OrderContract
{
use HasIstoyFields;
// All Istoy fields are automatically fillable!
// You can still add your own fillable fields if needed
}Complete Example:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Istoy\Contracts\OrderContract;
use Istoy\Traits\HasIstoyFields;
use Istoy\Models\Enums\OrderStatuses;
class Order extends Model implements OrderContract
{
use HasIstoyFields;
protected $fillable = [
// Your custom fields here (Istoy fields are added automatically)
'user_id',
'payment_status',
];
protected $casts = [
'status' => OrderStatuses::class,
];
public function scopeWithExternalId(Builder $query, $externalId): Builder
{
return $query->where('external_id', $externalId);
}
}use Istoy\Services\OrderService;
use App\Models\Order;
$order = Order::find(1);
$orderService = new OrderService($order);
// Start the order (pushes to provider)
$success = $orderService->start();
// Start with interval (in minutes)
$success = $orderService->start(interval: 5);use Istoy\Services\OrderService;
$orderService = new OrderService($order);
$orderService->syncStatuses();use Istoy\Services\OrderService;
$orderService = new OrderService($order);
$orderService->cancel();use Istoy\Providers\Factory;
use App\Models\Order;
$order = Order::find(1);
$provider = Factory::create($order);
// Add order to provider
$provider->add();
// Add with interval
$provider->add(interval: 10);
// Check statuses
$provider->statuses();
// Cancel Order
$provider->cancel();use Istoy\Providers\Smm\Service;
use App\Models\Order;
$order = Order::find(1);
$smmService = new Service($order);
$smmService->add(interval: 5);
$smmService->statuses();
$smmService->cancel();To create a custom provider:
- Extend the
AbstractProviderclass:
namespace App\Providers\Custom;
use Istoy\Providers\AbstractProvider;
use Istoy\Providers\Factory;
class CustomProvider extends AbstractProvider
{
public function getId(): int
{
return 2; // Your provider ID
}
public function add(?int $interval = null): void
{
// Implement your add logic
}
public function statuses(): void
{
// Implement your status check logic
}
public function cancel(): void
{
// Implement your status check logic
}
}- Register your provider:
use Istoy\Providers\Factory;
use App\Providers\Custom\CustomProvider;
Factory::register(2, CustomProvider::class);- Use it:
$provider = Factory::create($order, providerId: 2);The package includes the following order statuses:
Pending- Order is pendingInProgress- Order is in progressCancelled- Order is cancelledCompleted- Order is completedPaused- Order is paused
The package includes a comprehensive test suite using PHPUnit and Orchestra Testbench.
Important: You must install dependencies before running tests.
First, install development dependencies:
composer installOnce dependencies are installed, you can run tests:
# Run all tests (recommended)
composer test
# Or run PHPUnit directly
vendor/bin/phpunit
# Run tests with coverage
composer test-coverage
# Or run PHPUnit with coverage directly
vendor/bin/phpunit --coverage-html coverageThe test suite includes:
- Unit Tests: Tests for individual components
- Enums (Statuses)
- Factory pattern for provider creation
- OrderService for order management
- SMM Service provider
- Request definitions (Add, Status)
- Generic request definition base classes
The tests cover:
- Provider registration and factory pattern
- Order creation and status synchronization
- Request definition validation
- Enum functionality and mappings
- Error handling and edge cases
MIT
For issues and feature requests, please use the GitHub issue tracker.