एक Laravel ऐप में सुविधाओं को सक्षम / अक्षम करना


10

मैं एक Laravel ऐप बना रहा हूं, जिसमें कई तरह की विशेषताएं हैं। मैं एक विशेष डोमेन की आवश्यकता के आधार पर उन्हें सक्षम या अक्षम करने में सक्षम होना चाहता हूं। वर्तमान में, मेरे पास मेरे झंडे की एक श्रृंखला है जैसे:

'is_feature_1_enabled' => true,
'is_feature_2_enabled' => false,

... और इसी तरह।

फिर अपने नियंत्रकों और विचारों में, मैं यह देखने के लिए कि वे कुछ प्रदर्शित कर रहे हैं या नहीं, कुछ क्रियाओं की अनुमति देने के लिए मैं उन कॉन्फ़िगरेशन मूल्यों की जांच करता हूं, मेरा ऐप हर जगह इस प्रकार के चेक से प्रदूषित होने लगा है।

क्या एक लारवेल ऐप में सुविधाओं को प्रबंधित करने का सबसे अच्छा अभ्यास तरीका है?


नियंत्रक के बजाय मार्गों को अक्षम करें? या मिडिलवेयर का उपयोग कर सकते हैं
Berto99

फ़ीचर! == पृष्ठ।
स्टैकऑवरफ्लो न्यूवेबी


वास्तव में एक समाधान हो सकता है। अपनी टिप्पणी एक उत्तर में बनाना चाहते हैं?
स्टैकऑवरफ़्लो नेवेबी

mh कोई समस्या नहीं है, इसका उत्तर नहीं है, महत्वपूर्ण यह है कि इससे आपको मदद मिल सकती है
Berto99

जवाबों:


4

इसे तकनीकी रूप से फीचर फ़्लैग कहा जाता है - https://martinfowler.com/articles/feature-toggles.html

आपकी आवश्यकताओं पर निर्भर करता है, विन्यास में झंडे / डेटाबेस, रोलआउट, आदि ...

लेकिन यह मूल रूप से है अगर कोड में है और साफ नहीं हो सकता।

लारवेल पैकेज:

https://github.com/alfred-nutile-inc/laravel-feature-flag

https://github.com/francescomalatesta/laravel-feature

कुछ सेवाएं:

https://launchdarkly.com/

https://bullet-train.io/

https://configcat.com/

इसके अलावा https://marketingplatform.google.com/about/optimize/ को दृश्यपटल पर देखें


1
आप यहाँ सुविधा फ़्लैगिंग के साथ एक नमूना लारवल परियोजना पा सकते हैं: github.com/configcat/php-sdk/tree/master/samples/laravel
पीटर

7

मैंने एक ही समस्या का सामना किया है जब मैंने कई होटल प्रदाताओं को लागू करने की कोशिश की थी।

मैंने जो किया वह सर्विस कंटेनर का उपयोग कर रहा था।

पहले आप प्रत्येक डोमेन के लिए उसकी विशेषताओं के साथ कक्षा बनाएंगे:

  • जैसे Doman1.php, Domain2.php
  • फिर उनमें से हर एक के अंदर आप अपने तर्क जोड़ देंगे।

तब आप उपयोग करने के लिए कक्षा के साथ डोमेन को बांधने के लिए अपने ऐप सेवा प्रदाता में बाइंडिंग का उपयोग करने वाले हैं।

$this->app->bind('Domain1',function (){
       return new Domain1();
    });
    $this->app->bind('Domain2',function (){
        return new Domain2();
    });

ध्यान दें कि आप सामान्य वर्ग का उपयोग कर सकते हैं जो सुविधाएँ रखता है सभी डोमेन के साथ जाता है फिर अपनी कक्षाओं में उस सामान्य वर्ग का उपयोग करें

अंत में आपके नियंत्रक में आप अपने डोमेन की जांच कर सकते हैं फिर जिस कक्षा का आप उपयोग करने वाले हैं उसका उपयोग करने के लिए

    app(url('/'))->methodName();

0

कुछ विशेषताओं को सक्षम या अक्षम करने के लिए जैसे आप कॉन्फिगर वैल्यू के आधार पर हार्ड कोडिंग चीजें देखते हैं, वैसा ही करें। मैं आपको कॉन्फ़िगर मूल्य के बजाय नामित मार्गों के आधार पर चीजों को नियंत्रित करने की सलाह देता हूं।

  1. संपूर्ण या सुविधा के अनुसार पूरे मार्ग को समूह बनाएं।
  2. सभी मार्गों के लिए नाम परिभाषित करें
  3. डेटाबेस में मार्ग के नाम और रिकॉर्ड द्वारा सक्षम / अक्षम गतिविधि को नियंत्रित करें
  4. अनुरोध वस्तु से वर्तमान मार्ग का नाम प्राप्त करने और डेटाबेस के साथ मिलान करके यह देखने के लिए कि क्या कोई विशेष सुविधा सक्षम या अक्षम है, यह देखने के लिए Laravel मिडलवेयर का उपयोग करें।

इसलिए आपके पास हर जगह दोहराई जाने वाली स्थिति नहीं होगी और आपके कोड को ब्लोट किया जाएगा .. यहां एक नमूना कोड दिखाया गया है कि आप सभी मार्गों को कैसे पुनः प्राप्त कर सकते हैं, और आप अपनी स्थिति से मेल खाने के लिए मार्ग समूह के नाम को आगे की प्रक्रिया से मिला सकते हैं।

Route::get('routes', function() {
$routeCollection = Route::getRoutes();

echo "<table >";
    echo "<tr>";
        echo "<td width='10%'><h4>HTTP Method</h4></td>";
        echo "<td width='10%'><h4>Route</h4></td>";
        echo "<td width='80%'><h4>Corresponding Action</h4></td>";
    echo "</tr>";
    foreach ($routeCollection as $value) {
        echo "<tr>";
            echo "<td>" . $value->getMethods()[0] . "</td>";
            echo "<td>" . $value->getPath() . "</td>";
            echo "<td>" . $value->getName() . "</td>";
        echo "</tr>";
    }
echo "</table>";
});

और यहां एक नमूना मिडलवेयर हैंडलर है, जहां आप यह जांच सकते हैं कि क्या कोई विशेष सुविधा आपके डेटाबेस में पहले से संग्रहीत सामग्री के साथ मिलान करके सक्रिय है या नहीं।

public function handle($request, Closure $next)
    {
        if(Helper::isDisabled($request->route()->getName())){
             abort(403,'This feature is disabled.');
        }
        return $next($request);
    }

1
यह मानता है कि सुविधाएँ साइट पर पृष्ठों के बराबर हैं, है ना? ऐसी बात नहीं है। एक सुविधा एक पृष्ठ के भीतर कुछ स्निपेट हो सकती है (जैसे कि साइडबार में Google मानचित्र प्रदर्शित होगा), या कुछ प्रकार की कार्यक्षमता (जैसे उपयोगकर्ता कुछ डेटा निर्यात कर सकते हैं)।
स्टैकऑवरफ्लो न्यूवेबी

आप सही हैं, लेकिन क्या आपका मतलब कुछ ब्लॉक हैं जो विभिन्न पृष्ठों पर प्रदर्शित होते हैं? आप इसे प्रदर्शित करने के लिए क्या अड़चन हैं? विशिष्ट पृष्ठ के अनुसार या सभी पृष्ठों पर आप इसे प्रदर्शित करते हैं
अकरम वाहिद

सुविधाएँ एक संपूर्ण पृष्ठ, या पृष्ठ के एक भाग या केवल कुछ कार्यक्षमता हो सकती हैं।
स्टैकऑवरफ्लोNewbie

0

यह मानते हुए कि उन सुविधाओं को केवल HTTP अनुरोधों के लिए आवश्यक है।

मैं Featuresसभी डिफ़ॉल्ट झंडे के साथ एक डिफ़ॉल्ट आधार वर्ग बनाऊंगा:

Class Features {
    // Defaults
    protected $feature1_enabled = true;
    protected $feature2_enabled = true;

    public function isFeature1Enabled(): bool
    {
        return $this->feature1_enabled;
    }

    public function isFeature2Enabled(): bool
    {
        return $this->feature2_enabled;
    }
}

फिर मैं प्रत्येक डोमेन के लिए उस वर्ग का विस्तार करूँगा और उस डोमेन के लिए आवश्यक ओवरराइड्स सेट करूंगा:

Class Domain1 extends Features {
    // override
    protected $feature1_enabled = false;
}

फिर कंटेनर में फीचर क्लास को बांधने के लिए एक मिडलवेयर बनाएं:

class AssignFeatureByDomain
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        switch ($_SERVER['HTTP_HOST']) {
            case 'domain1':
                app()->bind(Features::class, Domain1::class);
                break;
            default:
                abort(401, 'Domain rejected');
        }

        return $next($request);
    }
}

इस मिडलवेयर को अपने मार्गों से जोड़ना न भूलें: किसी समूह या प्रत्येक मार्ग के लिए।

इसके बाद आप अपने नियंत्रकों में अपनी फीचर क्लास टाइप कर सकते हैं:

public function index(Request $request, Features $features)
{
    if ($features->isFeature1Enabled()) {
        //
    }
}

0

लारवेल इसके साथ बहुत अच्छा है, आप अपनी सुविधाओं को डीबी में भी स्टोर कर सकते हैं, और डोमेन के बीच संबंध बना सकते हैं।

मैं गेट्स और नीतियों का उपयोग करने की सलाह दूंगा, जो आपको अपने नियंत्रकों और ब्लेड टेम्पलेट्स में बेहतर नियंत्रण देगा। इसका मतलब है कि आप अपने डीबी या हार्ड कोड से फाटकों को पंजीकृत करते हैं।

उदाहरण के लिए यदि आपके पास अपने सिस्टम में एक बटन के साथ निर्यात उत्पाद सुविधा है और आप कुछ उपयोगकर्ताओं के लिए यह सुविधा उपलब्ध कराना चाहते हैं, तो आप व्यावसायिक तर्क के साथ द्वार पंजीकृत कर सकते हैं।

//Only admins can export products
Gate::define('export-products', function ($user) {
    return $user->isAdmin;
});

फिर आप नियंत्रकों में निम्नलिखित कर सकते हैं

<?php

namespace App\Http\Controllers;

use App\Product;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class ProductsController extends Controller
{
    /**
     * Export products
     *
     * @param  Request  $request
     * @param  Post  $post
     * @return Response
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function export(Request $request)
    {
        $this->authorize('export-products');

        // The current user can export products
    }
}

यहाँ आपके ब्लेड टेम्पलेट्स के लिए एक उदाहरण दिया गया है:

@can('export-products', $post)
    <!-- The Current User Can export products -->
@endcan

@cannot('export-products')
    <!-- The Current User Can't export products -->
@endcannot

अधिक जानकारी https://laravel.com/docs/5.8/authorization पर उपलब्ध है


0

दिलचस्प मामला आपके यहाँ है। यह एक Featureइंटरफ़ेस या अमूर्त वर्ग में देखना दिलचस्प हो सकता है जिसमें कुछ विधियाँ शामिल हैं जिनकी आपको आमतौर पर आवश्यकता होती है।

interface Feature
{
    public function isEnabled(): bool;

    public function render(): string;

    // Not entirely sure if this would be a best practice but the idea is to be
    // able to call $feature->execute(...) on any feature.
    public function execute(...);

    ...
}

तुम भी इन में विभाजित कर सकते हैं ExecutableFeatureऔर RenderableFeature

आगे कुछ प्रकार के कारखाने वर्ग को जीवन को आसान बनाने के लिए बनाया जा सकता है।

// Call class factory.
Feature::make('some_feature')->render();
...->isEnabled();

// Make helper method.
feature('some_feature')->render();

// Make a blade directives.
@feature('some_feature')
@featureEnabled('some_feature')

0

मैंने अपने मामले में डेटाबेस पर एक नई तालिका बना रहा था, आप इसे Domainsउदाहरण के लिए कह सकते हैं ।

सभी विशिष्ट विशेषताओं को जोड़ें, जिन्हें कुछ डोमेन पर दिखाया जा सकता है, लेकिन बाकी में नहीं, क्योंकि उस तालिका के कॉलम में बूलियन मानों के लिए बिट। जैसे, मेरे मामले में allow_multiple_bookings,use_company_card ... जो भी हो।

फिर, एक वर्ग Domainऔर उसके संबंधित भंडार बनाने पर विचार करें , और अपने कोड पर इन मूल्यों को पूछें, जितना संभव हो उतना उस तर्क को अपने डोमेन (आपके मॉडल, एप्लिकेशन सेवाओं, आदि) में धकेलने का प्रयास करें।

उदाहरण के लिए, मैं नियंत्रक विधि पर चेक नहीं करूंगा, RequestBookingयदि जो डोमेन बुकिंग के लिए अनुरोध कर रहा है वह केवल एक या अधिक अनुरोध कर सकता है।

इसके बजाय मैं यह एक पर करते हैं RequestBookingValidatorService जो यह चेक कर सकता है कि बुकिंग डेटटाइम बीत चुका है या नहीं, उपयोगकर्ता के पास एक सक्षम क्रेडिट कार्ड है, ... या यह क्रिया जिस डोमेन से आती है उसे एक से अधिक बुकिंग का अनुरोध करने की अनुमति है (और तब यदि यह पहले से ही है कोई भी)।

यह पठनीयता की सुविधा जोड़ता है, जैसा कि आपने इस निर्णय को अपनी एप्लिकेशन सेवाओं पर धकेल दिया है। इसके अलावा, मुझे लगता है कि जब भी मुझे एक नई सुविधा की आवश्यकता होती है, तो मैं उस सुविधा को टेबल पर जोड़ने के लिए लारवेल (या सिम्फनी) माइग्रेशन का उपयोग कर सकता हूं और मैं अपनी पंक्तियों (आपके डोमेन) को उन मूल्यों के साथ भी अपडेट कर सकता हूं जो मैं उसी कमिट पर चाहता हूं जिसे मैंने कोडित किया था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.