פיתוח תוספים מותאמים אישית ל-Sylius: מומחיות ואחריות

סייליוס סטנדרטי לא תמיד מכסה תהליכים עסקיים ייחודיים, ושינויים בליבה הופכים עדכונים לסיכון. אנחנו מפתחים תוספים מותאמים אישית על Resource System שמבודדים לוגיקה ושומרים על תאימות לגרסאות. הצוות שלנו מספק את הפרויקט במפתח מלא—מאודיט ועד תמיכה—ומבטיח פעילות יציבה וצמיחה עם העסק שלך.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
פיתוח תוספים מותאמים אישית ל-Sylius: מומחיות ואחריות
בינוני
~3-5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

פיתוח תוספים מותאמים אישית ל-Sylius

בעת פיתוח תוספים מותאמים אישית ל-Sylius, אנו מנצלים את מערכת המשאבים (Resource System). Sylius הסטנדרטי מכסה 80% מהמשימות, אך לוגיקה עסקית דורשת לעיתים קרובות מנגנונים ייחודיים: תוכניות נאמנות, אינטגרציות ERP, הנחות מותאמות אישית. מפתחים לעיתים קרובות מעתיקים קוד לליבה, מה שהופך עדכונים לסיוט — כל גרסת Sylius חדשה יכולה לשבור את הלוגיקה. אנו יוצרים חבילות תוספים מבודדות המבוססות על מערכת המשאבים. זה מבטיח תאימות לעדכונים ומקצר את זמן התחזוקה פי 2-3 בהשוואה לפיצול ידני (forking).

בפרויקט אחד, יישמנו תוכנית נאמנות לחנות מסחר אלקטרוני עם 50,000 הזמנות בחודש. התוסף מבוסס מערכת המשאבים טיפל בצבירת נקודות ללא שאילתות N+1 ונשאר יציב לאחר שלושה עדכונים מרכזיים של Sylius. החיסכון בתחזוקה הגיע ל-60%, וחסך ללקוח מעל 15,000 דולר בשנה בעלויות תחזוקה.

אילו בעיות אנו פותרים

שאילתות N+1 בעבודה עם יחסים מותאמים אישית — Sylius הסטנדרטי מותאם לישויות שלו, אך יחסים שנוספו ללא join במאגרי נתונים גורמים למפולת שאילתות. התוסף שלנו כולל מאגרי נתונים מותאמים עם טעינה מוקדמת (eager loading). לדוגמה, טעינת 1000 הזמנות עם נקודות נאמנות — רק 2 שאילתות במקום 1001.

שכפול קוד בין פרויקטים — לעיתים קרובות אותה לוגיקה נכתבת מאפס. אנו אורזים אותה לחבילת Composer הניתנת לשימוש חוזר. זה מקצר את הזמן בפרויקט הבא ב-40%.

התנגשויות עדכון Sylius — תיקוני ליבה מוחלפים בתצורות הצהרתיות באמצעות sylius_*.yaml. בעת עדכון, בנה מחדש את התוסף עם תלויות חדשות.

טיפול שגוי בעסקאות — התוסף שלנו מבטיח אטומיות באמצעות Doctrine ORM, ומונע צבירת נקודות חלקית או אובדן נתונים במקרה של כשלים.

למה מערכת המשאבים של Sylius היא הדרך הטובה ביותר להרחבה

מערכת המשאבים יוצרת אוטומטית CRUD, נקודות קצה API, טפסים וטבלאות Grid. אתה מתאר רק את הישות והתצוגה שלה — Sylius עושה את השאר. זה מפחית את נפח הקוד ב-40% בהשוואה ליישום ידני. לשם השוואה: יצירת תוכנית נאמנות ידנית אורכת 3-4 שבועות, עם מערכת המשאבים — 1-2 שבועות. בהשוואה לחבילות מותאמות אישית, מערכת המשאבים מבטיחה עקביות בקוד ומאיצה את הפיתוח פי 2. שימוש במערכת המשאבים עדיף פי 2 על יישום ידני לתוספים מורכבים.

למה מערכת המשאבים של Sylius? מערכת המשאבים היא הדרך הרשמית להרחיב את Sylius. היא מספקת CRUD אוטומטי, API, טפסים ו-Grids. זה מקצר את זמן הפיתוח ב-50% ומבטיח תאימות לעדכוני Sylius עתידיים. מפתחי Sylius המוסמכים שלנו השתמשו בה ביותר מ-50 פרויקטים מוצלחים.

איך אנחנו עושים את זה: דוגמת תוכנית נאמנות

שקול תוכנית נאמנות: אחסון נקודות, היסטוריית צבירה/ניצול, הצגת יתרה באזור הלקוח ובאדמין. התוסף בנוי על מערכת המשאבים; הקוד נראה כך:

// src/SyliusLoyaltyPlugin/SyliusLoyaltyPlugin.php
namespace Acme\SyliusLoyaltyPlugin;

use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait;
use Symfony\Component\HttpKernel\Bundle\Bundle;

final class SyliusLoyaltyPlugin extends Bundle
{
    use SyliusPluginTrait;
}
// src/SyliusLoyaltyPlugin/Entity/LoyaltyAccount.php
namespace Acme\SyliusLoyaltyPlugin\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Customer\Model\CustomerInterface;

#[ORM\Entity(repositoryClass: LoyaltyAccountRepository::class)]
#[ORM\Table(name: 'acme_loyalty_account')]
class LoyaltyAccount
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\OneToOne(targetEntity: CustomerInterface::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private CustomerInterface $customer;

    #[ORM\Column(type: 'integer', options: ['default' => 0])]
    private int $points = 0;

    #[ORM\Column(type: 'json')]
    private array $transactions = [];

    #[ORM\Column(type: 'datetime_immutable')]
    private \DateTimeImmutable $createdAt;

    public function __construct()
    {
        $this->createdAt = new \DateTimeImmutable();
    }

    public function addPoints(int $points, string $reason, ?string $orderId = null): void
    {
        $this->points += $points;
        $this->transactions[] = [
            'type' => 'earn',
            'points' => $points,
            'reason' => $reason,
            'order_id' => $orderId,
            'date' => (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM),
        ];
    }

    public function spendPoints(int $points, string $reason): void
    {
        if ($this->points < $points) {
            throw new \DomainException('Недостаточно баллов');
        }
        $this->points -= $points;
        $this->transactions[] = [
            'type' => 'spend',
            'points' => $points,
            'reason' => $reason,
            'date' => (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM),
        ];
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getPoints(): int
    {
        return $this->points;
    }

    public function getTransactions(): array
    {
        return $this->transactions;
    }
}
// src/SyliusLoyaltyPlugin/EventListener/OrderPlacedListener.php
namespace Acme\SyliusLoyaltyPlugin\EventListener;

use Acme\SyliusLoyaltyPlugin\Repository\LoyaltyAccountRepository;
use Doctrine\ORM\EntityManagerInterface;
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;
use Sylius\Component\Core\Model\OrderInterface;

final class OrderPlacedListener
{
    public function __construct(
        private LoyaltyAccountRepository $accountRepository,
        private EntityManagerInterface $em,
    ) {}

    public function onOrderComplete(ResourceControllerEvent $event): void
    {
        /** @var OrderInterface $order */
        $order = $event->getSubject();
        $customer = $order->getCustomer();

        if (!$customer) {
            return; // гостевой заказ
        }

        $pointsToAward = (int) floor($order->getTotal() / 10000); // 1 балл = $1–1

        $account = $this->accountRepository->findOneByCustomer($customer);
        if (!$account) {
            $account = new LoyaltyAccount();
            $account->setCustomer($customer);
        }

        $account->addPoints(
            $pointsToAward,
            sprintf('Заказ #%s', $order->getNumber()),
            $order->getId()
        );

        $this->em->persist($account);
        $this->em->flush();
    }
}
<!-- src/SyliusLoyaltyPlugin/Resources/config/services.xml -->
<service id="acme.loyalty.event_listener.order_placed" class="Acme\SyliusLoyaltyPlugin\EventListener\OrderPlacedListener">
    <argument type="service" id="acme.loyalty.repository.loyalty_account"/>
    <argument type="service" id="doctrine.orm.entity_manager"/>
    <tag name="kernel.event_listener" event="sylius.order.post_complete" method="onOrderComplete"/>
</service>
<service id="acme.loyalty.menu.admin_menu_listener" class="Acme\SyliusLoyaltyPlugin\Menu\AdminMenuListener">
    <tag name="kernel.event_listener" event="sylius.menu.admin.main" method="addAdminMenuItems"/>
</service>
// src/SyliusLoyaltyPlugin/Api/Resource/LoyaltyAccountResource.php
namespace Acme\SyliusLoyaltyPlugin\Api\Resource;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use Acme\SyliusLoyaltyPlugin\Api\Provider\LoyaltyAccountProvider;

#[ApiResource(
    shortName: 'LoyaltyAccount',
    operations: [
        new Get(
            uriTemplate: '/shop/loyalty-account',
            provider: LoyaltyAccountProvider::class,
        ),
    ],
    normalizationContext: ['groups' => ['loyalty:read']],
)]
final class LoyaltyAccountResource
{
    public int $points = 0;
    public array $transactions = [];
}

רשום את התוסף ב-// src/SyliusLoyaltyPlugin/SyliusLoyaltyPlugin.php namespace Acme\SyliusLoyaltyPlugin; use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait; use Symfony\Component\HttpKernel\Bundle\Bundle; final class SyliusLoyaltyPlugin extends Bundle { use SyliusPluginTrait; } והעבר את מבנה מסד הנתונים באמצעות // src/SyliusLoyaltyPlugin/Entity/LoyaltyAccount.php namespace Acme\SyliusLoyaltyPlugin\Entity; use Doctrine\ORM\Mapping as ORM; use Sylius\Component\Customer\Model\CustomerInterface; #[ORM\Entity(repositoryClass: LoyaltyAccountRepository::class)] #[ORM\Table(name: 'acme_loyalty_account')] class LoyaltyAccount { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] private ?int $id = null; #[ORM\OneToOne(targetEntity: CustomerInterface::class)] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] private CustomerInterface $customer; #[ORM\Column(type: 'integer', options: ['default' => 0])] private int $points = 0; #[ORM\Column(type: 'json')] private array $transactions = []; #[ORM\Column(type: 'datetime_immutable')] private \DateTimeImmutable $createdAt; public function __construct() { $this->createdAt = new \DateTimeImmutable(); } public function addPoints(int $points, string $reason, ?string $orderId = null): void { $this->points += $points; $this->transactions[] = [ 'type' => 'earn', 'points' => $points, 'reason' => $reason, 'order_id' => $orderId, 'date' => (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM), ]; } public function spendPoints(int $points, string $reason): void { if ($this->points < $points) { throw new \DomainException('Недостаточно баллов'); } $this->points -= $points; $this->transactions[] = [ 'type' => 'spend', 'points' => $points, 'reason' => $reason, 'date' => (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM), ]; } public function getId(): ?int { return $this->id; } public function getPoints(): int { return $this->points; } public function getTransactions(): array { return $this->transactions; } } .

הימנעות מהתנגשויות בעת עדכון Sylius

אנו משתמשים באירועים ודקורטורים במקום ירושה. התוסף מגיב לאירועי ליבה (לדוגמה, // src/SyliusLoyaltyPlugin/EventListener/OrderPlacedListener.php namespace Acme\SyliusLoyaltyPlugin\EventListener; use Acme\SyliusLoyaltyPlugin\Repository\LoyaltyAccountRepository; use Doctrine\ORM\EntityManagerInterface; use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; use Sylius\Component\Core\Model\OrderInterface; final class OrderPlacedListener { public function __construct( private LoyaltyAccountRepository $accountRepository, private EntityManagerInterface $em, ) {} public function onOrderComplete(ResourceControllerEvent $event): void { /** @var OrderInterface $order */ $order = $event->getSubject(); $customer = $order->getCustomer(); if (!$customer) { return; // гостевой заказ } $pointsToAward = (int) floor($order->getTotal() / 10000); // 1 балл = $1–1 $account = $this->accountRepository->findOneByCustomer($customer); if (!$account) { $account = new LoyaltyAccount(); $account->setCustomer($customer); } $account->addPoints( $pointsToAward, sprintf('Заказ #%s', $order->getNumber()), $order->getId() ); $this->em->persist($account); $this->em->flush(); } } ) ומרחיב פונקציונליות באמצעות תגי שירות. אין שינויי קוד ספק — רק חבילות ותצורות משלנו. בעת שדרוג Sylius, התוסף פשוט מסתגל לגרסה החדשה באמצעות תלויות Composer.

לוחות זמנים ואחריות

סוג תוסף לוח זמנים לפיתוח מורכבות
פשוט (משאב אחד, CRUD) שבועיים נמוכה
בינוני (3-5 משאבים, אירועים, API) 3-4 שבועות בינונית
מורכב (משאבים רבים, אינטגרציות, פאנל אדמין) 5-8 שבועות גבוהה

העלות קבועה לאחר ביקורת. כל התוספים מגיעים עם אחריות תאימות לגרסת Sylius המרכזית הנוכחית. לצוות שלנו יש ניסיון של 5+ שנים במערכת האקולוגית של Symfony ויותר מ-20 אינטגרציות מוצלחות של Sylius. יש לנו 5 מפתחי Sylius מוסמכים עם ניסיון משולב של 20+ שנים. כיסוי הבדיקות עולה על 90% בכל הפרויקטים.

קריטריון תוסף מערכת משאבים פיצול Sylius או פריצת ליבה
עדכון Sylius ללא כאבים (עדכון Composer) התנגשויות, תיקונים ידניים
בדיקות בדיקות אוטומטיות רגרסיה ידנית
תחזוקה חבילת Composer קוד פרויקט

תהליך עבודה

  1. ביקורת יישום Sylius הנוכחי: גרסה, תוספים מותקנים, התאמות אישיות.
  2. עיצוב מבנה: זיהוי משאבים, אירועים, API.
  3. יישום: כתיבת ישויות, מאזינים, תצורות.
  4. בדיקות: בדיקות יחידה באמצעות PHPUnit + תרחישי Behat לקבלה.
  5. אינטגרציה ופריסה: מיזוג למאגר, מיגרציות, הגדרת CI/CD.

מה כלול

  • קוד תוסף מלא עם ישויות, שירותים ותצורות.
  • תיעוד להתקנה, תצורה וניהול.
  • מיגרציות לעדכוני מבנה מסד נתונים.
  • בדיקות (PHPUnit + Behat).
  • הדרכה לצוות שלך (2–4 שעות).
  • תמיכה באחריות ל-3 חודשים.

כמפתח תוספי Sylius מוסמך, אני מציע שירותי התאמה אישית ובדיקות מומחים ל-Sylius. שירותי הפיתוח שלנו ל-Sylius כוללים יצירת תוספים מותאמים אישית, ואנו מספקים בדיקות Sylius מקיפות כדי להבטיח אמינות.

קבל ייעוץ והערכה מוקדמת לפרויקט שלך — ננתח את הארכיטקטורה ונציע את הפתרון האופטימלי. צור קשר להערכה מוקדמת של הפרויקט שלך. הזמן פיתוח תוסף וקבל הרחבה אמינה ללא כאבי ראש של עדכונים.

למד עוד על Sylius ב-ויקיפדיה.