sebafelis / RoboLynx.Umbraco.QRCodeGenerator

Property editor for Umbraco allowing to generate QR codes straight from Umbraco Backoffice.
MIT License
3 stars 2 forks source link

Documentation Clarification regarding dynamic URLs #4

Open danlance opened 10 months ago

danlance commented 10 months ago

Hi,

I have added this package to our Umbraco 11 app, and am successfully able to add a QR code to a Document Type and have this render within the template on the front end. I currently have the Source provider set to Absolute URL - and this results in the generate QR code referencing the URL of the page on which it is placed.

(I did find that the example given: https://github.com/sebafelis/RoboLynx.Umbraco.QRCodeGenerator#using-on-frontend-page did not work for me - I had to call @RoboLynx.Umbraco.QRCodeGenerator.Frontend.UrlHelperExtensionsForQRCodeGenerator.GetQRCodeUrl(Url,qrCode) - rather than just @Url.GetQRCodeUrl(qrCode) - presumably there's some other reference that I have missed here that I could not see in the documentation?)

I would like to update the URL which is referenced, to be suffixed by a hard coded value (either a query string or /path) so that the QR code points to {pageURL}/path.

I've looked at the documentation under https://github.com/sebafelis/RoboLynx.Umbraco.QRCodeGenerator#a-content-property - and I presume this is how I would configure this, setting the url argument dynamically... however I'm not clear on the necessary syntax in order to achieve this...

Would it be possible to provide feedback as to how this can be achieved - and maybe give slightly more detailed examples in the documentation which can be followed for those who are completely unfamiliar with the details?

Thanks.

sebafelis commented 8 months ago

Sorry for that late answer, but somehow I missed it notification about issue and message on linked.in.

Currently Absolute URL data source gets only current node URL (URL of document or media where QRCodeGenerator property is add). This data source will be extended and new one will be added in near future.

At this moment you have to two way:

  1. Most simple solution, but probably not enough for you:

    • You can simply create another property in the same document type where qr code is add.
    • Property should be of Textstring type. Name them i.e. myUrl.
    • Next go your qr code data type settings and set Source provider to Content Property. In Source provider settings field enter name of the propery what you create (myUrl in this example).
    • In Content section select document base on type that you modified and enter staticly the whole absolute URL what you want to pass to QR code.
  2. Second solution is more difficult and require to create a custom Source provider.

I don't know what you exacly wont to achive, but I wrote some example witch I hope it's help you. You need create two class inherit from QRCodeSource and QRCodeSourceFactory. Umbraco durning startup should find them automaticly.

public class CustomUrlSourceFactory : QRCodeSourceFactory
{
    private readonly IPublishedValueFallback _publishedValueFallback;
    private readonly IPublishedUrlProvider _publishedUrlProvider;

    public CustomUrlSourceFactory(ILocalizedTextService localizedTextService, IPublishedValueFallback publishedValueFallback, IPublishedUrlProvider publishedUrlProvider) : base(localizedTextService)
    {
        _publishedValueFallback = publishedValueFallback;
        _publishedUrlProvider = publishedUrlProvider;
    }

    public override string Id => "CustomUrl"; // Unique ID

       // Description and Name property don't need to be override. 
       // If you don't do this Name and Description will be geting from language file where you should add the follow tags:
       //<area alias="qrCodeSources">
       //   <key alias="customUrlSourceName">Custom URL</key>
       //   <key alias="customUrlSourceDescription">Description showing in blue border in data type configuration at Umbraco Backoffice.</key>
       //</area>
       // More about languange file => https://docs.umbraco.com/umbraco-cms/extending/language-files#user-language-files
    public override string Description => "Description showing in blue border in data type configuration at Umbraco Backoffice.";

    public override string Name => "Custom URL";

    public override IQRCodeSource Create(IPublishedContent publishedContent, string sourceSettings, string culture)
    {
        return new CustomUrlSource(_publishedUrlProvider, _publishedValueFallback, publishedContent, sourceSettings, culture);
    }
}
/// <summary>
/// Object gets an URL of current node (document or media) and add value of the other property from the same node to the end.
/// </summary>
public class CustomUrlSource : QRCodeSource
{
    private readonly IPublishedUrlProvider _publishedUrlProvider;
    private readonly IPublishedValueFallback _publishedValueFallback;
    private readonly IPublishedContent _content;
    private readonly string _sourceSettings;
    private readonly string _culture;

    public CustomUrlSource(IPublishedUrlProvider publishedUrlProvider, IPublishedValueFallback publishedValueFallback, IPublishedContent content, string sourceSettings, string culture) : base()
    {
        if (content is null)
        {
            throw new ArgumentNullException(nameof(content));
        }

        if (content.ContentType.ItemType == PublishedItemType.Member ||
            content.ContentType.ItemType == PublishedItemType.Element ||
            content.ContentType.ItemType == PublishedItemType.Unknown) // Only documents and media has an URL
        {
            throw new InvalidSettingQRCodeGeneratorException("codeSource", $"This source provider does not support {content.ItemType} nodes");
        }
        _publishedUrlProvider = publishedUrlProvider ?? throw new ArgumentNullException(nameof(publishedUrlProvider));
        _publishedValueFallback = publishedValueFallback ?? throw new ArgumentNullException(nameof(publishedValueFallback));
        _content = content;
        _sourceSettings = sourceSettings;
        _culture = culture;
    }

    public override T GetValue<T>(int index, string key)
    {
        var property = _content.GetProperty(_sourceSettings); // _sourceSettings is value of Source provider settings field. In this case should be name of Umbraco Document property containing the rest of URL address what you want to pass.
        if (property == null)
        {
            throw new SourceConfigurationQRCodeGeneratorException(GetType(), "Property not found.");
        }

        var urlSufix = property.Value(_publishedValueFallback, _culture);
        if (urlSufix is not string) { // In this case only property types that return string are support (e.g. Textstring). If you need more complex value type you need to get a correct value. 
            throw new SourceConfigurationQRCodeGeneratorException(GetType(), "Property value is not string.");
        }

        string url;
        switch (_content.ContentType.ItemType)
        {
            case PublishedItemType.Content:
                url = _publishedUrlProvider.GetUrl(_content, UrlMode.Absolute, _culture) + urlSufix;
                break;

            case PublishedItemType.Media:
                url = _publishedUrlProvider.GetMediaUrl(_content, UrlMode.Absolute, _culture, UmbracoCoreConstants.Conventions.Media.File) + urlSufix;
                break;

            default:
                throw new NotSupportedException();
        }

        // There is no validation in here. Basic validation of parameters is carried out in next level of qr code creating. 
                // Of course you can make more complex  validation in here and throw ValidationQRCodeGeneratorException if value is not valid.

        return (T)Convert.ChangeType(url, typeof(T));
    }
}

I you need more explenation, please write.