PHP-DbHandler هي مكتبة PHP مصممة لتبسيط التفاعلات مع قواعد بيانات MySQL. وهو يقدم مجموعة شاملة من الأدوات لبناء وتنفيذ الاستعلامات وإدارة المعاملات والتعامل مع مخطط قاعدة البيانات من خلال اتصالات PDO.
Where
و Having
الجمل".or
و and
المشغلينتثبيت الحزمة عبر Composer:
composer require tribal2/db-handler
ابدأ بإنشاء مثيل Db
:
use Tribal2 DbHandler Core PDOWrapper ;
use Tribal2 DbHandler Db ;
use Tribal2 DbHandler DbConfig ;
$ config = DbConfig:: create ( ' my_database ' )
-> withUser ( ' username ' )
-> withPassword ( ' password ' )
-> withHost ( ' localhost ' ) // Optional. Default: 'localhost'
-> withPort ( 3306 ) // Optional. Default: 3306
-> withCharset ( ' utf8mb4 ' ); // Optional. Default: 'utf8mb4'
$ pdoWrapper = new PDOWrapper (
$ config ,
// Optional PsrLogLoggerInterface instance.
// $logger, // Default: PsrLogNullLogger
);
$ db = new Db (
$ pdoWrapper ,
// Optional PsrSimpleCacheCacheInterface instance.
// $cache, // Default: NULL
);
Where
و Having
الجمل".توفر فئة Where طريقة مرنة وبديهية لإنشاء شروط الاستعلام. وهو يدعم مجموعة متنوعة من عوامل المقارنة والعوامل المنطقية، مما يسمح لك بتحديد معايير اختيار البيانات أو تصفيتها من قاعدة البيانات الخاصة بك بدقة.
تقوم الطرق بإرجاع كائن Where الذي يغلف الشرط، بالإضافة إلى قيمة ذات معلمات للاستعلام الآمن والفعال.
لا تعمل عبارات Where على تبسيط بناء جملة الاستعلام فحسب، بل تعمل أيضًا على تحسين الأمان من خلال إدارة المخاطر المرتبطة بإدخال SQL داخليًا. تقوم هذه المكتبة تلقائيًا باستبدال القيم بمعلمات PDO المسماة وتقوم بالربط باستخدام أنواع بيانات PDO المناسبة. ومن خلال التعامل مع هذه الجوانب الحاسمة، فإنه يضمن أن استفساراتك ليست نظيفة وقابلة للصيانة فحسب، بل آمنة أيضًا.
لم تعد بحاجة إلى القلق بشأن تنظيف مدخلاتك يدويًا لاستعلامات قاعدة البيانات. تعتني المكتبة بإعداد البيانات بطريقة تحمي من حقن SQL، وهي إحدى الثغرات الأمنية الأكثر شيوعًا في التطبيقات المعتمدة على قواعد البيانات. يتيح لك هذا الأسلوب التركيز على منطق الأعمال الخاص بالتطبيق الخاص بك، مع الثقة في أن تفاعلات قاعدة البيانات يتم التعامل معها بأمان وكفاءة.
$ where = Where:: equals ( ' status ' , ' active ' );
// Output: `status` = :status___1
$ where = Where:: notEquals ( ' category ' , ' archived ' );
// Output: `category` <> :category___1
$ where = Where:: greaterThan ( ' price ' , 100 );
// Output: `price` > :price___1
$ where = Where:: greaterThanOrEquals ( ' price ' , 100 );
// Output: `price` >= :price___1
$ where = Where:: lessThan ( ' price ' , 50 );
// Output: `price` < :price___1
$ where = Where:: lessThanOrEquals ( ' price ' , 50 );
// Output: `price` <= :price___1
$ where = Where:: isNull ( ' description ' );
// Output: `description` IS NULL
$ whereNotNull = Where:: isNotNull ( ' description ' );
// Output: Output: `description` IS NOT NULL
$ where = Where:: like ( ' name ' , ' %Apple% ' );
// Output: `name` LIKE :name___1
$ where = Where:: notLike ( ' name ' , ' %Apple% ' );
// Output: `name` NOT LIKE :name___1
$ where = Where:: between ( ' date ' , ' 2021-01-01 ' , ' 2021-12-31 ' );
// Output: `date` BETWEEN :date___1 AND :date___2
$ where = Where:: notBetween ( ' date ' , ' 2021-01-01 ' , ' 2021-12-31 ' );
// Output: `date` NOT BETWEEN :date___1 AND :date___2
$ where = Where:: in ( ' status ' , [ ' active ' , ' pending ' , ' on-hold ' ]);
// Output: `status` IN (:status___1, :status___2, :status___3)
$ where = Where:: notIn ( ' status ' , [ ' active ' , ' pending ' , ' on-hold ' ]);
// Output: `status` NOT IN (:status___1, :status___2, :status___3)
or
و and
المشغلين $ where1 = Where:: equals ( ' status ' , ' active ' );
$ where2 = Where:: greaterThan ( ' price ' , 100 );
$ orWhere = Where:: or ( $ where1 , $ where2 );
// Output: (`status` = :status___1 OR `price` > :price___1)
$ andWhere = Where:: and ( $ where1 , $ where2 );
// Output: (`status` = :status___1 AND `price` > :price___1)
يمكنك أيضًا تداخل عوامل التشغيل
or
and
:
$ where3 = Where:: equals ( ' category ' , ' archived ' );
$ combinedWhere = Where:: and ( $ where3 , $ orWhere );
// Output: (`category` = :category___1 AND (`status` = :status___1 OR `price` > :price___1))
في الأقسام الفرعية التالية، سوف نستكشف كيفية إنشاء وتنفيذ الاستعلامات باستخدام هذه المكتبة. من أجل التبسيط، سنفترض أن المتغير $db
هو مثيل لفئة Db
.
في جميع الأمثلة أدناه، قمنا بفصل بناء الاستعلام عن التنفيذ. يسمح لك هذا الأسلوب بإعادة استخدام كائن الاستعلام وتنفيذه عدة مرات باستخدام معلمات مختلفة، ولكن يمكنك أيضًا ربط الأساليب لإنشاء الاستعلام وتنفيذه في عبارة واحدة مثل هذا:
$ results = $ db
-> select ()
-> columns ([ ' column1 ' , ' column2 ' ])
-> from ( ' table_name ' )
-> where (Where:: equals ( ' column2 ' , 1 ))
-> fethAll ();
$ select = $ db -> select ()
-> columns ([ ' column1 ' , ' column2 ' ])
-> column ( ' column3 ' )
-> from ( ' table_name ' )
-> where (Where:: equals ( ' column2 ' , 1 )) // See "Where Clauses" section above
-> groupBy ( ' column1 ' )
-> having (Where:: equals ( ' sum(column2) ' , 5 ))
-> orderBy ( ' column3 ' , ' ASC ' )
-> limit ( 10 )
-> offset ( 5 );
$ sql = $ select -> getSql ();
// $sql:
// SELECT
// `column1`,
// `column2`,
// `column3`
// FROM
// `table_name`
// WHERE
// `column2` = :column2___1
// GROUP BY
// `column1`
// HAVING
// `sum(column2)` = :sum_column2____1
// ORDER BY
// `column3` ASC
// LIMIT
// 10
// OFFSET
// 5;
جلب النتائج:
افتراضيًا، تقوم طريقة fetchAll()
بإرجاع مصفوفة من الكائنات (باستخدام PDO::FETCH_OBJ
افتراضيًا)، حيث يمثل كل كائن صفًا من البيانات. يمكنك أيضًا جلب النتائج كمصفوفة من المصفوفات الترابطية عن طريق تمرير الثابت PDO::FETCH_ASSOC
كوسيطة لأسلوب منشئ fetchMethod()
قبل تنفيذ الاستعلام.
$ allResults = $ select -> fetchAll ();
$ firstResult = $ select -> fetchFirst ();
$ column1Values = $ select -> fetchColumn ( ' column1 ' );
$ column3DistinctValues = $ select -> fetchDistincts ( ' column3 ' );
// Output: object(FetchResult) {
// data => array(n) {
// [0]...
// [1]...
// [n-1]...
// },
// count => int(n)
// }
يمكنك أيضًا جلب عدد النتائج باستخدام:
$ countResults = $ select -> fetchCount ();
// Output: 5
ترقيم الصفحات:
يعد التعامل بكفاءة مع مجموعات البيانات الكبيرة وتوفير واجهة سهلة الاستخدام لتنقل البيانات أمرًا ضروريًا لأي تطبيق قوي. تعمل ميزة ترقيم الصفحات في PHP-DbHandler على تلبية هذه الاحتياجات بشكل أنيق. فهو يبسط عملية تقسيم بياناتك إلى أجزاء أو "صفحات" يمكن التحكم فيها، مما يسهل العمل مع مجموعات البيانات الكبيرة دون إرباك النظام أو المستخدم.
إعداد ترقيم الصفحات
هناك طريقتان لإعداد ترقيم الصفحات لاستفساراتك:
استخدام طريقة ترقيم الصفحات: تتيح لك هذه الطريقة تحديد عدد العناصر لكل صفحة بطريقة موجزة. إنها طريقة فعالة لإعداد الاستعلام الخاص بك لترقيم الصفحات.
$ select = $ db -> select ()
-> from ( ' table_name ' )
// ...
-> paginate (itemsPerPage: 10 );
تعيين الحد والإزاحة يدويًا: لمزيد من التحكم، يمكنك تحديد الحد (عدد العناصر في كل صفحة) والإزاحة (نقطة البداية في مجموعة البيانات) يدويًا لاستعلامك.
$ select = $ db -> select ()
-> from ( ' table_name ' )
// ...
-> limit ( 10 )
-> offset ( 0 );
جلب النتائج مع ترقيم الصفحات
بمجرد إعداد ترقيم الصفحات، يمكنك جلب النتائج بطرق مختلفة، والتنقل عبر مجموعة البيانات الخاصة بك بسهولة:
fetchPage(?int $page)
: جلب صفحة حالية أو محددة.fetchNextPage()
: جلب النتائج للصفحة التالية.fetchPreviousPage()
: جلب النتائج للصفحة السابقة.fetchFirstPage()
: جلب النتائج للصفحة الأولى.fetchLastPage()
: جلب النتائج للصفحة الأخيرة. تقوم كل من هذه الطرق بإرجاع كائن FetchPaginatedResult
، الذي يحتوي على الخصائص التالية:
data
: مجموعة من السجلات الموجودة في الصفحة الحالية.count
: إجمالي عدد السجلات في مجموعة البيانات.page
: رقم الصفحة الحالية.perPage
: عدد السجلات في كل صفحة.totalPages
: إجمالي عدد الصفحات. // Example output structure of FetchPaginatedResult
object (FetchPaginatedResult) {
data => array (n) {
[ 0 ]. . .
[ 1 ]. . .
[n- 1 ]. . .
},
count => int(n),
page => int( 10 ),
perPage => int( 10 ),
totalPages => int( 23 )
}
يضمن نظام ترقيم الصفحات هذا في PHP-DbHandler أنه يمكنك إدارة مجموعات البيانات الكبيرة والتنقل خلالها بشكل فعال، مما يعزز الأداء العام وتجربة المستخدم للتطبيق الخاص بك.
التخزين المؤقت:
في التطبيقات المعتمدة على البيانات اليوم، تعد الكفاءة والأداء أمرًا أساسيًا. لتعزيز هذه الجوانب في تفاعلات قاعدة البيانات، تتضمن المكتبة ميزة التخزين المؤقت ضمن استعلامات Select
الخاصة بها. تعمل هذه الميزة على تعزيز الأداء عن طريق تخزين نتائج الاستعلام مؤقتًا، وبالتالي تقليل تحميل قاعدة البيانات وتحسين أوقات الاستجابة للاستعلامات التي يتم تنفيذها بشكل متكرر. والأهم من ذلك، أنه مصمم ليكون متوافقًا تمامًا مع معيار PSR-16 (ذاكرة التخزين المؤقتة البسيطة)، مما يضمن التوافق والمرونة على نطاق واسع.
التخزين المؤقت المتوافق مع PSR-16
تقبل وظيفة التخزين المؤقت ضمن استعلامات التحديد أي مثيل لذاكرة التخزين المؤقت يقوم بتنفيذ PsrSimpleCacheCacheInterface. ويعني هذا التوافق مع معايير PSR-16 أنه يمكنك بسلاسة دمج مجموعة واسعة من مكتبات التخزين المؤقت التي تلتزم بهذه الواجهة، مما يوفر لك المرونة لاختيار حل التخزين المؤقت الذي يناسب احتياجات تطبيقك على أفضل وجه.
PsrSimpleCacheCacheInterface
عند تهيئة فئة Db
، فيمكنك تخطي هذه الخطوة. إذا لم تقم بذلك، يمكنك استخدام طريقة setCache
: $ select = $ db -> select ()-> setCache ( $ simpleCacheInstance );
ملحوظات:
- إذا لم تقم بتوفير مثيل ذاكرة التخزين المؤقت عند تهيئة فئة
Db
، فيجب عليك تعيينه لكل استعلامSelect
تريد تخزينه مؤقتًا.- يمكنك أيضًا استخدام هذه الطريقة إذا كنت تريد تعيين مثيل محدد لذاكرة التخزين المؤقت لاستعلام
Select
. يتيح لك هذا استخدام حلول تخزين مؤقت مختلفة لاستعلامات مختلفة، اعتمادًا على احتياجات التطبيق الخاص بك.
withCache
. يمكنك تحديد قيمة إرجاع افتراضية لإدخالات ذاكرة التخزين المؤقت المفقودة وTTL (مدة البقاء) للبيانات المخزنة مؤقتًا. $ select -> withCache (defaultValue, ttl);
ملحوظات:
- الوسيطة
defaultValue
اختيارية. إذا لم يتم توفيرها، فسوف تقوم المكتبة بإرجاعNULL
لإدخالات ذاكرة التخزين المؤقت المفقودة.- الوسيطة
ttl
اختيارية. إذا لم يتم توفيرها، فستستخدم المكتبة قيمة TTL التي تم تعيينها بواسطة مثيل PsrSimpleCache.
$ allResults = $ select -> fetchAll ();
$ firstResult = $ select -> fetchFirst ();
$ column1Values = $ select -> fetchColumn ( ' column1 ' );
$ column3DistinctValues = $ select -> fetchDistincts ( ' column3 ' );
الفوائد الرئيسية
تعمل فئة Insert
في مكتبة PHP-DbHandler على تبسيط عملية إنشاء وتنفيذ استعلامات الإدراج في قاعدة البيانات. توفر هذه الفئة، المجهزة بسمات وواجهات متعددة، أسلوبًا متطورًا للتعامل مع عمليات الإدراج بميزات متقدمة متنوعة.
توليد الاستعلام
Insert
بتعيين القيم ديناميكيًا للأعمدة لإدراجها. يمكنك إضافة قيمة واحدة أو قيم متعددة مرة واحدة: $ insert = $ db -> insert ()
-> into ( ' table_name ' )
-> value ( ' column1 ' , ' value1 ' )
-> values ([ ' column2 ' => ' value2 ' , ' column3 ' => ' value3 ' ]);
سيتحقق الفصل من وجود العمود في الجدول قبل إضافة القيمة، وسيهتم أيضًا بربط PDO الضروري.
$ rows = [
[ ' column1 ' => ' value1 ' , ' column2 ' => ' value2 ' ],
[ ' column1 ' => ' value3 ' , ' column2 ' => ' value4 ' ],
// ...
];
$ insert -> rows ( $ rows );
تنفيذ
$ success = $ insert -> execute ();
الشيكات
قبل تنفيذ عملية الإدراج، سيقوم الفصل تلقائيًا بالتحقق مما يلي:
- إذا كانت قاعدة البيانات في وضع القراءة فقط ، فسيتم منع عمليات الكتابة غير المقصودة.
- إذا كان هناك تصادمات في المفاتيح الأساسية غير التلقائية ، مما يضمن سلامة البيانات.
تعد فئة Insert
حلاً شاملاً للتعامل مع عمليات الإدراج في قاعدة بيانات، مما يوفر سهولة الاستخدام وميزات متقدمة لإدارة مهام الإدراج المعقدة بكفاءة.
توفر فئة Update
في مكتبة PHP-DbHandler طريقة متطورة ومرنة لإنشاء استعلامات التحديث وتنفيذها في قاعدة البيانات. لقد تم تصميمه للتكامل بسلاسة مع بنية قاعدة البيانات الحالية مع تقديم ميزات قوية لإدارة عمليات التحديث بفعالية.
توليد الاستعلام
$ update = $ db -> update ()
-> table ( ' table_name ' )
-> set ( ' column1 ' , ' newValue1 ' )
-> set ( ' column2 ' , ' newValue2 ' );
```
2. **Conditional Updates**: Incorporate conditions into your update queries using the `where` method. This allows for precise targeting of records to be updated.
``` php
$ update -> where (Where:: equals ( ' column3 ' , ' conditionValue ' ));
تنفيذ
$ success = $ update -> execute ();
التحقق من وضع القراءة فقط : قبل التنفيذ، يتحقق الفصل مما إذا كانت قاعدة البيانات في وضع القراءة فقط، وبالتالي منع عمليات الكتابة غير المقصودة.
تمثل فئة Update
حلاً شاملاً لإنشاء وتنفيذ عمليات التحديث في قاعدة البيانات. إن الجمع بين المرونة والقوة وسهولة الاستخدام يجعله خيارًا مثاليًا لإدارة تحديثات قاعدة البيانات في تطبيقات PHP.
توفر فئة Delete
في مكتبة PHP-DbHandler طريقة متطورة لإنشاء وتنفيذ استعلامات الحذف في قواعد البيانات. تضمن هذه الفئة إجراء عمليات الحذف بدقة وأمان، مع دمج الفحوصات والميزات الأساسية للتعامل الأمثل مع الاستعلامات.
توليد الاستعلام
يسمح الفصل بحذف السجلات بدقة باستخدام التعبيرات الشرطية. يتم تحقيق ذلك من خلال الطريقة where
، مما يتيح تحديد صفوف معينة للحذف بناءً على المعايير المحددة.
$ delete = $ db -> delete ()
-> from ( ' table_name ' )
-> where (Where:: equals ( ' column ' , ' value ' ));
شرط Where الإلزامي : لتجنب الحذف غير المقصود لجميع السجلات في الجدول، يتطلب الفصل تحديد عبارة
WHERE
. وهذا بمثابة ضمانة ضد عمليات الحذف المجمعة غير المقصودة.
تنفيذ
$ success = $ delete -> execute ();
يقوم الفصل بإجراء فحوصات أساسية قبل تنفيذ عملية الحذف، بما في ذلك التحقق من وجود الجدول والتأكد من أن قاعدة البيانات ليست في وضع القراءة فقط.
تم تصميم فئة Delete
للتعامل مع عمليات الحذف بدرجة عالية من التحكم والأمان. فهو يضمن إجراء عمليات الحذف بدقة، مع احترام بنية قاعدة البيانات وقيودها. سواء كنت تقوم بمهام حذف بسيطة أو معقدة، فإن هذه الفئة توفر الأدوات اللازمة لتنفيذها بشكل موثوق وآمن.
توفر فئة StoredProcedure
في مكتبة PHP-DbHandler طريقة مبسطة وفعالة لتنفيذ الإجراءات المخزنة في قواعد البيانات. توفر هذه الفئة طريقة قوية للتفاعل مع الإجراءات المخزنة والتعامل مع إدارة المعلمات والتنفيذ وجلب النتائج بسهولة.
توليد الاستعلام
إعداد استدعاءات الإجراءات المخزنة : يمكنك إعداد استدعاءات الإجراءات المخزنة بسهولة من خلال إدارة المعلمات الديناميكية. حدد اسم الإجراء والمعلمات التي يتطلبها.
$ procedure = $ db -> storedProcedure ()
-> call ( ' procedure_name ' )
-> with ( ' paramName ' , $ value )
// ...
-> with ( ' paramName2 ' , $ value );
تنفيذ
$ results = $ procedure -> execute ();
اختبارات وضع القراءة فقط : قبل التنفيذ، يتحقق الفصل مما إذا كانت قاعدة البيانات في وضع القراءة فقط، مما يضمن عدم تنفيذ عمليات الكتابة عن غير قصد.
تعد فئة StoredProcedure
أداة لا غنى عنها للتعامل مع استدعاءات الإجراءات المخزنة داخل تطبيقات PHP. فهو يبسط التفاعل مع الإجراءات المخزنة، مما يجعل العملية أكثر سهولة وأقل عرضة للخطأ، خاصة في التطبيقات التي تعتمد بشكل كبير على عمليات قاعدة البيانات المعقدة.
تعد إدارة معاملات قاعدة البيانات جانبًا حاسمًا لضمان سلامة البيانات، خاصة في التطبيقات التي تتعامل مع معالجة البيانات المعقدة. يعمل PHP-DbHandler على تبسيط هذه العملية، حيث يوفر طريقة بديهية ومباشرة للتعامل مع المعاملات.
بفضل إمكانات إدارة المعاملات المتوفرة، يمكنك بسهولة بدء المعاملات أو الالتزام بها أو استرجاعها، مما يتيح لك التحكم الكامل في عمليات قاعدة البيانات الخاصة بك. وهذا يضمن أنه يمكن التعامل مع سلسلة من عمليات قاعدة البيانات كوحدة ذرية واحدة، إما أن تكتمل بالكامل أو لا تكتمل على الإطلاق، وبالتالي الحفاظ على اتساق وموثوقية بياناتك.
$ db -> transaction -> begin ();
$ db -> transaction -> commit ();
$ db -> transaction -> rollback ();
تعتبر هذه الميزة مفيدة بشكل خاص في السيناريوهات التي تتطلب تنفيذ عمليات قاعدة بيانات متعددة مرتبطة معًا. في حالة فشل أي عملية ضمن المعاملة، يمكن استخدام أسلوب التراجع للتراجع عن كافة التغييرات التي تم إجراؤها منذ بداية المعاملة، وبالتالي منع التحديثات الجزئية التي قد تؤدي إلى عدم تناسق البيانات. على العكس من ذلك، إذا كانت جميع العمليات ناجحة، فسيقوم أسلوب الالتزام بحفظ جميع التغييرات في قاعدة البيانات.
باستخدام عناصر التحكم في المعاملات هذه، يضمن PHP-DbHandler أن تكون إدارة بيانات تطبيقك قوية ومتسقة ومقاومة للأخطاء. سواء كنت تتعامل مع إدخالات بيانات معقدة، أو تحديثات، أو عمليات مجمعة، فإن إمكانيات المعاملات هذه توفر الأدوات اللازمة لإدارة عمليات قاعدة البيانات الخاصة بك بفعالية.
تقدم فئة Transaction
أيضًا ميزة قوية لإدارة سيناريوهات المعاملات المعقدة. تتيح لك هذه الميزة التحكم عالميًا في عمليات تنفيذ المعاملات، وهي مفيدة بشكل خاص عندما تريد تضمين طرق متعددة تستخدم المعاملات ضمن سياق معاملات واحد وشامل.
التعامل مع المعاملات على مستوى العالم
يمكنك إدارة عمليات معاملات متعددة كجزء من معاملة أكبر عن طريق تعطيل عمليات الالتزام التلقائي. وهذا مفيد بشكل خاص في السيناريوهات التي يلزم فيها تنفيذ عدة عمليات، كل منها قادرة على التعامل مع المعاملات بشكل مستقل، كجزء من معاملة ذرية واحدة.
// Begin a transaction
$ db -> transaction -> begin ();
// Disable automatic commits
$ db -> transaction -> setCommitsModeOff ();
// Execute other methods that use transactions
// $db->transaction->begin();
// ...
// $db->transaction->commit();
// Re-enable automatic commits
$ db -> transaction -> setCommitsModeOn ();
// Commit the transaction
$ db -> transaction -> commit ();
تعمل هذه الميزة على تحسين التحكم في عمليات المعاملات، مما يسمح بسيناريوهات أكثر تعقيدًا وموثوقية لمعالجة البيانات. فهو يضمن أن جميع التغييرات التي تم إجراؤها ضمن نطاق المعاملة العالمية إما أن يتم الالتزام بها معًا أو التراجع عنها، مع الحفاظ على سلامة البيانات واتساقها.
نحن نقدر بشدة ونرحب بالمساهمات في المشروع! إذا كنت مهتمًا بالمساهمة، فيرجى قراءة ملف CONTRIBUTING.md الخاص بنا للحصول على معلومات مفصلة حول كيفية البدء، وإرشادات لتقديم المساهمات، ونصائح لجعل العملية سهلة وفعالة قدر الإمكان.
سواء كنت تقوم بإصلاح خطأ ما، أو إضافة ميزة، أو تحسين الوثائق، فإن مساهماتك محل تقدير كبير ولها تأثير كبير على المشروع.
إذا كانت لديك أسئلة أو تريد مناقشة الأفكار قبل البرمجة، فلا تتردد في فتح مشكلة على صفحة مشكلات GitHub للمناقشة.
نحن نقدر رغبتك في المساهمة ونتطلع إلى مشاركاتك!
هذه المكتبة مرخصة بموجب ترخيص MIT. راجع ملف الترخيص لمزيد من التفاصيل.
للحصول على الدعم، يرجى زيارة صفحة المشكلات في مستودع GitHub: مشكلات GitHub