Searcher هو منشئ استعلام بحث حيادي للإطار. تتم كتابة استعلامات البحث باستخدام معايير ويمكن تشغيلها على MySQL أو MongoDB أو ElasticSearch أو الملفات أو أي شيء آخر تريده. أحدث إصدار يدعم PHP 7 فقط . تم اختباره الآن أيضًا باستخدام Humbug
هل سبق لك أن رأيت كودًا مسؤولاً عن البحث عن شيء ما بناءً على العديد من المعايير المختلفة؟ يمكن أن تصبح فوضى كبيرة! تخيل أن لديك نموذجًا يحتوي على 20 حقلاً، ولكل منها بعض التأثير على شروط البحث. إنها ليست فكرة رائعة تمرير نموذج كامل إلى بعض الخدمات والسماح لها بتحليل كل شيء في مكان واحد. بفضل هذه المكتبة، يمكنك تقسيم مسؤولية بناء معايير الاستعلام إلى عدة فئات أصغر. فئة واحدة لكل مرشح. CriteriaBuilder
واحد لكل Criteria
. بهذه الطريقة، داخل CriteriaBuilder
أنت تهتم Criteria
واحدة فقط، مما يجعلها أكثر قابلية للقراءة والصيانة. يمكنك لاحقًا استخدام نفس Criteria
تمامًا لعمليات بحث مختلفة، باستخدام CriteriaBuilder
مختلف وحتى SearchingContext
مختلف يمكنه استخدام قواعد بيانات مختلفة. يمكنك أيضًا استخدام الباحث للعثور على الملفات الموجودة على نظامك بفضل FinderSearchingContext
.
يمكن العثور على الوثائق الكاملة على http://searcher.rtfd.io/
يمكنك تثبيت المكتبة عبر الملحن عن طريق الكتابة في المحطة:
$ الملحن يتطلب krzysztof-gzocha/searcher
يتم التكامل مع Symfony في SearcherBundle
CriteriaBuilder
- سيبني شروطًا جديدة Criteria
فردية،
Criteria
- النموذج الذي سيتم تمريره إلى CriteriaBuilder
. تحتاج فقط إلى ترطيبه بطريقة ما، لذلك سيكون مفيدًا. يمكن أن تحتوي المعايير على حقول متعددة بداخلها ويمكن استخدام جميعها (أو بعضها) داخل CriteriaBuilder
،
SearchingContext
- سياق البحث الفردي. يجب أن تعرف هذه الخدمة كيفية جلب النتائج من استعلام مُنشأ، كما أنها تحمل شيئًا يسمى QueryBuilder
، ولكنها يمكن أن تكون أي شيء يناسبك - أي خدمة. هذه طبقة تجريد بين البحث وقاعدة البيانات. هناك سياقات مختلفة لـ Doctrine's ORM وODM وElastica والملفات وما إلى ذلك. إذا لم يكن هناك سياق مناسب لك، فيمكنك تنفيذ واحد - لا ينبغي أن يكون الأمر صعبًا،
Searcher
- يحمل مجموعة CriteriaBuilder
وسيقوم بتمرير Criteria
إلى CriteriaBuilder
المناسب.
لنفترض أننا نريد البحث عن الأشخاص الذين تقع أعمارهم في نطاق ما تمت تصفيته. في هذا المثال، سنستخدم QueryBuilder الخاص بـ Doctrine، لذلك سنستخدم QueryBuilderSearchingContext
وسنحدد في CriteriaBuidler
أنه يجب أن يتفاعل فقط مع DoctrineORMQueryBuilder
، لكن تذكر أنه ليس علينا استخدام Doctrine فقط.
بادئ ذي بدء، سنحتاج إلى إنشاء AgeRangeCriteria
- الفئة التي ستحمل قيم الحد الأدنى والحد الأقصى للعمر. لقد تم بالفعل تطبيق Criteria
الافتراضية هنا.
فئة AgeRangeCriteria تطبق CriteriaInterface{private $minimalAge;private $maximalAge;/** * الطريقة المطلوبة فقط. * إذا تم إرجاعه صحيحًا، فسيتم تمريره إلى بعض CriteriaBuilder (s) */ public function mustBeApplied(): bool{return null !== $this->minimalAge && null !== $this->maximalAge; }// الحروف، المستوطنون، أيًا كان}
في الخطوة الثانية نود تحديد الشروط التي ينبغي فرضها لهذا النموذج. لهذا السبب سنحتاج إلى إنشاء AgeRangeCriteriaBuilder
فئة AgeRangeCriteriaBuilder تنفذ CriteriaBuilderInterface{public function buildCriteria(CriteriaInterface $criteria,SearchingContextInterface $searchingContext) {$searchingContext->getQueryBuilder() ->وأين ('e.age >= :minimalAge') ->وأين('e.age <= :maximalAge') ->setParameter('minimalAge', $criteria->getMinimalAge()) ->setParameter('maximalAge', $criteria->getMaximalAge()); }الوظيفة العامة تسمح بالمعايير (CriteriaInterface $criteria): bool{return $criteria مثيل AgeRangeCriteria؛ }/** * يمكنك تخطي هذه الطريقة إذا كنت ستمتد من AbstractORMCriteriaBuilder. */ الوظيفة العامة تدعمSearchingContext(SearchingContextInterface $searchingContext): bool{return $searchingContext مثيل QueryBuilderSearchingContext; } }
في الخطوات التالية، سنحتاج إلى إنشاء مجموعات لكليهما: Criteria
و CriteriaBuidler
.
$builders = new CriteriaBuilderCollection();$builders->addCriteriaBuilder(new AgeRangeCriteriaBuilder());$builders->addCriteriaBuilder(/** بقية البناة */);
$ageRangeCriteria = new AgeRangeCriteria();// علينا ملء النموذج قبل البحث$ageRangeCriteria->setMinimalAge(23);$ageRangeCriteria->setMaximalAge(29);$criteria = new CriteriaCollection();$criteria->addCriteria( $ageRangeCriteria);$criteria->addCriteria(/** بقية المعايير */);
نود الآن إنشاء SearchingContext
الخاص بنا وملؤه باستخدام QueryBuilder المأخوذ من Doctrine ORM.
$context = new QueryBuilderSearchingContext($queryBuilder);$searcher = new Searcher($builders, $context);$searcher->search($criteriaCollection); // ياي، لدينا نتائجنا!
إذا كانت هناك فرصة ضئيلة لأن يُرجع QueryBuilder null
عندما تتوقع كائنًا أو مصفوفة يمكن اجتيازها، فيمكنك استخدام WrappedResultsSearcher
بدلاً من فئة Searcher
العادية. سيعمل تمامًا مثل Searcher
، لكنه سيُرجع ResultCollection
، والذي سيعمل فقط مع المصفوفة أو Traversable
وإذا كانت النتيجة null
فقط، فسيظل الكود الخاص بك يعمل. هنا كيف سيبدو:
$searcher = new WrappedResultsSearcher(new Searcher($builders, $context));$results = $searcher->search($criteriaCollection); // مثيل ResultCollectionforeach ($results as $result) {// سيعمل!}foreach ($results->getResults() as $result) {// بما أن ResultCollection له طريقة getResults() فهذا سيعمل أيضًا!}
من أجل فرز نتائجك، يمكنك الاستفادة من Criteria
المطبقة بالفعل. لا تحتاج إلى تنفيذه من الصفر. ضع في اعتبارك أنك لا تزال بحاجة إلى تنفيذ CriteriaBuilder
الخاص بك (هذه الميزة لا تزال قيد التطوير). لنفترض أنك تريد طلب نتائجك وتحتاج إلى قيمة p.id
في CriteriaBuidler الخاص بك للقيام بذلك، ولكنك ترغب في إظهارها كقيمة pid
للمستخدم النهائي. لا شيء أبسط! هذه هي الطريقة التي يمكنك من خلالها إنشاء OrderByCriteria:
$mappedFields = ['pid' => 'p.id', 'valueForUser' => 'valueForBuilder'];$criteria = new MappedOrderByAdapter(new OrderByCriteria('pid'),$mappedFields);// $criteria->getMappedOrderBy () = 'p.id'// $criteria->getOrderBy() = 'pid'
بالطبع لا تحتاج إلى استخدام MappedOrderByAdapter
- يمكنك استخدام OrderByCriteria
فقط، ولكن بعد ذلك سيعرف المستخدم بالضبط ما هي الحقول التي يتم استخدامها للفرز.
يتم أيضًا تنفيذ Criteria
ترقيم الصفحات ولا تحتاج إلى القيام بذلك، ولكن ضع في اعتبارك أنك لا تزال بحاجة إلى تطبيق CriteriaBuilder
الذي سيستفيد منها ويقوم بترقيم الصفحات فعليًا (هذه الميزة قيد التطوير). لنفترض أنك تريد السماح للمستخدم النهائي بتغيير الصفحات، ولكن ليس عدد العناصر في كل صفحة. يمكنك استخدام رمز المثال هذا:
$criteria = new ImmutablePaginationAdapter( new PaginationCriteria($page = 1, $itemsPerPage = 50) );// $criteria->setItemsPerPage(250); <- يمكن للمستخدم محاولة تغييره// $criteria->getItemsPerPage() = 50 <- لكنه لا يستطيع فعل ذلك بالفعل// $criteria->getPage() = 1
بالطبع إذا كنت تريد السماح للمستخدم بتغيير عدد العناصر لكل صفحة، فيمكنك أيضًا تخطي ImmutablePaginationAdapter
واستخدام PaginationCriteria
فقط.
نرحب بجميع الأفكار وطلبات السحب ونقدرها :) إذا كانت لديك أي مشكلة تتعلق بالاستخدام، فلا تتردد في إنشاء مشكلة، فيمكننا حل مشكلتك معًا.
أمر تشغيل الاختبار: composer test
.
يتم اختبار جميع اختبارات الوحدات باستخدام مكتبة بادرية/هراء لاختبار الطفرات، بهدف الحفاظ على مؤشر درجة الطفرة مساويًا أو قريبًا من 100%.
لإجراء اختبارات الطفرات، تحتاج إلى تثبيت برنامج humbug وتشغيل: humbug
في الدليل الرئيسي. يجب أن يتم تخزين الإخراج في humbuglog.txt
.
بالترتيب الأبجدي
https://github.com/chkris
https://github.com/pawelhertman
https://github.com/ustrugany
https://github.com/wojciech-olszewski
الترخيص: معهد ماساتشوستس للتكنولوجيا
المؤلف: كرزيستوف جزوتشا