Can someone explain me this code please?

Silverstripe Version: 3.6 to 4.5.2 conversion

I have problems to understand what the following code does. I obviously am not so deep into SilverStripe and PHP (self-taught) that is makes sense to me - How does it all fit together especially the return statement?

The code worked in SS3.6, but now with only adding use and namespace it doesn’t work. The link doesn’t get shown as link anymore but as normal text (I agree to the Returns Terms + Conditions on the Returns page.) - funny, here it gets shown as a link just as I want it to be, but in the browser it shows <a class=“tandc” href="/resources/returns/#returns" target=“new” title=“Read the terms and conditions”>Returns</a>

  • as I actually expected it to do in the first place, but it obviously worked somehow in SS3.6
<?php
namespace MyNamespace;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\CMS\Model\SiteTree;
/**
 * Terms and conditions checkbox field that must be checked to be valid.
 */
class TermsAndConditionsCheckboxField extends CheckboxField
{
    protected $termsPage = null;
    public function __construct($name = "AgreeToTermsAndConditions", $title = null)
    {
        $this->name = $name;
        $title = $title ? $title : $this->getTitleContent();
        parent::__construct($name, $title);
    }
    public function setTermsPage(SiteTree $page) {
        $this->termsPage = $page;
        $this->title = $this->getTitleContent(); // set new title
        return $this;
    }
    public function getTitleContent()
    {
        if (!$this->termsPage) {
            return _t($this->class.'.Content', 'I agree to the terms and conditions');
        }
        return _t(
            $this->class.'.PageLinkContent',
            'I agree to the Returns Terms + Conditions on the <a class="tandc" href="{TermsPageLink}#returns" target="new" title="Read the terms and conditions">{TermsPageTitle}</a> page.',
            '',
            array(
                'TermsPageLink' => $this->termsPage->Link(),
                'TermsPageTitle' => $this->termsPage->Title
            )
        );
    }
    public function validate($validator)
    {
        if ($this->value) {
            return true;
        }
        $validator->validationError(
            $this->name,
            _t($this->class.".MustAgreeToTerms", "You must agree to the terms and conditions"),
            "required"
        );
        return false;
    }
}

By the way there is also nowhere a PageLinkContent

Obviously I would like to know how I can convert it as well, so it works in SS4.5.2.

Thank you very much.

Kim

The template parser is probably playing it safe and escaping the text that is being returned, which is why you see the markup in the browser.

The quickest way around it is probably to force the method to return an html fragment which the parser will then know how to handle:

public function getTitleContent()
  {
    if (!$this->termsPage) {
      $title = _t($this->class.'.Content', 'I agree to the terms and conditions');
    }
    else {
      $title = _t(
            $this->class.'.PageLinkContent',
            'I agree to the Returns Terms + Conditions on the <a class="tandc" href="{TermsPageLink}#returns" target="new" title="Read the terms and conditions">{TermsPageTitle}</a> page.',
            '',
            [
                'TermsPageLink' => $this->termsPage->Link(),
                'TermsPageTitle' => $this->termsPage->Title
            ]
        );
      }

      return DBField::create_field('HTMLFragment', $title);

    }

Hi DorsetDigital,
Thank you very much for that code.
It works perfectly fine, but how did you know how to solve it this way?

I don’t understand the construct of the $title. My understanding is that the _t() is for translation, but then the

$this->class.'.PageLinkContent',
            'I agree to the Returns Terms + Conditions on the <a class="tandc" href="{TermsPageLink}#returns" target="new" title="Read the terms and conditions">{TermsPageTitle}</a> page.',
            '',
            [
                'TermsPageLink' => $this->termsPage->Link(),
                'TermsPageTitle' => $this->termsPage->Title
            ]
is the part I don't understand how it fits into the creation of this checkbox.

If you don’t have the time to explain this to me, I completely get this, but could you give me a hint how/where I could find out/ read about it, please?

Thanks,
Kim

Hi,

You’re right, the _t() method deals with the translated text (https://docs.silverstripe.org/en/4/developer_guides/i18n/#the-t-function)

So… the parameters are:

  • Entity Name - this is a unique identifier for the translated entity. You usually use the classname as part of it to help avoid collisions. It’s this identifier which is used in your XML language files to provide alternative language versions. (https://docs.silverstripe.org/en/4/developer_guides/i18n/#language-definitions)
  • Default value - this is the default value for the translation in the event it’s not defined elsewhere (ie. in a language file).
  • Comment field (not used in this case)
  • Optional array of variables - This is an array which allows you to add dynamically generated text to the translated string. You’ll see that the keys in the array correspond to the placeholders in the default string ({TermsPageLink} for example). In this case, one is being fetched from a method on the related termsPage, and the other is the ‘Title’ property of the same related page.

In terms of how this relates to the creation of the checkbox… it’s providing some additional functionality that isn’t included in the default implementation. It’s allowing a translated string with some dynamic content to be used in the checkbox label, so it doesn’t end up being hard-coded.

Hopefully that makes sense!

Hi,
Yes, it makes sense now. Thank you very much for taking the time for this explanation!

Just one last questions. Why did this mix of HTML and text work in version 3.x and how did you know to use the HTMLFragment and to use it this way:

DBField::create_field(‘HTMLFragment’, $title);

I was first experimenting with the $casting, but I guess that didn’t work due to the _t() function?

private static $casting = [
        'MyCustomMethod' => 'HTMLText' 
    ];

Thank you,
Kim

Silverstripe 4 contains quite a lot of minor differences like this! I suspect the rationale was to improve consistency and most likely security. If I’m honest, I’m not sure how I originally found out about those methods… it’s just one of those things I learned along the way :slight_smile:

In case you haven’t already found it, there’s a section in the docs about casting, escaping, etc. here: https://docs.silverstripe.org/en/4/developer_guides/templates/casting/#casting

Yes, I thought it might be one of those things you learn by experience… thank you anyway.
Yes, I had a look at this document about casting before I put this question up, that’s where I got the idea of the previous mentioned $casting had from, but it didn’t work.
I also had another closer look when you came up with the solution and I read about the HTMLFragment further down the page, but I wouldn’t have figured out how to use it in the way you provided.
Anyway, thank you very much for your solution and all your explanations!
Have a great weekend.