مواصفات PHP

مواصفات عقيدة السعادة

باختصار حول المواصفات:


المواصفات هي نمط تصميم يمكنك بواسطته أن يعكس قواعد منطق العمل في شكل سلسلة من الكائنات المتصلة بعمليات منطقية منطقية. تسمح لك المواصفات بالتخلص من الأساليب المكررة والمماثلة في مستودع وتكرار منطق العمل.

يوجد اليوم مشروعان (إذا كنت تعرف مشاريع أخرى ، يرجى كتابة التعليقات) ، مشاريع PHP ناجحة وشائعة تتيح لك وصف قواعد العمل في المواصفات ومجموعات بيانات التصفية. هذه هي مواصفات RulerZ و Happyr . كلا المشروعين أدوات قوية مع مزاياها وعيوبها. مقارنة هذه المشاريع سوف ترسم مقالا كاملا. أريد هنا أن أخبركم بما جاء به الإصدار الجديد في مواصفات العقيدة.


باختصار حول مواصفات العقيدة


أولئك الذين هم أكثر أو أقل دراية بالمشروع ، يمكنهم تخطي هذا القسم بأمان.


بمساعدة هذا المشروع ، يمكنك وصف المواصفات في شكل كائنات ، وتأليفها من التكوين ، وبالتالي وضع قواعد عمل معقدة. يمكن إعادة استخدام التركيبات الناتجة بحرية ، ودمجها في تركيبات أكثر تعقيدًا يسهل اختبارها. يتم استخدام مواصفات العقيدة لبناء استعلامات العقيدة. في جوهرها ، مواصفات Doctrine هي مستوى التجريد على Doctrine ORM QueryBuilder و Doctrine ORM Query.


تنطبق المواصفات من خلال مستودع العقيدة:


$result = $em->getRepository(MyEntity::class)->match($spec); 

يمكن تطبيق المواصفات يدويًا ، لكنها ليست ملائمة بشكل خاص ، وفي المدى الطويل ، لا طائل من ورائها.
 $spec = ... $alias = 'e'; $qb = $em->getRepository(MyEntity::class)->createQueryBuilder($alias); $spec->modify($qb, $alias); $filter = (string) $spec->getFilter($qb, $alias); $qb->andWhere($filter); $result = $qb->getQuery()->execute(); 

هناك عدة طرق في المستودع:


  • match - الحصول على جميع النتائج المقابلة للمواصفات ؛
  • matchSingleResult - مكافئ Query::getSingleResult() ؛
  • matchOneOrNullResult - المكافئ لـ matchSingleResult ، لكنه يسمح matchSingleResult ؛
  • getQuery - يقوم بإنشاء QueryBuilder عن طريق تطبيق مواصفات عليه وإرجاع كائن Query منه.

في الآونة الأخيرة ، تمت إضافة طريقة getQueryBuilder إليهم ، مما يؤدي إلى إنشاء QueryBuilder ، وتطبيق المواصفات عليها ، ويعيدها.


يحدد المشروع عدة أنواع من المواصفات:



المواصفات المنطقية


orX و orX أيضًا كمجموعة من المواصفات.


  • Spec::andX()
  • Spec::orX()
  • Spec::not()

من المعتاد تثبيت كائنات مواصفات المكتبة من خلال واجهة Spec ، لكن هذا ليس ضروريًا. يمكنك إنشاء مثيل واضح لعنصر المواصفات:


 new AndX(); new OrX(): new Not(); 

مواصفات مرشح


تصفية المواصفات ، في الواقع ، تشكل قواعد منطق الأعمال وتستخدم في طلب WHERE . وتشمل هذه عمليات المقارنة:


  • isNull - SQL IS NULL المكافئ
  • isNotNull - SQL IS NOT NULL مكافئ
  • in - ما يعادل IN ()
  • NOT IN () - NOT IN () ما يعادلها
  • eq - اختبار المساواة =
  • neq - التحقق من عدم المساواة !=
  • lt - أقل من <
  • lte - أقل من أو يساوي <=
  • gt - أكثر من >
  • gte - أكبر من أو يساوي >=
  • like - like SQL يعادل
  • exampleOfX - ما يعادل DQL INSTANCE OF

مثال على استخدام مواصفات التصفية:


 $spec = Spec::andX( Spec::eq('ended', 0), Spec::orX( Spec::lt('endDate', new \DateTime()), Spec::andX( Spec::isNull('endDate'), Spec::lt('startDate', new \DateTime('-4 weeks')) ) ) ); 

معدّلات الاستعلام


لا علاقة لمعدلات الاستعلامات بقواعد العمل وقواعد العمل. كما يوحي الاسم ، فإنها فقط تعديل QueryBuilder. اسم وغرض المعدلات المعرفة مسبقا يتوافق مع أساليب مماثلة في QueryBuilder.


  • join
  • leftJoin
  • innerJoin
  • limit
  • offset
  • orderBy
  • groupBy
  • having

أريد أن أشير بشكل منفصل إلى معدل slice . فهو يجمع بين وظائف limit offset وحساب الإزاحة على أساس حجم الشريحة ورقمها التسلسلي. في تنفيذ هذا التعديل ، لم نوافق على مؤلف المشروع. إنشاء مُعدِّل ، تابعت هدف تبسيط تكوين المواصفات أثناء ترقيم الصفحات. في هذا السياق ، يجب أن تكون الصفحة الأولى ذات الرقم التسلسلي 1 مكافئة للشريحة الأولى ذات الرقم التسلسلي 1. لكن مؤلف المشروع اعتبر أنه من الصواب البدء في بدء العد التنازلي بأسلوب برمجة ، أي من 0. لذلك ، تجدر الإشارة إلى أنك إذا كنت بحاجة إلى الشريحة الأولى ، فيجب عليك تحديد 0 كرقم مسلسل.


نتيجة المعدلات


توجد معدّلات النتائج متباعدة قليلاً عن المواصفات. أنها تنطبق على عقيدة الاستعلام. تتحكم المعدلات التالية في ترطيب البيانات ( Query::setHydrationMode() ):


  • asArray
  • asSingleScalar
  • asScalar

يتحكم معدّل cache التخزين المؤقت في التخزين المؤقت لنتائج الاستعلام.


يجب أن نذكر أيضًا معدل roundDateTimeParams . يساعد في حل مشاكل التخزين المؤقت عندما تحتاج إلى العمل مع قواعد العمل التي تتطلب مقارنة بعض القيم مع الوقت الحالي. هذه قواعد أعمال عادية ، ولكن نظرًا لحقيقة أن الوقت ليس ثابتًا ، فلن يعمل التخزين المؤقت لأكثر من ثانية واحدة من أجلك. تم roundDateTimeParams معدل roundDateTimeParams لحل هذه المشكلة. يمر عبر جميع معلمات الطلب ، ويبحث عن التاريخ فيها ويقربها إلى القيمة المحددة ، والتي تعطينا قيم التاريخ التي تكون دائمًا مضاعفات بقيمة واحدة ولن نحصل على التاريخ في المستقبل. أي إذا أردنا تخزين الطلب مؤقتًا لمدة 10 دقائق ، فإننا نستخدم Spec::cache(600) و Spec::roundDateTimeParams(600) . في البداية ، تم اقتراح دمج هذين المعدلين للراحة ، ولكن تقرر فصلهما عن SRP.


المواصفات المضمنة


يحتوي Happyr Doctrine-Specification على واجهة منفصلة للمواصفات التي تجمع بين مرشح ومعدل طلب. المواصفات المحددة مسبقًا هي countOf والتي تتيح لك الحصول على عدد الكيانات المطابقة للمواصفات. لإنشاء مواصفات خاصة بك ، من المعتاد تمديد فئة BaseSpecification المجردة.


الابتكارات


تمت إضافة طرق جديدة إلى المستودع:


  • matchSingleScalarResult - المكافئ من Query::getSingleScalarResult() ؛
  • matchScalarResult - المكافئ Query::getScalarResult() ؛
  • iterate هو المكافئ Query::iterate() .

تتم MemberOfX مواصفات MemberOfX - MemberOfX المكافئ indexBy الخاص بـ MEMBER OF indexBy استعلام indexBy - المكافئ QueryBuilder::indexBy() .


المعاملات


الإصدار الجديد يقدم مفهوم Operand . تتكون كل الشروط الموجودة في المرشحات من المعاملات اليمنى واليسرى ومشغل بينهما.


 <left_operand> <operator> <right_operand> 

في الإصدارات السابقة ، يمكن أن يكون المعامل الأيسر مجرد حقل كيان ، والمعامل الأيمن يمكن أن يكون قيمة فقط. هذه آلية بسيطة وفعالة تكفي لمعظم المهام. في الوقت نفسه ، يفرض قيودًا معينة:


  • غير قادر على استخدام الوظائف ؛
  • لا يمكن استخدام الأسماء المستعارة للحقول ؛
  • من المستحيل مقارنة حقلين ؛
  • من المستحيل مقارنة قيمتين ؛
  • غير قادر على استخدام العمليات الحسابية ؛
  • لا يمكن تحديد نوع البيانات للقيمة.

في الإصدار الجديد ، يتم تمرير كائنات المعامل إلى المرشحات في الوسائط ويتم تفويض تحولها في DQL إلى المعاملات نفسها. هذا يفتح العديد من الاحتمالات ويجعل المرشحات أسهل.


الحقل والقيمة


للحفاظ على التوافق مع الإصدارات السابقة ، يتم تحويل الوسيطة الأولى في عوامل التصفية إلى معامل حقل ، إذا لم تكن معاملًا ، ويتم تحويل الوسيطة الأخيرة إلى معامل قيمة. لذلك ، يجب أن لا تواجه مشكلات في التحديث.


 // DQL: e.day > :day Spec::gt('day', $day); // or Spec::gt(Spec::field('day'), $day); // or Spec::gt(Spec::field('day', $dqlAlias), $day); 

 // DQL: e.day > :day Spec::gt('day', $day); // or Spec::gt('day', Spec::value($day)); // or Spec::gt('day', Spec::value($day, Type::DATE)); 

يمكنك مقارنة حقلين:


 // DQL: e.price_current < e.price_old Spec::lt(Spec::field('price_current'), Spec::field('price_old')); 

يمكنك مقارنة حقلين لكيانات مختلفة:


 // DQL: a.email = u.email Spec::eq(Spec::field('email', 'a'), Spec::field('email', 'u')); 

العمليات الحسابية


إضافة دعم للعمليات الحسابية القياسية - ، + ، * ، / ، % . على سبيل المثال ، ضع في اعتبارك حساب نقاط المستخدم:


 // DQL: e.posts_count + e.likes_count > :user_score Spec::gt( Spec::add(Spec::field('posts_count'), Spec::field('likes_count')), $user_score ); 

يمكن أن تتداخل العمليات الحسابية مع بعضها البعض:


 // DQL: ((e.price_old - e.price_current) / (e.price_current / 100)) > :discount Spec::gt( Spec::div( Spec::sub(Spec::field('price_old'), Spec::field('price_current')), Spec::div(Spec::field('price_current'), Spec::value(100)) ), Spec::value($discount) ); 

وظائف


الإصدار الجديد وأضاف المعاملات مع وظائف. يمكن استخدامها كطرق ثابتة لفئة Spec ، أو من خلال الأسلوب Spec::fun() .


 // DQL: size(e.products) > 2 Spec::gt(Spec::size('products'), 2); // or Spec::gt(Spec::fun('size', 'products'), 2); // or Spec::gt(Spec::fun('size', Spec::field('products')), 2); 

وظائف يمكن أن تتداخل واحدة في أخرى:


 // DQL: trim(lower(e.email)) = :email Spec::eq(Spec::trim(Spec::lower('email')), trim(strtolower($email))); // or Spec::eq( Spec::fun('trim', Spec::fun('lower', Spec::field('email'))), trim(strtolower($email)) ); 

يمكن تمرير وسيطات الوظائف كوسائط منفصلة ، أو بتمريرها في صفيف:


 // DQL: DATE_DIFF(e.create_at, :date) Spec::DATE_DIFF('create_at', $date); // or Spec::DATE_DIFF(['create_at', $date]); // or Spec::fun('DATE_DIFF', 'create_at', $date); // or Spec::fun('DATE_DIFF', ['create_at', $date]); 

إدارة العينات


في بعض الأحيان تحتاج إلى إدارة قائمة قيم الإرجاع. على سبيل المثال:


  • أضف كيانًا آخر إلى النتيجة حتى لا تنشئ استعلامات فرعية للحصول على الارتباطات ؛
  • لإرجاع ليس الكيان بأكمله ، ولكن فقط مجموعة من الحقول المنفصلة ؛
  • استخدام الأسماء المستعارة ؛
  • استخدم الأسماء المستعارة المخفية بشروط للفرز (يتطلب ذلك مبدأ ، ولكنه يعد بإصلاحه ).

قبل الإصدار 0.8.0 ، كانت هذه المهام تتطلب إنشاء مواصفات لهذه الاحتياجات. بدءًا من الإصدار 0.8.0 ، يمكنك استخدام الأسلوب getQueryBuilder() وإدارة التحديد من خلال واجهة QueryBuilder.


الإصدار الجديد 1.0.0 يضيف select و addSelect الطلب. select تمامًا يحل محل قائمة القيم addSelect للاختيار ، ويضيف addSelect قيمًا جديدة إلى القائمة. كقيمة ، يمكنك استخدام كائن يقوم بتنفيذ واجهة Selection أو مرشح. وبالتالي ، يمكنك توسيع قدرات المكتبة لتناسب احتياجاتك. النظر في الفرص المتاحة بالفعل.


يمكنك اختيار حقل واحد:


 // DQL: SELECT e.email FROM ... Spec::select('email') // or Spec::select(Spec::field('email')) 

يمكنك إضافة حقل واحد إلى التحديد:


 // DQL: SELECT e, u.email FROM ... Spec::addSelect(Spec::field('email', $dqlAlias)) 

يمكنك اختيار عدة مجالات:


 // DQL: SELECT e.title, e.cover, u.name, u.avatar FROM ... Spec::andX( Spec::select('title', 'cover'), Spec::addSelect(Spec::field('name', $dqlAlias), Spec::field('avatar', $dqlAlias)) ) 

يمكنك إضافة كيان إلى القيم التي يتم إرجاعها:


 // DQL: SELECT e, u FROM ... Spec::addSelect(Spec::selectEntity($dqlAlias)) 

يمكنك استخدام الأسماء المستعارة للحقول القابلة للتحديد:


 // DQL: SELECT e.name AS author FROM ... Spec::select(Spec::selectAs(Spec::field('name'), 'author')) 

يمكنك إضافة الحقول المخفية إلى التحديد:


 // DQL: SELECT e, u.name AS HIDDEN author FROM ... Spec::addSelect(Spec::selectHiddenAs(Spec::field('email', $dqlAlias), 'author'))) 

يمكنك استخدام التعبيرات ، على سبيل المثال ، للحصول على خصم على منتج:


 // DQL: SELECT (e.price_old is not null and e.price_current < e.price_old) AS discount FROM ... Spec::select(Spec::selectAs( Spec::andX( Spec::isNotNull('price_old'), Spec::lt(Spec::field('price_current'), Spec::field('price_old')) ), 'discount' )) 

يمكنك استخدام الأسماء المستعارة في المواصفات:


 // DQL: SELECT e.price_current AS price FROM ... WHERE price < :low_cost_limit Spec::andX( Spec::select(Spec::selectAs('price_current', 'price')), Spec::lt(Spec::alias('price'), $low_cost_limit) ) 

هذا كل شيء في الأساس. هذا هو المكان الذي تنتهي فيه الابتكارات. الإصدار الجديد قد جلب العديد من الميزات المثيرة للاهتمام ومفيدة. آمل أن يكونوا مهتمين بك.


ملاحظة: يمكنني استخدام مثال لتحليل استخدام المواصفات وإظهار مزايا وعيوب استخدامها. إذا كان هذا مثيرًا لك ، فاكتب في التعليقات أو في PM.

Source: https://habr.com/ru/post/ar455030/


All Articles