【问题标题】:XMLHttpRequest - append php function to .json?add_fields ajax requestXMLHttpRequest - 将 php 函数附加到 .json?add_fields ajax 请求
【发布时间】:2018-03-01 15:26:07
【问题描述】:

我正在尝试更新其他人的代码,该代码使用 XMLHttpRequest 设置从服务器获取产品信息以用于某些 SilverStripe 模板。我想从 Product.php 中获取 url() 函数,这样我就可以使用它来获取 Product 数据对象的 url 并将其发送到 Google Analytics。但是,简单地将其附加到现有的 add_fields 数据是行不通的——不会检索到 url 函数。

我对 XMLHttpRequests 不是很熟悉,所以我不知道在这里做什么。

这是获取产品数据的 JavaScript 代码:

document.addEventListener("DOMContentLoaded", function(event) {
    var productCatalogService = (function() {
        var endpoint = "/api/v1/Product/";

        return {
            'getProductById': function(id, callback) {
                var xhr = new XMLHttpRequest();
                xhr.open('GET', endpoint + id + ".json?add_fields=NutritionalInformationLabelURL,SortOrder,BeautyShotURL,url,Recipe"); //url function is not grabbed
                xhr.onload = function() {
                    if (xhr.status === 200) {
                        callback && callback(JSON.parse(xhr.responseText));
                    }
                    else {
                        console.error('Request failed.  Returned status of ' + xhr.status);
                    }
                };
                xhr.send();
            }
        };
    })();

    var utils = (function() {
        return {
            'removeClass': function(node, className) {
                node.className = node.className.replace(className, '');
                return node;
            },
            'addClass': function(node, className) {
                node.className = node.className.replace(className, '');
                node.className += " " + className;
            },
            'hasClass': function(node, className) {
                return node.className.indexOf(className) >= 0;
            }
        }
    })();

    var changeProduct = function(product) {

        var name = document.querySelector('.product-name'),
            subname = document.querySelector('.product-subname'),
            tagline = document.querySelector('.product-tagline'),
            description = document.querySelector('.product-description'),
            beautyShot = document.querySelector('.beauty-shot'),
            nutritionFacts = document.querySelector('.ingredients-list'),
            mobileNutritionLabel = document.querySelector('.mobile-nutrition-label img'),
            nutritionLabel = document.querySelector('.nutritional-label img'),
            recipeName = document.querySelector('.recipe-name'),
            recipeDescription = document.querySelector('.recipe-description'),
            recipeContainer = document.querySelector('.recipe-container');

        name.innerHTML = product.Name;
        subname.innerHTML = product.SubName;
        description.innerHTML = product.Description;
        tagline.innerHTML = product.Tagline;
        beautyShot.src = product.BeautyShotURL;
        if(product.NutritionalInformationLabelURL){
            nutritionLabel.src = product.NutritionalInformationLabelURL;
            mobileNutritionLabel.src = product.NutritionalInformationLabelURL;
        }

        if(product.NutritionFacts){
            nutritionFacts.innerHTML = product.NutritionFacts;
            if(utils.hasClass(nutritionFacts, 'hidden')) {
                utils.removeClass(nutritionFacts, 'hidden');
            }
        } else {
            utils.addClass(nutritionFacts, 'hidden');
        }


       // var pagePath = product.url();

        console.log(product.url); //returns undefined
        typeof(ga) !== "undefined" &&  ga('send', 'pageview', {
            'page': location.pathname, //want to use the url() function in Product.php here
            'title': product.PageTitle
        });
    };

    NodeList.prototype.forEach = Array.prototype.forEach;
    var products = document.querySelectorAll('.carousel-products .product');
    products.forEach(function(product) {
        product.onclick = function() {
            var productId = product.getAttribute('data-product-id');

            productCatalogService.getProductById(productId, function(product) {
                console.log(product);
                changeProduct(product); //add recipe data to be pulled in here (fields are above)
            });
        };
    });
});

产品.php

<?php
class Product extends DataObject implements Pageable, Searchable {
    private static $api_access = true;

    private static $db = [
        'Name' => 'varchar(255)',
        'SubName' => 'varchar(255)',
        'Tagline' => 'varchar(255)',
        'Description' => 'HTMLText',
        'WhereToBuy' => 'varchar(500)', // external link
        'NutritionFacts' => 'HTMLText',
        'PageTitle'             => 'varchar(250)',
        'MetaKeywords'          => 'Text',
        'MetaDescription'       => 'Text',
        'SortOrder'             =>'Int'
    ];

    private static $has_one = [
        'BeautyShot' => 'Image',
        'ThumbImage' => 'Image',
        'NutritionalInformationLabel' => 'Image',
        'Category' => 'Category',
    ];

    private static $summary_fields = [
        'GridThumbnail' => 'Photo',
        'Name' => 'Name'
    ];

    public function getCMSFields() {
        $fields = parent::getCMSFields();

        $fields->addFieldToTab('Root.Main',  new TextField("Name", "Name"));
        $fields->addFieldToTab('Root.Main',  new TextField("SubName", "SubName"));
        $fields->addFieldToTab('Root.Main',  new TextField("Tagline", "Tagline"));
        $fields->addFieldToTab("Root.Main", new HtmlEditorField("Description", "Description"));
        $fields->addFieldToTab('Root.Main', new TextField("WhereToBuy", "WhereToBuy"));
        $fields->addFieldToTab("Root.Main", new HtmlEditorField("NutritionFacts", "NutritionFacts"));
        $fields->addFieldToTab("Root.Main", new UploadField("BeautyShot", "BeautyShot"));
        $fields->addFieldToTab("Root.Main", new UploadField("ThumbImage", "ThumbImage"));
        $fields->addFieldToTab("Root.Main", new UploadField("NutritionalInformationLabel", "NutritionalInformationLabel"));

        $fields->addFieldToTab('Root.SEO',  new TextField("PageTitle", "PageTitle"));
        $fields->addFieldToTab('Root.SEO',  new TextareaField("MetaKeywords", "MetaKeywords"));
        $fields->addFieldToTab('Root.SEO',  new TextareaField("MetaDescription", "MetaDescription"));
        $fields->removeByName('SortOrder');

        return $fields;
    }

    public function getGridThumbNail() {
        if ($this->BeautyShot()->exists()) {
            return $this->BeautyShot()->SetWidth(100);
        }

        return '(no image)';
    }

    public function getBeautyShotURL() {
        return $this->BeautyShot()->URL;
    }

    public function getNutritionalInformationLabelURL() {
        if ($this->NutritionalInformationLabel()->Exists()) {
            return $this->NutritionalInformationLabel()->URL;
        } else {
            return "";
        }
    }

    public function getCouponImageURL() {
        if ($this->CouponImage()->Exists()) {
            return $this->CouponImage()->URL;
        } else {
            return "";
        }
    }

    public function getProductFullName(){
        return $this->Name." ".$this->SubName;

    }

    public function AbsoluteLink() {
        return Director::absoluteURL($this->url());
    }

    private function url() {
        return sprintf("/home/products/%s/%s", $this->Category()->slug(), $this->slug());
    }

    // lifted from Artisa
    public function MetaTags() {
        $tags = "";

        $generator = trim(Config::inst()->get('SiteTree', 'meta_generator'));
        if (!empty($generator)) {
            $tags .= "<meta name=\"generator\" content=\"" . Convert::raw2att($generator) . "\" />\n";
        }

        $charset = Config::inst()->get('ContentNegotiator', 'encoding');
        $tags .= "<meta http-equiv=\"Content-type\" content=\"text/html; charset=$charset\" />\n";
        if($this->MetaDescription) {
            $tags .= "<meta name=\"description\" content=\"" . Convert::raw2att($this->MetaDescription) . "\" />\n";
        }
        if($this->MetaKeywords) {
            $tags .= "<meta name=\"keywords\" content=\"" . Convert::raw2att($this->MetaKeywords) . "\" />\n";
        }

        if(Permission::check('CMS_ACCESS_CMSMain')
            && in_array('CMSPreviewable', class_implements($this))
            && !$this instanceof ErrorPage
            && $this->ID > 0
        ) {
            $tags .= "<meta name=\"x-page-id\" content=\"{$this->ID}\" />\n";
            $tags .= "<meta name=\"x-cms-edit-link\" content=\"" . $this->CMSEditLink() . "\" />\n";
        }

        $this->extend('MetaTags', $tags);

        return $tags;
    }

    public function canView($member = null){
        return true;
    }

    public function canEdit($member = null) {
        return true;
    }

    public function canCreate($member = null) {
        return true;
    }

    public function slug()
    {
        return Utilities::friendlyName($this->Name);
    }

    public function Link()
    {
        return $this->url();
    }

    public function getTitleFields() {
        return ['Name', 'SubName'];
    }

    public function getContentFields() {
        return ['Description'];
    }

    public static function getSearchFilter() {
        return [];
    }
}

// Handles Products and categories
class ProductCsvBulkImporter extends CsvBulkLoader {
    protected function processRecord($record, $columnMap, &$results, $preview = false) {
        $categoryName = $record['Main Category'];
        $productName = $record['Product ID'];
        $productSubName = $record['Product Type'];
        $productTagline = $record['Product Label'];
        $productDescription = $record['Product Description'];
        $productKeywords = $record['Keyphrase'];

        $category = Category::get()
            ->filter(['Name' => $categoryName])
            ->first();

        if (!$category) {
            $category = new Category();
            $category->Name = $categoryName;
            $category->write();
        }

        $product = Product::get()
            ->filter(['Name' => $productName])
            ->first();

        if (!$product) {
            $product = new Product();
        }

        $product->PageTitle = sprintf("%s %s", $productName, $productSubName);
        $product->Name = $productName;
        $product->SubName = $productSubName;
        $product->Tagline = $productTagline;
        $product->Description = $productDescription;
        $product->MetaKeywords = $productKeywords;
        $product->CategoryID = $category->ID;
        $product->write();
        return $product->ID;
    }
}

我不知道现在设置的代码是否是最佳实践,因为我没有做到,所以如果有错误,我无法确定。

有没有办法将 url() 函数从 Product.php 附加到 .json?add_fields ajax 响应?

【问题讨论】:

    标签: javascript php xmlhttprequest silverstripe


    【解决方案1】:

    正如您在 Product 类中看到的,url() 方法是 private,因此您无法在该类之外访问它:

    private function url() {
        return sprintf("/home/products/%s/%s", $this->Category()->slug(), $this->slug());
    }
    

    如果您将其更改为:

    public function url() {
        return sprintf("/home/products/%s/%s", $this->Category()->slug(), $this->slug());
    }
    

    它可能会起作用...根据您提交的代码,我只能这么说。你应该知道,url() 方法是私有的可能是有原因的——很可能它只在 Product 类内部使用。

    如果它仍然不起作用,请尝试像这样复制该功能:

    public function getUrl() {
        return sprintf("/home/products/%s/%s", $this->Category()->slug(), $this->slug());
    }
    

    ...然后在 JS 代码中你可以这样使用它:

    console.log(product.Url);
    

    如您所见,您在 JS 代码中有这样的调用:product.BeautyShotURL,但Product 类中的实际方法称为getBeautyShotURL(),因此它应该与product.Url 一起使用(这也可能努力工作:product.getUrl)

    【讨论】:

    • 如果由于某种原因,您不能或不允许更改 Product.php 中的代码,请告诉我,我将向您展示如何通过添加来扩展 Product 类的功能一个新的 getUrl() 方法到一个新的类(称为 DataExtension 类)中。
    猜你喜欢
    • 2022-01-05
    • 2013-12-12
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    • 2012-05-02
    • 1970-01-01
    • 2017-08-26
    • 2013-07-03
    相关资源
    最近更新 更多