Laravel Türkiye Discord Kanalı Forumda kod paylaşılırken dikkat edilmesi gerekenler!Birlikte proje geliştirmek ister misiniz?

Merhaba, herkese iyi günler diliyorum. Az önce https://laravel.gen.tr/d/6867-dinamik-failed-jobs-yonetimi bu konu üzerinde Repository Pattern hakkında farklı bir yorum gördüm. Mustafa abi kullanılmasını önermiş. Bazı forumlarda tekrar eden kod yapısını engellemek için kullanıldığını okumuştum. Repository Pattern hakkında kullanım açısından başka avantajları var mı? Bilgi verebilirseniz çok sevinirim. Herkese teşekkür ederim.

  • mgsmus bunu yanıtladı.
  • mkeremcansev Tasarım desenlerinin kullanımı dilden dile göre de değişir, her dilde karşılığını bulamayabilirsiniz ya da farklı halini görebilirsiniz. O yüzden mevzubahis PHP olduğu için şuraya bakabilirsiniz:
    https://designpatternsphp.readthedocs.io/tr/latest/README.html

    Tekrar eden kod yapısını engellediği doğrudur ama dependency injection ile birleştiğinde size farklı faydalar sağlar. Teorik bir örnek vermek gerekirse

    class UserData implements Arrayable
    {
        public function __construct(
            public int|string $id;
            public string $name;
            public string $email;
        )
        {}
    
        public function toArray(): array
        {
            return [
                'id' => $this->id,
                'name' => $this->name,
                'email' => $this->email,
            ];
        }
    }
    interface UserRepositoryInterface
    {
        public function find(int|string $id): ?UserData;
    }
    class MySQLUserRepository implements UserRepositoryInterface
    {
        public function find(int|string $id): ?UserData
        {
            $data = DB::select('select id, name, email from users where id = ? limit 1', [$id]);
    
            return $data 
                    ? new UserData($data[0]['id'], $data[0]['name'], $data[0]['email']) 
                    : null;
        }
    }
    class MongoDBUserRepository implements UserRepositoryInterface
    {
        public function __construct(
            public MongoDBConnector $connector
        )
        {}
        
        public function find(int|string $id): ?UserData
        {
            $data = $this->connector
                ->users
                ->findOne(
                    ['_id' => new MongoDB\BSON\ObjectId((string)$id)],
                    ['projection' => [
                        'name' => 1,
                        'email' => 1,
                    ]
                ]);
    
            return $data 
                    ? new UserData($data['_id'], $data['name'], $data['email']) 
                    : null;
        }
    }

    AppServiceProvider::register();

    $this->app->bind(UserRepositoryInterface::class, function ($app) {
        $connection = config('database.default');
    
        if($connection === 'mysql') {
            return new MySQLUserRepository;
        }
    
        if($connection === 'mongodb') {
            return new MongoDBUserRepository(
                new MongoDBConnector(...)
            );
        }
    });

    Şöyle yaptığınızı varsayarsak:

    class UserController extends Controller
    {
        public function __construct(
            public UserRepositoryInterface $userRepository,
        )
        {}
        
        public function show($id)
        {
            // Burada hangi veritabanına bağlandığımı bilmiyorum, config
            // dosyasında hangisi seçili ise o.
            $user = $this->userRepository
                ->find($id);
    
            if($user) {
                return response()->json($user->toArray());
            }
    
            abort(404, __('User not found.'));
        }
    }

    Artık config/database.php içinde default sürücüyü mysql yaparsanız MySQL veritabanına bağlanıp kullanıcıyı çekecek, mongodb yaparsanız MongoDB'ye bağlanıp kullanıcıyı çekecek. Siz kendi kodunuzda değişiklik yapmayacaksınız. Burada siz değişiklik yapmıyorsunuz, bu işi service container aracılığıyla frameworke yaptırıyorsunuz, buna da Inversion of Control (IoC) denir.

    ---

    https://designpatternsphp.readthedocs.io/tr/latest/README.html
    https://laravel.com/docs/9.x/container
    https://laravel.com/docs/9.x/providers

    mkeremcansev Tasarım desenlerinin kullanımı dilden dile göre de değişir, her dilde karşılığını bulamayabilirsiniz ya da farklı halini görebilirsiniz. O yüzden mevzubahis PHP olduğu için şuraya bakabilirsiniz:
    https://designpatternsphp.readthedocs.io/tr/latest/README.html

    Tekrar eden kod yapısını engellediği doğrudur ama dependency injection ile birleştiğinde size farklı faydalar sağlar. Teorik bir örnek vermek gerekirse

    class UserData implements Arrayable
    {
        public function __construct(
            public int|string $id;
            public string $name;
            public string $email;
        )
        {}
    
        public function toArray(): array
        {
            return [
                'id' => $this->id,
                'name' => $this->name,
                'email' => $this->email,
            ];
        }
    }
    interface UserRepositoryInterface
    {
        public function find(int|string $id): ?UserData;
    }
    class MySQLUserRepository implements UserRepositoryInterface
    {
        public function find(int|string $id): ?UserData
        {
            $data = DB::select('select id, name, email from users where id = ? limit 1', [$id]);
    
            return $data 
                    ? new UserData($data[0]['id'], $data[0]['name'], $data[0]['email']) 
                    : null;
        }
    }
    class MongoDBUserRepository implements UserRepositoryInterface
    {
        public function __construct(
            public MongoDBConnector $connector
        )
        {}
        
        public function find(int|string $id): ?UserData
        {
            $data = $this->connector
                ->users
                ->findOne(
                    ['_id' => new MongoDB\BSON\ObjectId((string)$id)],
                    ['projection' => [
                        'name' => 1,
                        'email' => 1,
                    ]
                ]);
    
            return $data 
                    ? new UserData($data['_id'], $data['name'], $data['email']) 
                    : null;
        }
    }

    AppServiceProvider::register();

    $this->app->bind(UserRepositoryInterface::class, function ($app) {
        $connection = config('database.default');
    
        if($connection === 'mysql') {
            return new MySQLUserRepository;
        }
    
        if($connection === 'mongodb') {
            return new MongoDBUserRepository(
                new MongoDBConnector(...)
            );
        }
    });

    Şöyle yaptığınızı varsayarsak:

    class UserController extends Controller
    {
        public function __construct(
            public UserRepositoryInterface $userRepository,
        )
        {}
        
        public function show($id)
        {
            // Burada hangi veritabanına bağlandığımı bilmiyorum, config
            // dosyasında hangisi seçili ise o.
            $user = $this->userRepository
                ->find($id);
    
            if($user) {
                return response()->json($user->toArray());
            }
    
            abort(404, __('User not found.'));
        }
    }

    Artık config/database.php içinde default sürücüyü mysql yaparsanız MySQL veritabanına bağlanıp kullanıcıyı çekecek, mongodb yaparsanız MongoDB'ye bağlanıp kullanıcıyı çekecek. Siz kendi kodunuzda değişiklik yapmayacaksınız. Burada siz değişiklik yapmıyorsunuz, bu işi service container aracılığıyla frameworke yaptırıyorsunuz, buna da Inversion of Control (IoC) denir.

    ---

    https://designpatternsphp.readthedocs.io/tr/latest/README.html
    https://laravel.com/docs/9.x/container
    https://laravel.com/docs/9.x/providers

      mgsmus Bilgi için gerçekten çok teşekkür ederim abi. Ben dillere göre kullanım alanının değiştiğini bilmiyordum. Örnek olarak gösterdiğin alan aşırı iyi tam yerine oturmuş. Bir de abi buna benzer bir örnek verilen Factory Pattern var. Çalışma mantığı olarak tam anlattığın gibi örnek göstermişler, Provider içerisinde kontrol edip çalıştırıyoruz. Factory Pattern PHP üzerinde tam olarak ne amaçla kullanılıyor bilgi verebilir misin? Tekrardan çok teşekkür ederim değerli bilgi için.

        mkeremcansev Factory obje oluşturur. Mesela üstteki paylaştığım koda bakalım. Orada service container ile ilgili kısımda şöyle yapılabilir:

        class UserRepositoryFactory
        {
            public static function create(?string $connection = null): UserRepositoryInterface
            {
                $connection ??= config('database.default');
        
                if($connection === 'mysql') {
                    return new MySQLUserRepository;
                }
        
                if($connection === 'mongodb') {
                    return new MongoDBUserRepository(
                        new MongoDBConnector(...)
                    );
                }
        
                throw new InvalidArgumentException(__('Invalid connection: :name', [
                    'name' => $connection
                ]));
            }
        }
        $this->app->bind(UserRepositoryInterface::class, function ($app) {
            return UserRepositoryFactory::create();
        });

        Bu aynı zamanda şu şekilde de kullanılabilir (ama bu sefer IoC kullanamazsınız):

        $user = UserRepositoryFactory::create()
            ->find(1);

          mgsmus Bilgi için çok teşekkür ederim abi. Genel olarak diğer Pattern yapılarını ve kullanım alanlarını araştırmam gerekecek. Araştırdıktan sonra derleyip forumda paylaşacağım. Tekrardan teşekkür ederim.

          7 gün sonra