2016-06-07 6 views
1

Ich habe einen Inhaltsteil, der eine Begin Timestamp und End Timestamp Option bietet. Diese 2 Felder werden verwendet, um einen Zeitraum zu definieren, in dem der Inhalt angezeigt werden soll.Wie kann ich die Anzeige eines Inhalts in Orchard CMS überspringen?

Ich habe jetzt Schwierigkeiten, einen Skip-Ansatz zu implementieren, während Inhaltselemente nicht angezeigt/übersprungen werden sollten, wenn die Zeitspanne nicht die aktuelle Zeit umfasst.

Graben in dem Quellcode und zu versuchen, einen Einstiegspunkt für meinen Ansatz zu finden, ergaben den folgenden Content-Handler

public class SkipContentHandler : Orchard.ContentManagement.Handlers.ContentHandler 
{ 
    protected override void BuildDisplayShape(Orchard.ContentManagement.Handlers.BuildDisplayContext aContext) 
    { 
    if (...) // my condition to process only content shapes which need to be skipped 
    { 
     aContext.Shape = null; // return null shape to skip it 
    } 
    } 
} 

Dies funktioniert, aber es gibt einige Nebenwirkungen

  • musste ich ändern der Quellcode von BuildDisplayContext als Shape ist normalerweise nur lesbar
  • List Shape möglicherweise einen falschen Pager angezeigt, wenn es Inhaltselemente mit meinem Inhalt Teil enthält, weil die Count() Anruf in ContainerPartDriver.Display() wird ausgeführt, bevor BuildDisplay()
  • die URL eines Content-Objekts aufrufen, die Ergebnisse in einer Ausnahme übersprungen, weil View(null) abigious ist

Also, was hier der richtige Ansatz wäre, oder gibt es ein Modul in Existenz, die den Job macht? Ich konnte keinen finden.

+1

Sie könnten in Erwägung ziehen, stattdessen nur ein "Unpublish" -Ereignis zu registrieren, wenn die Zeitspanne abläuft – devqon

+0

@devqon Ja, ich dachte darüber nach . Dies würde jedoch eine Art Hintergrundaufgabe erfordern, die regelmäßig ausgeführt wird, und diese Aufgabe muss alle Inhaltselemente abfragen, um nach den richtigen zu suchen, um die Veröffentlichung rückgängig zu machen. Außerdem bin ich kein Fan von der Aufhebung der Veröffentlichung, da dies den Benutzer verwirren könnte, der zuvor auf die Schaltfläche zum Veröffentlichen geklickt hatte. Ich hoffe immer noch, dass es eine Möglichkeit gibt, das Rendern einer Form auf sichere Weise irgendwie abzubrechen ... – ViRuSTriNiTy

+0

Es kann sein, dass Sie das Rendern stoppen können, aber dann haben Sie immer noch Probleme mit der Zählung, wie Sie erwähnt haben. Aus diesem Grund schlägt das Paging wahrscheinlich fehl und wahrscheinlich auch mehr. – devqon

Antwort

1

Dies ist eine ziemlich komplexe Aufgabe. Es gibt mehrere Schritte erforderlich eine richtige Überspringen der Anzeigeelemente zu erreichen:

  1. den Teil erstellen richtig

    Es gibt einige Fallen hier wie bei der Zugabe einer Teilansicht auf die Aufgabe kommt man könnte Orchards Datum Zeit Editor in Verbindung mit den DateTime Eigenschaften verwenden. Aber das bringt eine Menge zusätzlicher Probleme auf den Tisch, aber diese beziehen sich nicht wirklich auf die Frage.

    Wenn jemand daran interessiert ist, wie man Orchards Date Time Editor benutzt, dann kann ich diesen Code auch posten, aber für den Moment würde es den Code nur unnötig in die Luft jagen.

    So hier gehen wir, die Teil der Klasse ...

    public class ValidityPart : Orchard.ContentManagement.ContentPart<ValidityPartRecord> 
    { 
        // public 
        public System.DateTime? ValidFromUtc 
        { 
         get { return Retrieve(r => r.ValidFromUtc); } 
         set { Store(r => r.ValidFromUtc, value); } 
        } 
    
        ... 
    
        public System.DateTime? ValidTillUtc 
        { 
         get { return Retrieve(r => r.ValidTillUtc); } 
         set { Store(r => r.ValidTillUtc, value); } 
        } 
    
        ... 
    
        public bool IsContentItemValid() 
        { 
         var lUtcNow = System.DateTime.UtcNow; 
    
         return (ValidFromUtc == null || ValidFromUtc.Value <= lUtcNow) && (ValidTillUtc == null || ValidTillUtc.Value >= lUtcNow); 
        } 
    
        ... 
    } 
    

    ... und die Datensatzklasse ...

    public class ValidityPartRecord : Orchard.ContentManagement.Records.ContentPartRecord 
    { 
        // valid from value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections 
        // (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue) 
        public virtual System.DateTime? ValidFromUtc { get; set; } 
    
        // valid from value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections 
        // (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue) 
        public virtual System.DateTime? ValidTillUtc { get; set; } 
    } 
    
  2. erstellen individuell angepasste Inhalt Abfrageklasse

    public class MyContentQuery : Orchard.ContentManagement.DefaultContentQuery 
    { 
        // public 
        public ContentQuery(Orchard.ContentManagement.IContentManager aContentManager, 
         Orchard.Data.ITransactionManager aTransactionManager, 
         Orchard.Caching.ICacheManager aCacheManager, 
         Orchard.Caching.ISignals aSignals, 
         Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentTypeRecord> aContentTypeRepository, 
         Orchard.IWorkContextAccessor aWorkContextAccessor) 
         : base(aContentManager, aTransactionManager, aCacheManager, aSignals, aContentTypeRepository) 
        { 
         mWorkContextAccessor = aWorkContextAccessor; 
        } 
    
        protected override void BeforeExecuteQuery(NHibernate.ICriteria aContentItemVersionCriteria) 
        { 
         base.BeforeExecuteQuery(aContentItemVersionCriteria); 
    
         // note: 
         // this method will be called each time a query for multiple items is going to be executed (e.g. content items of a container, layers, menus), 
         // this gives us the chance to add a validity criteria 
    
         var lWorkContext = mWorkContextAccessor.GetContext(); 
    
         // exclude admin as content items should still be displayed/accessible when invalid as validity needs to be editable 
         if (lWorkContext == null || !Orchard.UI.Admin.AdminFilter.IsApplied(lWorkContext.HttpContext.Request.RequestContext)) 
         { 
         var lUtcNow = System.DateTime.UtcNow; 
    
         // left outer join of ValidityPartRecord table as part is optional (not present on all content types) 
         var ValidityPartRecordCriteria = aContentItemVersionCriteria.CreateCriteria(
          "ContentItemRecord.ValidityPartRecord", // string adopted from foreach loops in Orchard.ContentManagement.DefaultContentQuery.WithQueryHints() 
          NHibernate.SqlCommand.JoinType.LeftOuterJoin 
         ); 
    
         // add validity criterion 
         ValidityPartRecordCriteria.Add( 
          NHibernate.Criterion.Restrictions.And(
          NHibernate.Criterion.Restrictions.Or(
           NHibernate.Criterion.Restrictions.IsNull("ValidFromUtc"), 
           NHibernate.Criterion.Restrictions.Le("ValidFromUtc", lUtcNow) 
          ), 
          NHibernate.Criterion.Restrictions.Or(
           NHibernate.Criterion.Restrictions.IsNull("ValidTillUtc"), 
           NHibernate.Criterion.Restrictions.Ge("ValidTillUtc", lUtcNow) 
          ) 
         ) 
         ); 
         } 
        } 
    
        // private 
        Orchard.IWorkContextAccessor mWorkContextAccessor; 
    } 
    

    Dies fügt im Wesentlichen einen linken Join der Geltungsteilfelder hinzu an die SQL-Abfrage (Inhaltsabfrage) und erweitert die WHERE-Anweisung mit der Gültigkeitsbedingung.

    Bitte beachten Sie, dass dieser Schritt mit der Lösung nur möglich ist, das folgende Problem beschrieben: https://github.com/OrchardCMS/Orchard/issues/6978

  3. den Inhalt Abfrageklasse Registrieren

    public class ContentModule : Autofac.Module 
    { 
        protected override void Load(Autofac.ContainerBuilder aBuilder) 
        { 
        aBuilder.RegisterType<MyContentQuery>().As<Orchard.ContentManagement.IContentQuery>().InstancePerDependency(); 
        } 
    } 
    
  4. erstellen ein maßgeschneidertes Content-Manager

    public class ContentManager : Orchard.ContentManagement.DefaultContentManager 
    { 
        // public 
        public ContentManager(
         Autofac.IComponentContext aContext, 
         Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentTypeRecord> aContentTypeRepository, 
         Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentItemRecord> aContentItemRepository, 
         Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentItemVersionRecord> aContentItemVersionRepository, 
         Orchard.ContentManagement.MetaData.IContentDefinitionManager aContentDefinitionManager, 
         Orchard.Caching.ICacheManager aCacheManager, 
         System.Func<Orchard.ContentManagement.IContentManagerSession> aContentManagerSession, 
         System.Lazy<Orchard.ContentManagement.IContentDisplay> aContentDisplay, 
         System.Lazy<Orchard.Data.ITransactionManager> aTransactionManager, 
         System.Lazy<System.Collections.Generic.IEnumerable<Orchard.ContentManagement.Handlers.IContentHandler>> aHandlers, 
         System.Lazy<System.Collections.Generic.IEnumerable<Orchard.ContentManagement.IIdentityResolverSelector>> aIdentityResolverSelectors, 
         System.Lazy<System.Collections.Generic.IEnumerable<Orchard.Data.Providers.ISqlStatementProvider>> aSqlStatementProviders, 
         Orchard.Environment.Configuration.ShellSettings aShellSettings, 
         Orchard.Caching.ISignals aSignals, 
         Orchard.IWorkContextAccessor aWorkContextAccessor) 
         : base(aContext, aContentTypeRepository, aContentItemRepository, aContentItemVersionRepository, aContentDefinitionManager, aCacheManager, aContentManagerSession, 
          aContentDisplay, aTransactionManager, aHandlers, aIdentityResolverSelectors, aSqlStatementProviders, aShellSettings, aSignals) 
        { 
         mWorkContextAccessor = aWorkContextAccessor; 
        } 
    
        public override ContentItem Get(int aId, Orchard.ContentManagement.VersionOptions aOptions, Orchard.ContentManagement.QueryHints aHints) 
        { 
         var lResult = base.Get(aId, aOptions, aHints); 
    
         if (lResult != null) 
         { 
         // note: 
         // the validity check is done here (after the query has been executed!) as changing base.GetManyImplementation() to 
         // apply the validity critera directly to the query (like in ContentQuery) will not work due to a second attempt to retrieve the 
         // content item from IRepository<> (see base.GetManyImplementation(), comment "check in memory") when the query 
         // returns no data (and the query should not return data when the validity critera is false) 
         // 
         // http://stackoverflow.com/q/37841249/3936440 
    
         var lWorkContext = mWorkContextAccessor.GetContext(); 
    
         // exclude admin as content items should still be displayed/accessible when invalid as validity needs to be editable 
         if (lWorkContext == null || !Orchard.UI.Admin.AdminFilter.IsApplied(lWorkContext.HttpContext.Request.RequestContext)) 
         { 
          var lValidityPart = lResult.As<ValidityPart>(); 
          if (lValidityPart != null) 
          { 
          if (lValidityPart.IsContentItemValid()) 
          { 
           // content item is valid 
          } 
          else 
          { 
           // content item is not valid, return null (adopted from base.Get()) 
    
           lResult = null; 
          } 
          } 
         } 
         } 
    
         return lResult; 
        } 
    
        // private 
        Orchard.IWorkContextAccessor mWorkContextAccessor; 
    } 
    

Die Schritte 2-4 werden benötigt, wenn Inhaltselemente vorhanden sind, während der Inhaltstyp einen Container und Containable Teil oder sogar Inhaltselemente hat, die separat verarbeitet/angezeigt werden. Hier können Sie die Inhaltsabfrage, die hinter den Kulissen ausgeführt wird, normalerweise nicht anpassen.

Schritte 2-4 sind nicht erforderlich, wenn Sie das Projektionsmodul verwenden. Aber noch einmal, dies bringt ein paar andere Probleme auf den Tisch, wie in dieser Ausgabe berichtet: https://github.com/OrchardCMS/Orchard/issues/6979

Verwandte Themen