NotionCommotion Posted October 12, 2019 Share Posted October 12, 2019 For right or wrong, I've been using XML to define my Doctrine entities. When the XML changes, my entities need to change. I've automated the process with a simple PHP script which allows me to swap some text to modify one of the auto-generated methods, add methods, etc. Kind of clunky but it works well enough. Now, I recently had the need to remove a given method in its entirety from a given class. I "could" just add the entire string which represents the method name, earlier comments, and script for the method to my parsing script to my parsing script and remove it, but would like to be a little more concise. For instance, say I have $script as follows: $script = <<<'EOT' class SomeEntityClass { //... more stuff above public function getSomething() { return $this->something; } /** * Get foos. * * @return \Doctrine\Common\Collections\Collection */ public function getFoos() { return $this->foos; } /** * Get somethingElse. * */ //... more stuff below } EOT; How would you recommend creating the function: removeFunction($script, 'getFoos') which would remove the given function along with its comments from the $script string and result with? $script = <<<'EOT' class SomeEntityClass { //... more stuff above public function getSomething() { return $this->something; } /** * Get somethingElse. * */ //... more stuff below } EOT; Assuming regex is the way to go, I was thinking of something like the following, but could use some help with the regex expression. function removeFunction($script, $method) { $method="public function $method("; //regex to remove script with which starts after pattern "{\n" OR "**/", contains $method, and is located before pattern "\n{" OR "\n /**" return $script; } Thanks Quote Link to comment Share on other sites More sharing options...
requinix Posted October 12, 2019 Share Posted October 12, 2019 Your entities should not be changing so frequently that you feel a need to automate updating the code... Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted October 13, 2019 Author Share Posted October 13, 2019 12 hours ago, requinix said: Your entities should not be changing so frequently that you feel a need to automate updating the code... I agree they shouldn't be but they are and thus the desire to automate. Quote Link to comment Share on other sites More sharing options...
requinix Posted October 13, 2019 Share Posted October 13, 2019 9 hours ago, NotionCommotion said: I agree they shouldn't be but they are and thus the desire to automate. Implied in my reply was "you should look into why this is and deal with it accordingly". It's a symptom of a problem. If there are business needs that are changing, the problem is that the business doesn't know what it wants to do, and there needs to be more planning and thinking before rushing into development. If there are programming needs that change then... well, actually, there needs to be more planning and thinking before rushing into development for that too. That aside, in your shoes, I would regenerate the code every time. Use those files as a base and put your own implementation into, for example, traits - a thing that can be easily added into a class. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted October 13, 2019 Author Share Posted October 13, 2019 Unfortunately, I am the cause of the problem, but I am getting it under control. Trying to improve my skills regarding entities and modelling and have been making some changes along the way. Before automating the process, I would make some changes to the XML file, regenerate the entities, and it was time consuming to identified what was changed. Using annotations in the PHP file wouldn't result in these issues, but I think doing so brings other baggage. Below is what I ended up adding to my "create_entities.php" file which I run from the command line. /** * Returns an array of each method script. * * @param string $script * @param array $methods. Sequential * * @param array (associate array where keys are method names and value method script * */ function extractMethods(string $script, array $methods):array { $methods = getMethods($script, $methods); $script = explode(PHP_EOL, $script); foreach ($methods as $methodName=>$lns) { $methods[$methodName]= implode(PHP_EOL, array_slice($script, $lns[0], $lns[1])); } return $methods; } /** * Removes or replaces a given function. * * @param array $methods. If an element is associative, replaces with the vvalue, else removes * * @return string (script) */ function replaceFunction(string $script, array $methods):string { $methodNames=[]; foreach($methods as $key=>$name){ $methodNames[]=is_int($key)?$name:$key; } echo("Removing or replacing methods ".implode(', ', $methodNames).PHP_EOL); $methodNames = getMethods($script, $methodNames); //$columns = array_column($methodNames, 0); //array_multisort($columns, SORT_DESC, $methodNames); uasort($methodNames, function($a, $b) {return $b[0] <=> $a[0];}); //$script = preg_split("/\r\n|\n|\r/", $script); $script = explode(PHP_EOL, $script); foreach ($methodNames as $methodName=>$lns) { array_splice($script, $lns[0]-1, $lns[1]+1, $methods[$methodName]??null); } return implode(PHP_EOL, $script); } /** * Returns the line number and length of methods. * * @param string $script * @param array $methods. Sequential * * @param array (associate array where keys are method names and value is start line number and number of lines * */ function getMethods(string $script, array $methods):array { $tokens = token_get_all($script); if(count($tokens)!==count(token_get_all($script, TOKEN_PARSE))) exit('Investigate TOKEN_PARSE'); $count=count($tokens); $eof=$count - array_search('}',array_reverse($tokens)); $output=[]; foreach ($tokens as $index=>$token) { if (is_array($token) && $token[0]===T_FUNCTION) { //346 for ($nameIndex = $index+1; $nameIndex <= $count; $nameIndex++) { if (is_array($tokens[$nameIndex]) && $tokens[$nameIndex][0]===T_STRING) { //319 if(in_array($tokens[$nameIndex][1], $methods)) { for ($lastIndex = $nameIndex+1; $lastIndex <= $count; $lastIndex++) { if($lastIndex===$eof || (is_array($tokens[$lastIndex]) && $tokens[$lastIndex][0]===T_DOC_COMMENT)) { //378 for ($endIndex = $lastIndex-1; $endIndex > 0; $endIndex--) { if (is_array($tokens[$endIndex])) { break; } } for ($startIndex = $index-1; $startIndex > 0; $startIndex--) { if (is_array($tokens[$startIndex]) && $tokens[$startIndex][0]===T_DOC_COMMENT) { //378 $output[$tokens[$nameIndex][1]]=[$tokens[$startIndex][2], $tokens[$endIndex][2]-$tokens[$startIndex][2]]; break(3); } } exit('Initial comment not found'); } } } break; exit('Next comment or closing tag not found'); } } } } if($error = array_diff($methods, array_keys($output))){ exit(implode(', ', $error).' not found.'); } return $output; } Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.