/
www
/
wwwroot
/
alo88.autos
/
wp-content
/
plugins
/
wp-content-crawler
/
app
/
Objects
/
Filtering
/
Property
/
Strings
/
Upload File
HOME
<?php /** * Created by PhpStorm. * User: turgutsaricam * Date: 27/06/2020 * Time: 08:01 * * @since 1.11.0 */ namespace WPCCrawler\Objects\Filtering\Property\Strings; use DOMElement; use Exception; use Symfony\Component\DomCrawler\Crawler; use WPCCrawler\Objects\Crawling\Bot\DummyBot; use WPCCrawler\Objects\Enums\ValueType; use WPCCrawler\Objects\Filtering\Commands\Base\AbstractBaseCommand; use WPCCrawler\Objects\Filtering\Commands\CommandUtils; use WPCCrawler\Objects\Filtering\Commands\Views\ViewDefinitionFactory; use WPCCrawler\Objects\Filtering\Commands\Views\ViewDefinitionList; use WPCCrawler\Objects\Filtering\Enums\PropertyKey; use WPCCrawler\Objects\Filtering\Property\Base\AbstractActionProperty; use WPCCrawler\Objects\Filtering\Property\Objects\AttributeValue; use WPCCrawler\Objects\Filtering\Property\Objects\CalculationResult; class StringElementAttributeProperty extends AbstractActionProperty { /** * @var array Structured as [string => string]. Maps property keys to original subject keys. The values are actual * dot keys of the subject items. The keys are the keys of the property values calculated from the original * subject item. This is used to know which property key belongs to which subject key so that we can recreate * the original structure of the subject item by putting the new values back into their specific place. */ private $keyMap = []; /** * @var array Structured as [string => {@link Crawler}]. The keys are the keys of the sources. The values are * {@link Crawler} versions of the sources. */ private $crawlersIndex = []; /** * @var array Structured as [string => array]. The keys are the keys of sources. The values are arrays structured * as [string => {@link Crawler}]. The keys are structured as "$key.{@link KEY_SEPARATOR}.(index as int)" */ private $extractedElementsIndex = []; /** @var null|string Stores the attribute option's value */ private $attribute = null; public function getKey(): string { return PropertyKey::STRING_ELEMENT_ATTR_VALUE; } public function getName(): string { return _wpcc('Element attribute value'); } public function getInputDataTypes(): array { return [ValueType::T_STRING]; } public function getOutputDataTypes(): array { return [ValueType::T_STRING]; } protected function createViews(): ?ViewDefinitionList { $viewDefinitionFactory = ViewDefinitionFactory::getInstance(); return (new ViewDefinitionList()) ->add($viewDefinitionFactory->createMultipleCssSelectorInput()) ->add($viewDefinitionFactory->createElementAttributeInput()); } protected function onCalculate($key, $source, AbstractBaseCommand $cmd): ?array { // If the source is not a string, do not try to create a Crawler from it. if (!is_string($source)) return null; $commandUtils = new CommandUtils(); // Get the attribute $this->attribute = $commandUtils->getElementAttributeOption($cmd); if ($this->attribute === null) return null; // Get the CSS selectors $selectorOption = $commandUtils->getCssSelectorsOption($cmd); if ($selectorOption === null) return null; // Cast the given value to string and create a Crawler from it $bot = new DummyBot([]); $crawler = $bot->createDummyCrawler((string) $source); // Find the elements matching the selectors and collect them in an array, as well as their attributes $elements = []; $attributes = []; $results = []; foreach($selectorOption as $selectorData) { $nodes = $bot->getElementsFromCrawler($crawler, $selectorData); if ($nodes === null) continue; foreach($nodes as $node) { $domNode = $node->getNode(0); if (!$domNode) continue; // Use the node's path in the DOM document as a unique identifier for this node. $elementKey = $key . static::KEY_SEPARATOR . $domNode->getNodePath(); // If this node was processed earlier, do not process it again. Continue with the next one. if (isset($this->keyMap[$elementKey])) continue; // Get the attribute value. If it is null continue with the next node. $attrValue = $this->getAttributeValue($node, $this->attribute); if ($attrValue === null) continue; $elementAttr = $attrValue->getValue(); $this->keyMap[$elementKey] = $key; $elements[$elementKey] = $node; $attributes[$elementKey] = $elementAttr; // Add a new result $results[] = new CalculationResult($elementKey, $elementAttr); } } // Store the crawler and the elements since we need them to remap the new values into their original places. $this->crawlersIndex[$key] = $crawler; $this->extractedElementsIndex[$key] = $elements; return $results; } protected function onRevertStructure(array $newSubjectValues): ?array { if ($this->attribute === null) return null; // Put the new values into their specific places foreach($newSubjectValues as $elementKey => $newSubjectValue) { // Get the actual subject key $subjectKey = $this->keyMap[$elementKey] ?? null; // If we could not retrieve the subject key, continue with the next one. if ($subjectKey === null) continue; // Get the elements of the current subject key $extractedElements = $this->extractedElementsIndex[$subjectKey] ?? null; if ($extractedElements === null) continue; // Get the Crawler object of the element for the current property key /** @var Crawler|null $node */ $node = $extractedElements[$elementKey] ?? null; if ($node === null) continue; // Now, set the node's new attribute value. /** @var DOMElement|null $domNode */ $domNode = $node->getNode(0); if ($domNode === null) continue; try { if ($newSubjectValue !== null) { $domNode->setAttribute($this->attribute, $newSubjectValue); } else { $domNode->removeAttribute($this->attribute); } } catch (Exception $e) { continue; } } // All attributes are set. Now, get the HTML from the Crawlers. $bot = new DummyBot([]); $results = []; foreach($this->crawlersIndex as $subjectKey => $crawler) { /** @var Crawler $crawler */ $results[$subjectKey] = $bot->getContentFromDummyCrawler($crawler); } return $results; } /* * */ /** * Get value of an attribute of an element * * @param Crawler|null $node The node whose attribute is wanted * @param string|null $attr The attribute's name * @return AttributeValue|null If found, an {@link AttributeValue}. Otherwise, null. If this is null, the attribute * will not be considered. If an {@link AttributeValue} with its value set to null is * returned, the attribute will probably be removed from its element. So, if the * attribute should be removed from its element, return an {@link AttributeValue} by * setting its value to null. If you want to skip this attribute, return null. * @since 1.11.0 */ protected function getAttributeValue(?Crawler $node, ?string $attr): ?AttributeValue { $value = (new CommandUtils())->getAttributeValue($node, $attr, false); return new AttributeValue($value); } }