@@ -540,6 +540,140 @@ private function resolveEntityClass($entity, $recursive = [])
540540 }
541541
542542
543+ /**
544+ * @return void
545+ */
546+ public function complete ()
547+ {
548+ $ this ->prepareClassList ();
549+
550+ foreach ($ this ->definitions as $ name => $ def ) {
551+ if ($ def ->isDynamic ()) {
552+ continue ;
553+ }
554+
555+ $ this ->currentService = NULL ;
556+ $ entity = $ def ->getFactory ()->getEntity ();
557+ $ serviceRef = $ this ->getServiceName ($ entity );
558+ $ factory = $ serviceRef && !$ def ->getFactory ()->arguments && !$ def ->getSetup () && $ def ->getImplementType () !== 'create '
559+ ? new Statement (['@ ' . self ::THIS_CONTAINER , 'getService ' ], [$ serviceRef ])
560+ : $ def ->getFactory ();
561+
562+ try {
563+ $ def ->setFactory ($ this ->completeStatement ($ factory ));
564+ $ this ->classListNeedsRefresh = FALSE ;
565+
566+ $ this ->currentService = $ name ;
567+ $ setups = $ def ->getSetup ();
568+ foreach ($ setups as & $ setup ) {
569+ if (is_string ($ setup ->getEntity ()) && strpbrk ($ setup ->getEntity (), ':@? \\' ) === FALSE ) { // auto-prepend @self
570+ $ setup = new Statement (['@ ' . $ name , $ setup ->getEntity ()], $ setup ->arguments );
571+ }
572+ $ setup = $ this ->completeStatement ($ setup );
573+ }
574+ $ def ->setSetup ($ setups );
575+
576+ } catch (\Exception $ e ) {
577+ throw new ServiceCreationException ("Service ' $ name': " . $ e ->getMessage (), 0 , $ e );
578+
579+ } finally {
580+ $ this ->currentService = NULL ;
581+ }
582+ }
583+ }
584+
585+
586+ /**
587+ * @return void
588+ */
589+ public function completeStatement (Statement $ statement )
590+ {
591+ $ entity = $ this ->normalizeEntity ($ statement ->getEntity ());
592+ $ arguments = $ statement ->arguments ;
593+
594+ if (is_string ($ entity ) && Strings::contains ($ entity , '? ' )) { // PHP literal
595+
596+ } elseif ($ service = $ this ->getServiceName ($ entity )) { // factory calling
597+ $ params = [];
598+ foreach ($ this ->definitions [$ service ]->parameters as $ k => $ v ) {
599+ $ params [] = preg_replace ('#\w+\z# ' , '\$$0 ' , (is_int ($ k ) ? $ v : $ k )) . (is_int ($ k ) ? '' : ' = ' . PhpHelpers::dump ($ v ));
600+ }
601+ $ rm = new \ReflectionFunction (create_function (implode (', ' , $ params ), '' ));
602+ $ arguments = Helpers::autowireArguments ($ rm , $ arguments , $ this );
603+ $ entity = '@ ' . $ service ;
604+
605+ } elseif ($ entity === 'not ' ) { // operator
606+
607+ } elseif (is_string ($ entity )) { // class name
608+ if ($ constructor = (new ReflectionClass ($ entity ))->getConstructor ()) {
609+ $ this ->addDependency ((string ) $ constructor ->getFileName ());
610+ $ arguments = Helpers::autowireArguments ($ constructor , $ arguments , $ this );
611+ } elseif ($ arguments ) {
612+ throw new ServiceCreationException ("Unable to pass arguments, class $ entity has no constructor. " );
613+ }
614+
615+ } elseif (!Nette \Utils \Arrays::isList ($ entity ) || count ($ entity ) !== 2 ) {
616+ throw new ServiceCreationException (sprintf ('Expected class, method or property, %s given. ' , PhpHelpers::dump ($ entity )));
617+
618+ } elseif (!preg_match ('#^\$? ' . PhpHelpers::PHP_IDENT . '(\[\])?\z# ' , $ entity [1 ])) {
619+ throw new ServiceCreationException ("Expected function, method or property name, ' $ entity [1 ]' given. " );
620+
621+ } elseif ($ entity [0 ] === '' ) { // globalFunc
622+
623+ } elseif ($ entity [0 ] instanceof Statement) {
624+ $ entity [0 ] = $ this ->completeStatement ($ entity [0 ]);
625+
626+ } elseif ($ entity [1 ][0 ] === '$ ' ) { // property getter, setter or appender
627+ Validators::assert ($ arguments , 'list:0..1 ' , "setup arguments for ' " . Nette \Utils \Callback::toString ($ entity ) . "' " );
628+ if (!$ arguments && substr ($ entity [1 ], -2 ) === '[] ' ) {
629+ throw new ServiceCreationException ("Missing argument for $ entity [1 ]. " );
630+ }
631+ if ($ service = $ this ->getServiceName ($ entity [0 ])) {
632+ $ entity [0 ] = '@ ' . $ service ;
633+ }
634+
635+ } elseif ($ service = $ this ->getServiceName ($ entity [0 ])) { // service method
636+ $ class = $ this ->definitions [$ service ]->getImplement ();
637+ if (!$ class || !method_exists ($ class , $ entity [1 ])) {
638+ $ class = $ this ->definitions [$ service ]->getClass ();
639+ }
640+ if ($ class ) {
641+ $ arguments = $ this ->autowireArguments ($ class , $ entity [1 ], $ arguments );
642+ }
643+ $ entity [0 ] = '@ ' . $ service ;
644+
645+ } else { // static method
646+ $ arguments = $ this ->autowireArguments ($ entity [0 ], $ entity [1 ], $ arguments );
647+ }
648+
649+ array_walk_recursive ($ arguments , function (& $ val ) {
650+ if ($ val instanceof Statement) {
651+ $ val = $ this ->completeStatement ($ val );
652+
653+ } elseif ($ val === $ this ) {
654+ trigger_error ("Replace object ContainerBuilder in Statement arguments with '@container'. " , E_USER_DEPRECATED );
655+ $ val = self ::literal ('$this ' );
656+
657+ } elseif ($ val instanceof ServiceDefinition) {
658+ $ val = '@ ' . current (array_keys ($ this ->getDefinitions (), $ val , TRUE ));
659+
660+ } elseif (is_string ($ val ) && strlen ($ val ) > 1 && $ val [0 ] === '@ ' && $ val [1 ] !== '@ ' ) {
661+ $ pair = explode (':: ' , $ val , 2 );
662+ $ name = $ this ->getServiceName ($ pair [0 ]);
663+ if (!isset ($ pair [1 ])) { // @service
664+ $ val = '@ ' . $ name ;
665+ } elseif (preg_match ('#^[A-Z][A-Z0-9_]*\z# ' , $ pair [1 ], $ m )) { // @service::CONSTANT
666+ $ val = self ::literal ($ this ->getDefinition ($ name )->getClass () . ':: ' . $ pair [1 ]);
667+ } else { // @service::property
668+ $ val = new Statement (['@ ' . $ name , '$ ' . $ pair [1 ]]);
669+ }
670+ }
671+ });
672+
673+ return new Statement ($ entity , $ arguments );
674+ }
675+
676+
543677 private function checkCase ($ class )
544678 {
545679 if ((class_exists ($ class ) || interface_exists ($ class )) && $ class !== ($ name = (new ReflectionClass ($ class ))->getName ())) {
@@ -596,7 +730,7 @@ public function getDependencies()
596730 */
597731 public function generateClasses ($ className = NULL , $ parentName = NULL )
598732 {
599- $ this ->prepareClassList ();
733+ $ this ->complete ();
600734
601735 $ this ->generatedClasses = [];
602736 $ this ->className = $ className ?: $ this ->className ;
@@ -676,14 +810,9 @@ private function generateService($name)
676810 );
677811 }
678812
679- $ setups = $ def ->getSetup ();
680- foreach ($ setups as & $ setup ) {
681- if (is_string ($ setup ->getEntity ()) && strpbrk ($ setup ->getEntity (), ':@? \\' ) === FALSE ) { // auto-prepend @self
682- $ setup = new Statement (['@self ' , $ setup ->getEntity ()], $ setup ->arguments );
683- }
813+ foreach ($ def ->getSetup () as $ setup ) {
684814 $ code .= $ this ->formatStatement ($ setup ) . "; \n" ;
685815 }
686- $ def ->setSetup ($ setups );
687816 $ this ->currentService = NULL ;
688817
689818 $ code .= 'return $service; ' ;
@@ -743,39 +872,21 @@ private function convertParameters(array $parameters)
743872 */
744873 public function formatStatement (Statement $ statement )
745874 {
746- $ entity = $ this -> normalizeEntity ( $ statement ->getEntity () );
875+ $ entity = $ statement ->getEntity ();
747876 $ arguments = $ statement ->arguments ;
748877
749878 if (is_string ($ entity ) && Strings::contains ($ entity , '? ' )) { // PHP literal
750879 return $ this ->formatPhp ($ entity , $ arguments );
751880
752881 } elseif ($ service = $ this ->getServiceName ($ entity )) { // factory calling
753- $ params = [];
754- foreach ($ this ->definitions [$ service ]->parameters as $ k => $ v ) {
755- $ params [] = preg_replace ('#\w+\z# ' , '\$$0 ' , (is_int ($ k ) ? $ v : $ k )) . (is_int ($ k ) ? '' : ' = ' . PhpHelpers::dump ($ v ));
756- }
757- $ rm = new \ReflectionFunction (create_function (implode (', ' , $ params ), '' ));
758- $ arguments = Helpers::autowireArguments ($ rm , $ arguments , $ this );
759882 return $ this ->formatPhp ('$this->?(?*) ' , [Container::getMethodName ($ service ), $ arguments ]);
760883
761884 } elseif ($ entity === 'not ' ) { // operator
762885 return $ this ->formatPhp ('!? ' , [$ arguments [0 ]]);
763886
764887 } elseif (is_string ($ entity )) { // class name
765- if ($ constructor = (new ReflectionClass ($ entity ))->getConstructor ()) {
766- $ this ->addDependency ((string ) $ constructor ->getFileName ());
767- $ arguments = Helpers::autowireArguments ($ constructor , $ arguments , $ this );
768- } elseif ($ arguments ) {
769- throw new ServiceCreationException ("Unable to pass arguments, class $ entity has no constructor. " );
770- }
771888 return $ this ->formatPhp ("new $ entity " . ($ arguments ? '(?*) ' : '' ), [$ arguments ]);
772889
773- } elseif (!Nette \Utils \Arrays::isList ($ entity ) || count ($ entity ) !== 2 ) {
774- throw new ServiceCreationException (sprintf ('Expected class, method or property, %s given. ' , PhpHelpers::dump ($ entity )));
775-
776- } elseif (!preg_match ('#^\$? ' . PhpHelpers::PHP_IDENT . '(\[\])?\z# ' , $ entity [1 ])) {
777- throw new ServiceCreationException ("Expected function, method or property name, ' $ entity [1 ]' given. " );
778-
779890 } elseif ($ entity [0 ] === '' ) { // globalFunc
780891 return $ this ->formatPhp ("$ entity [1 ](?*) " , [$ arguments ]);
781892
@@ -787,12 +898,8 @@ public function formatStatement(Statement $statement)
787898 return $ this ->formatPhp ("$ inner->?(?*) " , [$ entity [1 ], $ arguments ]);
788899
789900 } elseif ($ entity [1 ][0 ] === '$ ' ) { // property getter, setter or appender
790- Validators::assert ($ arguments , 'list:0..1 ' , "setup arguments for ' " . Nette \Utils \Callback::toString ($ entity ) . "' " );
791901 $ name = substr ($ entity [1 ], 1 );
792902 if ($ append = (substr ($ name , -2 ) === '[] ' )) {
793- if (!$ arguments ) {
794- throw new ServiceCreationException ("Missing argument for $ entity [1 ]. " );
795- }
796903 $ name = substr ($ name , 0 , -2 );
797904 }
798905 if ($ this ->getServiceName ($ entity [0 ])) {
@@ -805,17 +912,9 @@ public function formatStatement(Statement $statement)
805912 : $ prop ;
806913
807914 } elseif ($ service = $ this ->getServiceName ($ entity [0 ])) { // service method
808- $ class = $ this ->definitions [$ service ]->getImplement ();
809- if (!$ class || !method_exists ($ class , $ entity [1 ])) {
810- $ class = $ this ->definitions [$ service ]->getClass ();
811- }
812- if ($ class ) {
813- $ arguments = $ this ->autowireArguments ($ class , $ entity [1 ], $ arguments );
814- }
815915 return $ this ->formatPhp ('?->?(?*) ' , [$ entity [0 ], $ entity [1 ], $ arguments ]);
816916
817917 } else { // static method
818- $ arguments = $ this ->autowireArguments ($ entity [0 ], $ entity [1 ], $ arguments );
819918 return $ this ->formatPhp ("$ entity [0 ]:: $ entity [1 ](?*) " , [$ arguments ]);
820919 }
821920 }
@@ -832,37 +931,18 @@ public function formatPhp($statement, $args)
832931 if ($ val instanceof Statement) {
833932 $ val = self ::literal ($ this ->formatStatement ($ val ));
834933
835- } elseif ($ val === $ this ) {
836- trigger_error ("Replace object ContainerBuilder in Statement arguments with '@container'. " , E_USER_DEPRECATED );
837- $ val = self ::literal ('$this ' );
838-
839- } elseif ($ val instanceof ServiceDefinition) {
840- $ val = '@ ' . current (array_keys ($ this ->getDefinitions (), $ val , TRUE ));
841- }
842-
843- if (!is_string ($ val )) {
844- return ;
845-
846- } elseif (substr ($ val , 0 , 2 ) === '@@ ' ) {
934+ } elseif (is_string ($ val ) && substr ($ val , 0 , 2 ) === '@@ ' ) { // escaped text @@
847935 $ val = substr ($ val , 1 );
848936
849- } elseif (substr ($ val , 0 , 1 ) === '@ ' && strlen ($ val ) > 1 ) {
850- $ pair = explode (':: ' , $ val , 2 );
851- $ name = $ this ->getServiceName ($ pair [0 ]);
852- if (isset ($ pair [1 ]) && preg_match ('#^[A-Z][A-Z0-9_]*\z# ' , $ pair [1 ])) {
853- $ val = $ this ->getDefinition ($ name )->getClass () . ':: ' . $ pair [1 ];
854- } elseif (isset ($ pair [1 ])) {
855- $ val = $ this ->formatStatement (new Statement (['@ ' . $ name , '$ ' . $ pair [1 ]]));
937+ } elseif (is_string ($ val ) && substr ($ val , 0 , 1 ) === '@ ' && strlen ($ val ) > 1 ) { // service reference
938+ $ name = substr ($ val , 1 );
939+ if ($ name === self ::THIS_CONTAINER ) {
940+ $ val = self ::literal ('$this ' );
941+ } elseif ($ name === $ this ->currentService ) {
942+ $ val = self ::literal ('$service ' );
856943 } else {
857- if ($ name === self ::THIS_CONTAINER ) {
858- $ val = '$this ' ;
859- } elseif ($ name === $ this ->currentService ) {
860- $ val = '$service ' ;
861- } else {
862- $ val = $ this ->formatStatement (new Statement (['@ ' . self ::THIS_CONTAINER , 'getService ' ], [$ name ]));
863- }
944+ $ val = self ::literal ($ this ->formatStatement (new Statement (['@ ' . self ::THIS_CONTAINER , 'getService ' ], [$ name ])));
864945 }
865- $ val = self ::literal ($ val );
866946 }
867947 });
868948 return PhpHelpers::formatArgs ($ statement , $ args );
0 commit comments