Override presenteru, ak existuje v custom folderi

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
stewestw
Člen | 42
+
0
-

ahojte, je prosim neako mozne overridenut presenter, napr. HomepagePresenter v nom samotnom, ked zisti, ze sa v zlozke custom nachadza HomepagePresenterOverride, ktory ho dedi?
dakujem

matopeto
Člen | 395
+
0
-

Pravdepodobne to vobec nepotrebujes a nechces dostiahut, a ak ano, tak na robis nieco zle :)
Napis nam prosim, preco to potrebujes a k comu by to bolo.

Editoval matopeto (21. 6. 2017 15:47)

stewestw
Člen | 42
+
+1
-

riesime si CMS, v ktorom je normalne zachovana struktura nette. z casu na cas potrebujeme overridenut presenter pre konkr. klienta, nechceme ale zasiahnut do core.

  • vsetky presenteri dedia basePresenter.
  • custom mame vynate a ked sa v nom nachadza nazov presenteru ktory volame, tak sa forwardne (forward ale nechceme)

kod:

<?php
/**
 * Created by PhpStorm.
 * User: stefan
 * Date: 27/01/2017
 * Time: 14:08
 */

namespace Core;

use Nette;
use Core\Models\Privileges;


class BasePresenter extends Nette\Application\UI\Presenter{


    /** @var */
    protected $acl;



    /**
     *
     * set override on startup
     *
     */
    public function startup(){

        //  call default functionality
        parent::startup();

        //  set right presenter override
        $request    = $this->getRequest();
        $action     = $this->getAction();
        $shortName  = str_replace('Override', '', explode(':', $this->getName())[count(explode(':', $this->getName())) -1]);
        $folder     = 'custom/overrides/';

        if ( !$request->isMethod('forward')) {

            $parts = $this->getParts();
            $rewrite_dest =  __DIR__ . '/../../'.$folder.implode('/',$parts).'/presenters/'.$shortName.'OverridePresenter.php';

            if(file_exists($rewrite_dest)){
                $exploder = explode(':', $this->getName());
                $exploder[count($exploder) - 1] = $exploder[count($exploder) - 1].'Override';
                $override = ':'.implode(':', $exploder).':'.$action;
                $override = str_replace('OverrideOverride', "Override", $override);
                $args = $this->getParameters();
                $this->forward($override, $args);
            }

        }

        //  set right template override
        $parts = $this->getParts();

        $rewrite_dest_original = str_replace( 'Override.latte', '.latte', __DIR__ . '/../'.implode('/', $parts).'/templates/'.$shortName.'/' .$action.'.latte');
        $rewrite_dest = str_replace( 'Override.latte', '.latte', __DIR__ . '/../../'.$folder.implode('/', $parts) .'/templates/'.$shortName.'/'.$action.'.latte');


        if(file_exists($rewrite_dest)){
            $this->template->setFile($rewrite_dest);
        }else{
            $this->template->setFile($rewrite_dest_original);
        }


    }

    /**
     * @return mixed
     */
    protected function getParts(){
        $class_info = new \ReflectionClass($this);
        $class_info = explode('\\Presenters\\', $class_info->name)[0];
        return explode('\\', $class_info);
    }


    /**
     * @param Privileges $acl
     */
    public function injectDependencies(Privileges $acl){
        $this->acl = $acl;
    }

}
David Matějka
Moderator | 6445
+
+3
-

o zjisteni nazvu presenteru se stara sluzba PresenterFactory (respektivfe IPresenterFactory), takze si muzes udelat vlastni implementaci, ktera se koukne, jestli existuje ta override trida

stewestw
Člen | 42
+
0
-

ahoj David,
dakujem za pomoc, o toto som sa pokusal, ale bohuzial neuspesne. nemas pls neaky priklad takejto implementacie?

Editoval stewestw (21. 6. 2017 16:36)

Martk
Člen | 661
+
0
-

@stewestw řešil jsem stejnou záležitost, ale pak jsem z ní upustil a koukám, že na gitu jsem to stále nechal. Třeba ti to pomůže

matopeto
Člen | 395
+
0
-

Bud pretazit a/alebo prrepisat ten kusok co hlada tu classu na nieco take:

<?php

  $classOverride = $this->formatPresenterClass($name . "override");
  if (class_exists($classOverride) {
   $class = $classOverride;
 } else {
  $class = $this->formatPresenterClass($name);
}

   if (!class_exists($class)) {
             throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' was not found.");
   }

?>

Editoval matopeto (21. 6. 2017 16:58)

stewestw
Člen | 42
+
0
-

posunul som sa dalej, dakujem, vyzera to, ze mi uz robi aj override, ale samotny presenter hadze chybu:

Call to a member function isSent() on null

tu:

File: .../nette/application/src/Application/UI/Presenter.php:177

167:         * @return Nette\Application\IResponse
168:         */
169:        public function run(Application\Request $request)
170:        {
171:            try {
172:                // STARTUP
173:                $this->request = $request;
174:                $this->payload = $this->payload ?: new \stdClass;
175:                $this->setParent($this->getParent(), $request->getPresenterName());
176:
177:                if (!$this->httpResponse->isSent()) {
178:                    $this->httpResponse->addHeader('Vary', 'X-Requested-With');
179:                }
180:
181:                $this->initGlobalParameters();
stewestw
Člen | 42
+
0
-

uz som to presiel cez

<?php
/**
 * Created by PhpStorm.
 * User: stefan
 * Date: 21/06/2017
 * Time: 16:44
 */

namespace Core;

use Nette\Application\PresenterFactory;
use Nette\Application\IPresenter;


class CorePresenterFactory extends PresenterFactory{


    public function getPresenterClass(& $name) {


        $class = parent::getPresenterClass($name);



           $exploder = explode(':', $name);
           $exploder[count($exploder) - 1] = $exploder[count($exploder) - 1].'Override';
           $override = implode(':', $exploder);
           $override = str_replace('OverrideOverride', 'Override', $override);


           $class = $this->formatPresenterClass($override);
           if (!class_exists($class)) {
               throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' was not found.");
           }


           $reflection = new \ReflectionClass($class);
           $class = $reflection->getName();


           if (!$reflection->implementsInterface(IPresenter::class)) {
               throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is not Nette\\Application\\IPresenter implementor.");
           } elseif ($reflection->isAbstract()) {
               throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract.");
           }





        return $class;


    }

}

stale mi t ale vracia:

Argument 1 passed to Front\CoreModule\Presenters\HomepageOverridePresenter::__construct() must be an instance of Core\Models\Db, none given, called in /Applications/MAMP/htdocs/suchacms/vendor/nette/application/src/Application/PresenterFactory.php

je to mozne pls neako vyriesit?

Martk
Člen | 661
+
0
-

A registruješ tu třídu presenter factory takhle? Měl jsem tam potíže, že se mi tam nepředávalo factory v konstruktoru presenter factory, takže se použilo výchozí factory callback

Edit:

Pro tebe to bude chtít menší úpravu

		$def = $builder->getDefinition($builder->getByType('Nette\Application\IPresenterFactory'));
		$original = $def->getFactory();
		$def->setFactory('TvojeTrida', $original->arguments);

Editoval Martk (21. 6. 2017 17:46)

stewestw
Člen | 42
+
0
-

dakujem, uz to slape :) vytvoril som jednoduchu extension ako si to mal ty. ak to niekto do buducna bude hladat, tak tu je inicializacia:

<?php

namespace Core;

use Nette\DI\CompilerExtension;
use Core\CorePresenterFactory;

class CoreExtension extends CompilerExtension
{

    public function beforeCompile()
    {

        $builder = $this->getContainerBuilder();
        $def = $builder->getDefinition($builder->getByType('Nette\Application\IPresenterFactory'));
        $original = $def->getFactory();
        $def->setFactory('Core\CorePresenterFactory', $original->arguments);

    }
}
stewestw
Člen | 42
+
0
-

pani, este by som sa chcel spytat, ci je mozne neako overridenut aj dedeny presenter. presnejsie, je mozne prepisat basePresenter, ktory je dedeny, ked volam jeho child?
dakujem

David Matějka
Moderator | 6445
+
+1
-

ta trida dedi od base presenteru na urovni php, to nezmenis.. (pokud nepocitam prasarny s autoloadingem :))

matopeto
Člen | 395
+
+1
-

Pripadne nepouzivat dedicnost ale kompozitnost a basepresenter nahradit traitou a tu si vkladat tam kde potrebujes, pripadne vlozit inu tam kde potrebujes inu…

Editoval matopeto (16. 8. 2017 16:33)

stewestw
Člen | 42
+
0
-

myslel, som si, dakujem :) riesim si vlastne cms a ten override chcem len ak je neaka poziadavka custom a ma sa zobrazit componenta vsade. chcel som ju volat v basePresenteri, resp. ak by som potreboval do buducna neaku fciu specificku pre projekt supnut do base presenteru

David Matějka
Moderator | 6445
+
0
-

tak muzes prekryt createComponent a delegovat to na nejakou sluzbu